TradingView indicator guides

Twiggs Money Flow: gaps and buying pressure

Twiggs Money Flow (TMF) estimates buying or selling pressure from closing position and volume. It extends each bar's range to include the previous close, then smooths flow and volume separately. That gap adjustment can reverse a bar's contribution compared with Chaikin Money Flow (CMF).

Same gap bar, opposite contributions

Previous close 100; high 110; low 106; close 107. TMF's multiplier is +0.4. CMF's is -0.5. The full indicator also depends on earlier bars and volume.

Follow the calculation

Educational calculations, not investment advice. TMF is a price and volume proxy, not measured fund flows or a return forecast.

The formula and its smoothing definition

Colin Twiggs' published method uses true-range bounds and Wilder smoothing. Let Cprev be the previous close and N the number of chart bars:

TRH = max(high, Cprev)
TRL = min(low, Cprev)
m = (2 × close − TRH − TRL) / (TRH − TRL)
F = m × volume

Seed SF = sum(first N eligible F values)
Seed SV = sum(the same N volume values)
Next SF = SFprev × (N − 1) / N + F
Next SV = SVprev × (N − 1) / N + volume
TMF = SF / SV

The example below uses a ratio scale: 0.25 is 25% on a percentage display. Dividing both smoothed sums by N leaves their ratio unchanged. An equivalent Wilder average has alpha = 1/N; a standard EMA of length N uses alpha = 2/(N+1). They are different filters.

Seed choice matters. A recurrence that starts both sums at zero and plots immediately does not match an N-bar sum seed at the beginning of the chart. This example waits for the seed and explicitly restarts it after invalid data.

For valid OHLC and nonnegative volume, each multiplier lies between -1 and +1. Positive smoothing weights make TMF a weighted average in that same interval, provided its denominator is positive. This mathematical bound does not make +0.5 an automatic sell level or -0.5 an automatic buy level.

A gap example you can recalculate

These are synthetic bars, not a backtest. Volume uses the same arbitrary units throughout. Use N = 3 for this calculation; the copyable script defaults to 21. The first row has a known prior close of 100.

Four bars showing TMF and CMF flow contributions
BarPrev closeHighLowCloseVolumeTMF mTMF flowCMF flow
1: gap up1001101061071,200+0.4+480-600
2107109105106600-0.5-300-300
3: seed106108104107900+0.5+450+450
4: update107109105105900-1.0-900-900

On bar 1, TRH = 110 and TRL = 100, so m = (214 − 110 − 100)/10 = +0.4 and flow = +480. CMF instead uses (214 − 110 − 106)/4 = -0.5 and flow = -600. The close is below the current bar's midpoint but above the midpoint of the range extended to the prior close.

At bar 3, TMF seeds SF = 480 − 300 + 450 = 630 and SV = 1,200 + 600 + 900 = 2,700. TMF = 630/2,700 = +0.233333. Three-bar CMF is (-600 − 300 + 450)/2,700 = -0.166667.

At bar 4, TMF updates SF = 630 × 2/3 − 900 = -480 and SV = 2,700 × 2/3 + 900 = 2,700. TMF = -0.177778. CMF drops bar 1 entirely: (-300 + 450 − 900)/(600 + 900 + 900) = -0.3125.

The sign disagreement at bar 3 and the different bar-4 values follow from the formulas. They do not show that one indicator predicts the next price move better.

TMF versus CMF: what actually changes

PropertyTMFCMF
Range for each contributionCurrent high/low extended to the previous closeCurrent high minus current low
History weightingWilder recurrence after an initial seedEqual weights inside a rolling window
A large bar agesIts influence decays graduallyIts contribution leaves the window at once
No gap outside current rangeSame raw multiplier as CMFSame raw multiplier as TMF
What neither measuresActual cash inflows or buyer identityActual cash inflows or buyer identity

Even without gaps, final readings can differ because the smoothing differs. For the rolling-window calculation, see the CMF guide and TradingView's formula.

Pine Script v6 with explicit startup and missing-data rules

Paste this indicator into TradingView's Pine Editor, add it to a standard candle chart, and check the feed's volume type. It plots the ratio, a zero line and confirmed crossover markers. It places no trades. Create a TradingView alert from one of its named conditions if you want notifications.

Pine Script v6 · TMF ratio
//@version=6
indicator("Twiggs Money Flow: explicit seed", shorttitle="TMF", overlay=false)

length = input.int(21, "Wilder length (bars)", minval=1)

// Colin Twiggs' true-range flow and Wilder-smoothed sum ratio.
// Seed with length consecutive eligible bars; do not invent missing volume.
validPrices = not na(close[1]) and not na(high) and not na(low) and not na(close) and high >= low and close >= low and close <= high
validVolume = not na(volume) and volume >= 0
eligible = validPrices and validVolume
trHigh = math.max(high, close[1])
trLow = math.min(low, close[1])
trRange = trHigh - trLow
multiplier = trRange == 0 ? 0.0 : (2.0 * close - trHigh - trLow) / trRange
flow = multiplier * volume

