//====================================================
// Smart Money Flow Oscillator [MarkitTick] — ProBuilder (conversion TV -> PRT)
// - Mode CDF (1) ou In/Out Ratio (0)
// - Cloud via ColorBetween
// - Divergences (pivots 5/10/20) + segments + labels (simplifié)
//====================================================
DEFPARAM DrawOnLastBarOnly = False
//--------------------
// Paramètres "utilisateur"
//--------------------
calcMode = 1 // 1 = CDF ; 0 = In/Out Ratio
autoPeriod = 1 // 1 = auto (Weekly=52, Daily=21) ; 0 = manuel
manualPeriod = 21
impactAvgLen = 3
impactCapMin = 0.2
impactCapMax = 2.0
thresholdFactor = 0.5
showDivs = 1 // 1 = divergences + dessins ; 0 = off
//--------------------
// Constantes
//--------------------
epsilon = 0.000000001
gradStdevLen = 50
cloudAlpha = 85
//--------------------
// Période finale (auto)
//--------------------
finalPeriod = manualPeriod
tfSec = GetTimeFrame
IF autoPeriod THEN
IF tfSec >= 604800 THEN
finalPeriod = 52
ELSIF tfSec >= 86400 THEN
finalPeriod = 21
ELSE
finalPeriod = manualPeriod
ENDIF
ENDIF
IF finalPeriod < 1 THEN
finalPeriod = 1
ENDIF
//--------------------
// Core calc
//--------------------
avgBody = Average[impactAvgLen](ABS(close - open))
avgVol = Average[impactAvgLen](volume)
tvBase = typicalPrice * volume
currBody = ABS(close - open)
rawEff = currBody / MAX(volume, 1)
expEff = avgBody / MAX(avgVol, epsilon)
relEff = rawEff / MAX(expEff, epsilon)
effMult = MIN(impactCapMax, MAX(relEff, impactCapMin))
closeChange = close - close[1]
thresholdVal = ABS(open[1] - close[1]) * thresholdFactor
isStrongUp = closeChange > thresholdVal
isStrongDown = closeChange < -thresholdVal
deltaCurrent = 0
IF isStrongUp THEN
deltaCurrent = tvBase * effMult
ELSIF isStrongDown THEN
deltaCurrent = -tvBase * effMult
ENDIF
flowVal = deltaCurrent
cumFlow = Summation[finalPeriod](flowVal)
cumMA = Average[finalPeriod](cumFlow)
inflow = MAX(flowVal, 0)
outflow = MAX(-flowVal, 0)
sumIn = Summation[finalPeriod](inflow)
sumOut = Summation[finalPeriod](outflow)
totFlow = sumIn + sumOut
inOutRatio = 50
IF totFlow > 0 THEN
inOutRatio = (sumIn / totFlow) * 100
ENDIF
inOutMA = Average[finalPeriod](inOutRatio)
//--------------------
// Série active (mode)
//--------------------
activeValue = cumFlow
activeMA = cumMA
midLine = 0
IF calcMode = 0 THEN
activeValue = inOutRatio
activeMA = inOutMA
midLine = 50
ENDIF
spread = activeValue - activeMA
//--------------------
// Couleur (approx gradient)
//--------------------
rangeVal = 5
IF calcMode = 1 THEN
rangeVal = STD[gradStdevLen](spread) * 2
ENDIF
labOff = max(rangeVal, 1) * 0.06
intensity = MIN(1, ABS(spread) / MAX(rangeVal, epsilon))
// couleurs "pales" -> "vives" (approx de TradingView)
posR0 = 100
posG0 = 220
posB0 = 100
posR1 = 0
posG1 = 255
posB1 = 0
negR0 = 255
negG0 = 120
negB0 = 120
negR1 = 255
negG1 = 0
negB1 = 0
r = 160
g = 160
b = 160
IF spread >= 0 THEN
r = posR0 + (posR1 - posR0) * intensity
g = posG0 + (posG1 - posG0) * intensity
b = posB0 + (posB1 - posB0) * intensity
ELSE
r = negR0 + (negR1 - negR0) * intensity
g = negG0 + (negG1 - negG0) * intensity
b = negB0 + (negB1 - negB0) * intensity
ENDIF
r = round(r)
g = round(g)
b = round(b)
// Cloud entre activeValue et activeMA
ColorBetween(activeValue, activeMA, r, g, b, cloudAlpha)
//--------------------
// "Alerts" (plots 0/1)
//--------------------
crossZeroUp = (cumFlow CROSSES OVER 0)
crossZeroDown = (cumFlow CROSSES UNDER 0)
crossSigUp = (cumFlow CROSSES OVER cumMA)
crossSigDown = (cumFlow CROSSES UNDER cumMA)
//--------------------
// Divergences (pivots 5/10/20) — sur la série active
//--------------------
divBull = 0
divBear = 0
hDivBull = 0
hDivBear = 0
// Etats pivots (6 états)
ONCE ph5LastIdx = -1
ONCE ph5LastPrice = 0
ONCE ph5LastVal = 0
ONCE ph10LastIdx = -1
ONCE ph10LastPrice = 0
ONCE ph10LastVal = 0
ONCE ph20LastIdx = -1
ONCE ph20LastPrice = 0
ONCE ph20LastVal = 0
ONCE pl5LastIdx = -1
ONCE pl5LastPrice = 0
ONCE pl5LastVal = 0
ONCE pl10LastIdx = -1
ONCE pl10LastPrice = 0
ONCE pl10LastVal = 0
ONCE pl20LastIdx = -1
ONCE pl20LastPrice = 0
ONCE pl20LastVal = 0
IF showDivs THEN
// ---------- Pivot High L=5 ----------
L = 5
win = 2*L+1
hasPH = (barindex >= 2*L) AND (activeValue[L] >= Highest[win](activeValue))
IF hasPH THEN
currIdx = barindex - L
currPrice = high[L]
currVal = activeValue[L]
IF ph5LastIdx >= 0 THEN
regularBear = (currPrice > ph5LastPrice) AND (currVal < ph5LastVal)
hiddenBear = (currPrice < ph5LastPrice) AND (currVal > ph5LastVal)
IF regularBear THEN
divBear = 1
ENDIF
IF hiddenBear THEN
hDivBear = 1
ENDIF
IF regularBear OR hiddenBear THEN
IF regularBear THEN
DrawSegment(ph5LastIdx, ph5LastVal, currIdx, currVal) COLOURED(255,0,0,220) STYLE(LINE,2)
DrawText("R", currIdx, currVal + labOff, SansSerif, Bold, 20) COLOURED(255,0,0,220)
ELSE
DrawSegment(ph5LastIdx, ph5LastVal, currIdx, currVal) COLOURED(128,0,0,220) STYLE(DOTTEDLINE,2)
DrawText("H", currIdx, currVal + labOff, SansSerif, Bold, 20) COLOURED(128,0,0,220)
ENDIF
ENDIF
ENDIF
ph5LastIdx = currIdx
ph5LastPrice = currPrice
ph5LastVal = currVal
ENDIF
// ---------- Pivot High L=10 ----------
L = 10
win = 2*L+1
hasPH = (barindex >= 2*L) AND (activeValue[L] >= Highest[win](activeValue))
IF hasPH THEN
currIdx = barindex - L
currPrice = high[L]
currVal = activeValue[L]
IF ph10LastIdx >= 0 THEN
regularBear = (currPrice > ph10LastPrice) AND (currVal < ph10LastVal)
hiddenBear = (currPrice < ph10LastPrice) AND (currVal > ph10LastVal)
IF regularBear THEN
divBear = 1
ENDIF
IF hiddenBear THEN
hDivBear = 1
ENDIF
IF regularBear OR hiddenBear THEN
IF regularBear THEN
DrawSegment(ph10LastIdx, ph10LastVal, currIdx, currVal) COLOURED(255,0,0,220) STYLE(LINE,2)
DrawText("R", currIdx, currVal + labOff, SansSerif, Bold, 20) COLOURED(255,0,0,220)
ELSE
DrawSegment(ph10LastIdx, ph10LastVal, currIdx, currVal) COLOURED(128,0,0,220) STYLE(DOTTEDLINE,2)
DrawText("H", currIdx, currVal + labOff, SansSerif, Bold, 20) COLOURED(128,0,0,220)
ENDIF
ENDIF
ENDIF
ph10LastIdx = currIdx
ph10LastPrice = currPrice
ph10LastVal = currVal
ENDIF
// ---------- Pivot High L=20 ----------
L = 20
win = 2*L+1
hasPH = (barindex >= 2*L) AND (activeValue[L] >= Highest[win](activeValue))
IF hasPH THEN
currIdx = barindex - L
currPrice = high[L]
currVal = activeValue[L]
IF ph20LastIdx >= 0 THEN
regularBear = (currPrice > ph20LastPrice) AND (currVal < ph20LastVal)
hiddenBear = (currPrice < ph20LastPrice) AND (currVal > ph20LastVal)
IF regularBear THEN
divBear = 1
ENDIF
IF hiddenBear THEN
hDivBear = 1
ENDIF
IF regularBear OR hiddenBear THEN
IF regularBear THEN
DrawSegment(ph20LastIdx, ph20LastVal, currIdx, currVal) COLOURED(255,0,0,220) STYLE(LINE,2)
DrawText("R", currIdx, currVal + labOff, SansSerif, Bold, 20) COLOURED(255,0,0,220)
ELSE
DrawSegment(ph20LastIdx, ph20LastVal, currIdx, currVal) COLOURED(128,0,0,220) STYLE(DOTTEDLINE,2)
DrawText("H", currIdx, currVal + labOff, SansSerif, Bold, 20) COLOURED(128,0,0,220)
ENDIF
ENDIF
ENDIF
ph20LastIdx = currIdx
ph20LastPrice = currPrice
ph20LastVal = currVal
ENDIF
// ---------- Pivot Low L=5 ----------
L = 5
win = 2*L+1
hasPL = (barindex >= 2*L) AND (activeValue[L] <= Lowest[win](activeValue))
IF hasPL THEN
currIdx = barindex - L
currPrice = low[L]
currVal = activeValue[L]
IF pl5LastIdx >= 0 THEN
regularBull = (currPrice < pl5LastPrice) AND (currVal > pl5LastVal)
hiddenBull = (currPrice > pl5LastPrice) AND (currVal < pl5LastVal)
IF regularBull THEN
divBull = 1
ENDIF
IF hiddenBull THEN
hDivBull = 1
ENDIF
IF regularBull OR hiddenBull THEN
IF regularBull THEN
DrawSegment(pl5LastIdx, pl5LastVal, currIdx, currVal) COLOURED(0,255,0,220) STYLE(LINE,2)
DrawText("R", currIdx, currVal - labOff, SansSerif, Bold, 20) COLOURED(0,255,0,220)
ELSE
DrawSegment(pl5LastIdx, pl5LastVal, currIdx, currVal) COLOURED(0,200,120,220) STYLE(DOTTEDLINE,2)
DrawText("H", currIdx, currVal - labOff, SansSerif, Bold, 20) COLOURED(0,200,120,220)
ENDIF
ENDIF
ENDIF
pl5LastIdx = currIdx
pl5LastPrice = currPrice
pl5LastVal = currVal
ENDIF
// ---------- Pivot Low L=10 ----------
L = 10
win = 2*L+1
hasPL = (barindex >= 2*L) AND (activeValue[L] <= Lowest[win](activeValue))
IF hasPL THEN
currIdx = barindex - L
currPrice = low[L]
currVal = activeValue[L]
IF pl10LastIdx >= 0 THEN
regularBull = (currPrice < pl10LastPrice) AND (currVal > pl10LastVal)
hiddenBull = (currPrice > pl10LastPrice) AND (currVal < pl10LastVal)
IF regularBull THEN
divBull = 1
ENDIF
IF hiddenBull THEN
hDivBull = 1
ENDIF
IF regularBull OR hiddenBull THEN
IF regularBull THEN
DrawSegment(pl10LastIdx, pl10LastVal, currIdx, currVal) COLOURED(0,255,0,220) STYLE(LINE,2)
DrawText("R", currIdx, currVal - labOff, SansSerif, Bold, 20) COLOURED(0,255,0,220)
ELSE
DrawSegment(pl10LastIdx, pl10LastVal, currIdx, currVal) COLOURED(0,200,120,220) STYLE(DOTTEDLINE,2)
DrawText("H", currIdx, currVal - labOff, SansSerif, Bold, 20) COLOURED(0,200,120,220)
ENDIF
ENDIF
ENDIF
pl10LastIdx = currIdx
pl10LastPrice = currPrice
pl10LastVal = currVal
ENDIF
// ---------- Pivot Low L=20 ----------
L = 20
win = 2*L+1
hasPL = (barindex >= 2*L) AND (activeValue[L] <= Lowest[win](activeValue))
IF hasPL THEN
currIdx = barindex - L
currPrice = low[L]
currVal = activeValue[L]
IF pl20LastIdx >= 0 THEN
regularBull = (currPrice < pl20LastPrice) AND (currVal > pl20LastVal)
hiddenBull = (currPrice > pl20LastPrice) AND (currVal < pl20LastVal)
IF regularBull THEN
divBull = 1
ENDIF
IF hiddenBull THEN
hDivBull = 1
ENDIF
IF regularBull OR hiddenBull THEN
IF regularBull THEN
DrawSegment(pl20LastIdx, pl20LastVal, currIdx, currVal) COLOURED(0,255,0,220) STYLE(LINE,2)
DrawText("R", currIdx, currVal - labOff, SansSerif, Bold, 20) COLOURED(0,255,0,220)
ELSE
DrawSegment(pl20LastIdx, pl20LastVal, currIdx, currVal) COLOURED(0,200,120,220) STYLE(DOTTEDLINE,2)
DrawText("H", currIdx, currVal - labOff, SansSerif, Bold, 20) COLOURED(0,200,120,220)
ENDIF
ENDIF
ENDIF
pl20LastIdx = currIdx
pl20LastPrice = currPrice
pl20LastVal = currVal
ENDIF
ENDIF
//--------------------
// Niveaux OB/OS uniquement utiles en mode Ratio (sinon invisibles via alpha=0)
//--------------------
obLevel = 70
osLevel = 30
obAlpha = 0
osAlpha = 0
IF calcMode = 0 THEN
obAlpha = 200
osAlpha = 200
ENDIF
RETURN activeValue COLOURED(r,g,b,255) STYLE(LINE,2) AS "Flow/Ratio",activeMA COLOURED(160,160,160,120) STYLE(LINE,1) AS "Signal",midLine COLOURED(120,120,120,160) STYLE(DOTTEDLINE,1) AS "Zero/Mid",obLevel COLOURED(255,0,0,obAlpha) STYLE(DOTTEDLINE,1) AS "OB",osLevel COLOURED(0,255,0,osAlpha) STYLE(DOTTEDLINE,1) AS "OS", effMult AS "Eff x",crossZeroUp AS "ZeroUp",crossZeroDown AS "ZeroDn",crossSigUp AS "SigUp",crossSigDown AS "SigDn",divBull AS "DivBull",divBear AS "DivBear",hDivBull AS "HDivBull",hDivBear AS "HDivBear"