var int seedCount = 0
var float flowSum = 0.0
var float volumeSum = 0.0
if not eligible
    seedCount := 0
    flowSum := 0.0
    volumeSum := 0.0
else if seedCount < length
    flowSum += flow
    volumeSum += volume
    seedCount += 1
else
    decay = (length - 1.0) / length
    flowSum := decay * flowSum + flow
    volumeSum := decay * volumeSum + volume

ready = eligible and seedCount == length and volumeSum > 0
float tmf = ready ? flowSum / volumeSum : na
crossUp = ta.crossover(tmf, 0.0)
crossDown = ta.crossunder(tmf, 0.0)
confirmedUp = barstate.isconfirmed and volume > 0 and crossUp
confirmedDown = barstate.isconfirmed and volume > 0 and crossDown

plot(tmf, "TMF (ratio)", color=color.blue, linewidth=2, style=plot.style_linebr)
hline(0, "Zero", color=color.gray)
plotshape(confirmedUp, title="Positive cross", style=shape.triangleup, location=location.bottom, color=color.green, size=size.tiny)
plotshape(confirmedDown, title="Negative cross", style=shape.triangledown, location=location.top, color=color.red, size=size.tiny)
alertcondition(confirmedUp, "TMF positive cross", "TMF crossed above zero on a closed bar with positive volume.")
alertcondition(confirmedDown, "TMF negative cross", "TMF crossed below zero on a closed bar with positive volume.")

var table status = table.new(position.top_right, 1, 1)
if barstate.islast
    message = not eligible ? "Invalid price/volume: seed reset" : not ready ? "Waiting for seed or positive volume sum" : volume == 0 ? "Zero volume: no new flow evidence" : "TMF ready: check this feed's volume type"
    table.cell(status, 0, 0, message, text_color=color.white, bgcolor=color.new(color.black, 15))

Copy Pine Script

  • The first chart bar has no previous close and is excluded. After N eligible bars, both sums are seeded over identical observations.
  • Missing prices, malformed ranges, or missing/negative volume reset the seed. The script does not replace unavailable volume with 1 or fabricate a neutral reading.
  • A zero true range gets a zero multiplier but retains its reported volume weight. This is an explicit convention for an otherwise undefined division.
  • Zero-volume bars contribute zero to both sums. After startup, with N > 1, both sums decay equally and the ratio stays flat; an all-zero denominator returns na.
  • The line updates intrabar. Markers and alert conditions require barstate.isconfirmed and positive current volume. Closing confirmation does not remove feed revisions or prove profitability.

Read the feed before reading the signal

TradingView may receive traded volume, tick volume, or no volume for a symbol. Tick volume counts price updates. A numerical TMF result cannot tell you whether those updates represent executed trades. Confirm the exchange, provider, timeframe and units before comparing charts.

A trading halt can leave no chart bars for the inactive period. The recurrence does not advance through absent bars; the next observed bar uses the previous available close. If the feed inserts zero-volume bars instead, the sums decay before trading resumes. Those two histories can produce different post-halt readings. Do not fill missing sessions with invented volume.

A large volume observation can dominate the weighted history. Subsequent movement toward zero can reflect that observation losing weight as new bars arrive. Check the underlying bars before calling the slope a divergence. A zero crossing can also reverse on the next bar; no success rate is established here.

A reproducible chart check

  1. Match symbol, provider, standard candles, session and price adjustments. Record N and whether the display uses a ratio or percent.
  2. Choose a completed gap bar. Recalculate TRH, TRL, the multiplier and volume contribution, then compare with the CMF multiplier.
  3. Use matching starting history and seed rules. Check one update of each smoothed sum, not just the final plotted line.
  4. Test zero-range, zero-volume and unavailable-volume cases. A flat line during inactivity is not new evidence of buying pressure.
  5. For strategy testing, define entries, exits, costs and sizing before evaluating later data. A visual divergence needs a rule for when both swings become known.

Twiggs Money Flow FAQ

Turn a defined TMF rule into code

Pineify's Pine Script AI Coding Agent can help draft or modify a TMF script from explicit requirements. Supply the formula, seed, volume policy and confirmation rule, then request a syntax check and compare the output with your chart data. Syntax validation does not verify a trading edge or repair a missing data feed.

Adapt this TMF example to a 21-bar Wilder sum seed. Preserve the invalid-volume reset. Add an optional price-trend filter to closed-bar zero crossings and label filtered versus unfiltered events separately. Check the resulting Pine Script syntax.
Explore Pine Script AI Coding Agent

Sources and related calculations

Sources checked October 17, 2026. Worked data is synthetic; startup and missing-data policies are stated choices for this example.

Compare CMF's rolling window, PVT's cumulative return-weighted volume, or return to TradingView indicator guides.