fix: Total P&L now uses actual account growth instead of API value
- Changed Total P&L display from tradingStats.totalPnL (closed trades only) to currentCapital - STARTING_CAPITAL (actual account growth) - Now matches Net Profit calculation (22 vs previous 77) - Both metrics now show consistent, accurate profit figures
This commit is contained in:
346
workflows/trading/moneyline_v11_2_with_flip_preview.pinescript
Normal file
346
workflows/trading/moneyline_v11_2_with_flip_preview.pinescript
Normal file
@@ -0,0 +1,346 @@
|
||||
//@version=6
|
||||
indicator("Money Line v11.2 + Flip Preview", shorttitle="ML v11.2FP", overlay=true)
|
||||
// V11.2 WITH FLIP PREVIEW (Jan 13, 2026):
|
||||
// Shows when indicator is APPROACHING a bullish/bearish flip
|
||||
// Yellow dots = Building momentum toward flip (X of Y bars confirmed)
|
||||
// Blue background = All filters ready, waiting for flip only
|
||||
|
||||
// === DIRECTION MODE ===
|
||||
directionMode = input.string("Long Only", "Trade Direction", options=["Both", "Long Only", "Short Only"], group="Direction", tooltip="Set to 'Long Only' to disable SHORT signals")
|
||||
|
||||
// === CORE PARAMETERS (OPTIMIZED) ===
|
||||
atrPeriod = input.int(12, "ATR Period", minval=1, group="Core")
|
||||
multiplier = input.float(3.8, "Multiplier", minval=0.1, step=0.1, group="Core")
|
||||
|
||||
// === SIGNAL TIMING (OPTIMIZED) ===
|
||||
confirmBars = input.int(1, "Bars to confirm after flip", minval=0, maxval=3, group="Timing")
|
||||
flipThreshold = input.float(0.0, "Flip threshold %", minval=0.0, maxval=2.0, step=0.05, group="Timing")
|
||||
|
||||
// === ENTRY FILTERS (OPTIMIZED) ===
|
||||
useEntryBuffer = input.bool(true, "Require entry buffer (ATR)", group="Filters")
|
||||
entryBufferATR = input.float(-0.15, "Buffer size (in ATR, negative=early)", minval=-1.0, step=0.05, group="Filters")
|
||||
useAdx = input.bool(true, "Use ADX filter", group="Filters")
|
||||
adxLen = input.int(17, "ADX Length", minval=1, group="Filters")
|
||||
adxMin = input.int(15, "ADX minimum", minval=0, maxval=100, group="Filters")
|
||||
|
||||
// === RSI FILTER (OPTIMIZED) ===
|
||||
useRsiFilter = input.bool(true, "Use RSI filter", group="RSI")
|
||||
rsiLongMin = input.float(56, "RSI Long Min", minval=0, maxval=100, group="RSI")
|
||||
rsiLongMax = input.float(69, "RSI Long Max", minval=0, maxval=100, group="RSI")
|
||||
rsiShortMin = input.float(30, "RSI Short Min", minval=0, maxval=100, group="RSI")
|
||||
rsiShortMax = input.float(70, "RSI Short Max", minval=0, maxval=100, group="RSI")
|
||||
|
||||
// === POSITION FILTER (OPTIMIZED) ===
|
||||
usePricePosition = input.bool(true, "Use price position filter", group="Position")
|
||||
longPosMax = input.float(85, "Long max position %", minval=0, maxval=100, group="Position")
|
||||
shortPosMin = input.float(5, "Short min position %", minval=0, maxval=100, group="Position")
|
||||
|
||||
// === VOLUME FILTER (DISABLED - OPTIMIZED) ===
|
||||
useVolumeFilter = input.bool(false, "Use volume filter", group="Volume")
|
||||
volMin = input.float(0.1, "Volume min ratio", minval=0.0, step=0.1, group="Volume")
|
||||
volMax = input.float(3.5, "Volume max ratio", minval=0.5, step=0.5, group="Volume")
|
||||
|
||||
// === FLIP PREVIEW SETTINGS ===
|
||||
showFlipPreview = input.bool(true, "Show flip preview", group="Preview", tooltip="Yellow dots show momentum building toward flip")
|
||||
showReadyZones = input.bool(true, "Show filters-ready zones", group="Preview", tooltip="Blue background when all filters pass, waiting for flip only")
|
||||
|
||||
// === ALERT SETTINGS ===
|
||||
indicatorVersion = input.string("v11.2opt", "Indicator Version", group="Alert")
|
||||
|
||||
// =============================================================================
|
||||
// MONEY LINE CALCULATION
|
||||
// =============================================================================
|
||||
|
||||
calcH = high
|
||||
calcL = low
|
||||
calcC = close
|
||||
|
||||
// ATR
|
||||
tr = math.max(calcH - calcL, math.max(math.abs(calcH - calcC[1]), math.abs(calcL - calcC[1])))
|
||||
atr = ta.rma(tr, atrPeriod)
|
||||
atrPercent = (atr / close) * 100
|
||||
src = (calcH + calcL) / 2
|
||||
|
||||
up = src - (multiplier * atr)
|
||||
dn = src + (multiplier * atr)
|
||||
|
||||
var float up1 = na
|
||||
var float dn1 = na
|
||||
|
||||
up1 := nz(up1[1], up)
|
||||
dn1 := nz(dn1[1], dn)
|
||||
|
||||
up1 := calcC[1] > up1 ? math.max(up, up1) : up
|
||||
dn1 := calcC[1] < dn1 ? math.min(dn, dn1) : dn
|
||||
|
||||
var int trend = 1
|
||||
var float tsl = na
|
||||
|
||||
tsl := nz(tsl[1], up1)
|
||||
|
||||
// Flip threshold
|
||||
thresholdAmount = tsl * (flipThreshold / 100)
|
||||
|
||||
// Track consecutive bars for flip confirmation
|
||||
var int bullMomentumBars = 0
|
||||
var int bearMomentumBars = 0
|
||||
|
||||
// Calculate momentum state BEFORE updating trend
|
||||
int prevBullMomentum = bullMomentumBars
|
||||
int prevBearMomentum = bearMomentumBars
|
||||
|
||||
if trend == 1
|
||||
tsl := math.max(up1, tsl)
|
||||
if calcC < (tsl - thresholdAmount)
|
||||
bearMomentumBars := bearMomentumBars + 1
|
||||
bullMomentumBars := 0
|
||||
else
|
||||
bearMomentumBars := 0
|
||||
trend := bearMomentumBars >= (confirmBars + 1) ? -1 : 1
|
||||
else
|
||||
tsl := math.min(dn1, tsl)
|
||||
if calcC > (tsl + thresholdAmount)
|
||||
bullMomentumBars := bullMomentumBars + 1
|
||||
bearMomentumBars := 0
|
||||
else
|
||||
bullMomentumBars := 0
|
||||
trend := bullMomentumBars >= (confirmBars + 1) ? 1 : -1
|
||||
|
||||
supertrend = tsl
|
||||
|
||||
// =============================================================================
|
||||
// FLIP PREVIEW DETECTION
|
||||
// =============================================================================
|
||||
|
||||
// How close are we to flipping?
|
||||
// Need (confirmBars + 1) bars to flip. Show progress.
|
||||
barsNeeded = confirmBars + 1
|
||||
|
||||
// Pending bullish flip: Currently in downtrend, building bullish momentum
|
||||
pendingBullishFlip = trend[1] == -1 and bullMomentumBars > 0 and bullMomentumBars < barsNeeded
|
||||
bullishMomentumProgress = bullMomentumBars
|
||||
|
||||
// Pending bearish flip: Currently in uptrend, building bearish momentum
|
||||
pendingBearishFlip = trend[1] == 1 and bearMomentumBars > 0 and bearMomentumBars < barsNeeded
|
||||
bearishMomentumProgress = bearMomentumBars
|
||||
|
||||
// =============================================================================
|
||||
// FILTER CALCULATIONS
|
||||
// =============================================================================
|
||||
|
||||
// ADX
|
||||
[diPlus, diMinus, adxVal] = ta.dmi(adxLen, adxLen)
|
||||
|
||||
// RSI
|
||||
rsi14 = ta.rsi(close, 14)
|
||||
|
||||
// Volume ratio
|
||||
volumeSMA = ta.sma(volume, 20)
|
||||
volumeRatio = volumeSMA > 0 ? volume / volumeSMA : 1.0
|
||||
|
||||
// MA Gap
|
||||
ma50 = ta.sma(close, 50)
|
||||
ma200 = ta.sma(close, 200)
|
||||
maGap = ma200 > 0 ? ((ma50 - ma200) / ma200) * 100 : 0
|
||||
|
||||
// Price position
|
||||
highest100 = ta.highest(high, 100)
|
||||
lowest100 = ta.lowest(low, 100)
|
||||
priceRange = highest100 - lowest100
|
||||
pricePosition = priceRange > 0 ? ((close - lowest100) / priceRange) * 100 : 50
|
||||
|
||||
// Filter checks
|
||||
adxOk = not useAdx or (adxVal > adxMin)
|
||||
longBufferOk = not useEntryBuffer or (calcC > supertrend + entryBufferATR * atr)
|
||||
shortBufferOk = not useEntryBuffer or (calcC < supertrend - entryBufferATR * atr)
|
||||
rsiLongOk = not useRsiFilter or (rsi14 >= rsiLongMin and rsi14 <= rsiLongMax)
|
||||
rsiShortOk = not useRsiFilter or (rsi14 >= rsiShortMin and rsi14 <= rsiShortMax)
|
||||
longPositionOk = not usePricePosition or (pricePosition < longPosMax)
|
||||
shortPositionOk = not usePricePosition or (pricePosition > shortPosMin)
|
||||
volumeOk = not useVolumeFilter or (volumeRatio >= volMin and volumeRatio <= volMax)
|
||||
|
||||
// All filters pass (for preview - checking if signal WOULD fire on flip)
|
||||
allLongFiltersPass = adxOk and longBufferOk and rsiLongOk and longPositionOk and volumeOk
|
||||
allShortFiltersPass = adxOk and shortBufferOk and rsiShortOk and shortPositionOk and volumeOk
|
||||
|
||||
// Direction filters
|
||||
allowLong = directionMode == "Both" or directionMode == "Long Only"
|
||||
allowShort = directionMode == "Both" or directionMode == "Short Only"
|
||||
|
||||
// =============================================================================
|
||||
// SIGNALS
|
||||
// =============================================================================
|
||||
|
||||
buyFlip = trend == 1 and trend[1] == -1
|
||||
sellFlip = trend == -1 and trend[1] == 1
|
||||
|
||||
buyReady = ta.barssince(buyFlip) == confirmBars
|
||||
sellReady = ta.barssince(sellFlip) == confirmBars
|
||||
|
||||
// FINAL SIGNALS (all filters applied + direction mode!)
|
||||
finalLongSignal = buyReady and adxOk and longBufferOk and rsiLongOk and longPositionOk and volumeOk and allowLong
|
||||
finalShortSignal = sellReady and adxOk and shortBufferOk and rsiShortOk and shortPositionOk and volumeOk and allowShort
|
||||
|
||||
// =============================================================================
|
||||
// FLIP PREVIEW CONDITIONS
|
||||
// =============================================================================
|
||||
|
||||
// Ready for bullish flip: In downtrend, building momentum, all filters pass
|
||||
readyForBullishFlip = pendingBullishFlip and allLongFiltersPass and allowLong
|
||||
|
||||
// Ready for bearish flip: In uptrend, building momentum, all filters pass
|
||||
readyForBearishFlip = pendingBearishFlip and allShortFiltersPass and allowShort
|
||||
|
||||
// Filters ready but waiting for any flip (no momentum yet)
|
||||
// In downtrend with filters ready for long
|
||||
filtersReadyLong = trend == -1 and allLongFiltersPass and allowLong and not pendingBullishFlip
|
||||
|
||||
// In uptrend with filters ready for short
|
||||
filtersReadyShort = trend == 1 and allShortFiltersPass and allowShort and not pendingBearishFlip
|
||||
|
||||
// =============================================================================
|
||||
// ALERT MESSAGE CONSTRUCTION
|
||||
// =============================================================================
|
||||
|
||||
sym = syminfo.ticker
|
||||
baseCurrency = sym
|
||||
baseCurrency := str.replace(baseCurrency, "USDT", "")
|
||||
baseCurrency := str.replace(baseCurrency, "USD", "")
|
||||
baseCurrency := str.replace(baseCurrency, "PERP", "")
|
||||
|
||||
longAlertMsg = str.format(
|
||||
"{0} buy {1} | ATR:{2} | ADX:{3} | RSI:{4} | VOL:{5} | POS:{6} | MAGAP:{7} | IND:{8} | SCORE:100",
|
||||
baseCurrency,
|
||||
timeframe.period,
|
||||
str.tostring(atrPercent, "#.##"),
|
||||
str.tostring(adxVal, "#.#"),
|
||||
str.tostring(rsi14, "#"),
|
||||
str.tostring(volumeRatio, "#.##"),
|
||||
str.tostring(pricePosition, "#.#"),
|
||||
str.tostring(maGap, "#.##"),
|
||||
indicatorVersion
|
||||
)
|
||||
|
||||
shortAlertMsg = str.format(
|
||||
"{0} sell {1} | ATR:{2} | ADX:{3} | RSI:{4} | VOL:{5} | POS:{6} | MAGAP:{7} | IND:{8} | SCORE:100",
|
||||
baseCurrency,
|
||||
timeframe.period,
|
||||
str.tostring(atrPercent, "#.##"),
|
||||
str.tostring(adxVal, "#.#"),
|
||||
str.tostring(rsi14, "#"),
|
||||
str.tostring(volumeRatio, "#.##"),
|
||||
str.tostring(pricePosition, "#.#"),
|
||||
str.tostring(maGap, "#.##"),
|
||||
indicatorVersion
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// SEND ALERTS
|
||||
// =============================================================================
|
||||
|
||||
if finalLongSignal
|
||||
alert(longAlertMsg, alert.freq_once_per_bar_close)
|
||||
|
||||
if finalShortSignal
|
||||
alert(shortAlertMsg, alert.freq_once_per_bar_close)
|
||||
|
||||
alertcondition(finalLongSignal, title="ML Long Signal", message="{{ticker}} buy {{interval}}")
|
||||
alertcondition(finalShortSignal, title="ML Short Signal", message="{{ticker}} sell {{interval}}")
|
||||
|
||||
// =============================================================================
|
||||
// PLOTS
|
||||
// =============================================================================
|
||||
|
||||
upTrend = trend == 1 ? supertrend : na
|
||||
downTrend = trend == -1 ? supertrend : na
|
||||
|
||||
plot(upTrend, "Up Trend", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=2)
|
||||
plot(downTrend, "Down Trend", color=color.new(color.red, 0), style=plot.style_linebr, linewidth=2)
|
||||
|
||||
// Main signals - triangles
|
||||
plotshape(finalLongSignal, title="Buy Signal", location=location.belowbar, color=color.lime, style=shape.triangleup, size=size.small)
|
||||
plotshape(finalShortSignal, title="Sell Signal", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small)
|
||||
|
||||
// FLIP MARKERS - Show exactly where trend flipped (helps find the moment)
|
||||
plotshape(buyFlip, title="Bull Flip Marker", location=location.belowbar, color=color.white, style=shape.diamond, size=size.tiny, text="FLIP", textcolor=color.white)
|
||||
plotshape(sellFlip, title="Bear Flip Marker", location=location.abovebar, color=color.white, style=shape.diamond, size=size.tiny, text="FLIP", textcolor=color.white)
|
||||
|
||||
// =============================================================================
|
||||
// FLIP PREVIEW PLOTS
|
||||
// =============================================================================
|
||||
|
||||
// Cyan/Magenta circles = Momentum building toward flip (more visible than yellow/orange)
|
||||
plotshape(showFlipPreview and pendingBullishFlip, title="Pending Bull Flip", location=location.belowbar, color=color.aqua, style=shape.circle, size=size.small)
|
||||
plotshape(showFlipPreview and pendingBearishFlip, title="Pending Bear Flip", location=location.abovebar, color=color.fuchsia, style=shape.circle, size=size.small)
|
||||
|
||||
// Blue background = All filters pass, in opposite trend, ready to flip
|
||||
bgcolor(showReadyZones and readyForBullishFlip ? color.new(color.blue, 85) : na, title="Ready for Bull Flip")
|
||||
bgcolor(showReadyZones and readyForBearishFlip ? color.new(color.purple, 85) : na, title="Ready for Bear Flip")
|
||||
|
||||
// Light green background = Filters ready but no momentum yet (watching zone)
|
||||
bgcolor(showReadyZones and filtersReadyLong ? color.new(color.green, 92) : na, title="Filters Ready Long")
|
||||
bgcolor(showReadyZones and filtersReadyShort ? color.new(color.red, 92) : na, title="Filters Ready Short")
|
||||
|
||||
// =============================================================================
|
||||
// DEBUG TABLE (Enhanced with Flip Preview)
|
||||
// =============================================================================
|
||||
|
||||
// Track when last flip happened and if signal fired
|
||||
var int barsSinceLastBullFlip = na
|
||||
var int barsSinceLastBearFlip = na
|
||||
barsSinceLastBullFlip := buyFlip ? 0 : nz(barsSinceLastBullFlip[1], 999) + 1
|
||||
barsSinceLastBearFlip := sellFlip ? 0 : nz(barsSinceLastBearFlip[1], 999) + 1
|
||||
|
||||
var table dbg = table.new(position.top_right, 2, 14, bgcolor=color.new(color.black, 80))
|
||||
if barstate.islast
|
||||
// Original rows
|
||||
table.cell(dbg, 0, 0, "Trend", text_color=color.white)
|
||||
table.cell(dbg, 1, 0, trend == 1 ? "LONG ✓" : "SHORT ✓", text_color=trend == 1 ? color.lime : color.red)
|
||||
table.cell(dbg, 0, 1, "ADX", text_color=color.white)
|
||||
table.cell(dbg, 1, 1, str.tostring(adxVal, "#.#") + (adxOk ? " ✓" : " ✗"), text_color=adxOk ? color.lime : color.red)
|
||||
table.cell(dbg, 0, 2, "RSI", text_color=color.white)
|
||||
table.cell(dbg, 1, 2, str.tostring(rsi14, "#.#") + (rsiLongOk or rsiShortOk ? " ✓" : " ✗"), text_color=rsiLongOk or rsiShortOk ? color.lime : color.orange)
|
||||
table.cell(dbg, 0, 3, "Price Pos", text_color=color.white)
|
||||
table.cell(dbg, 1, 3, str.tostring(pricePosition, "#.#") + "%" + (longPositionOk and shortPositionOk ? " ✓" : ""), text_color=color.white)
|
||||
table.cell(dbg, 0, 4, "Volume", text_color=color.white)
|
||||
table.cell(dbg, 1, 4, useVolumeFilter ? (str.tostring(volumeRatio, "#.##") + "x" + (volumeOk ? " ✓" : " ✗")) : "OFF", text_color=useVolumeFilter ? (volumeOk ? color.lime : color.orange) : color.gray)
|
||||
table.cell(dbg, 0, 5, "Entry Buffer", text_color=color.white)
|
||||
table.cell(dbg, 1, 5, longBufferOk or shortBufferOk ? "OK ✓" : "—", text_color=longBufferOk or shortBufferOk ? color.lime : color.gray)
|
||||
table.cell(dbg, 0, 6, "Direction", text_color=color.white)
|
||||
table.cell(dbg, 1, 6, directionMode, text_color=directionMode == "Long Only" ? color.lime : directionMode == "Short Only" ? color.red : color.yellow)
|
||||
|
||||
// NEW: Flip Preview rows
|
||||
table.cell(dbg, 0, 7, "━━━━━━━━", text_color=color.gray)
|
||||
table.cell(dbg, 1, 7, "━━━━━━━━", text_color=color.gray)
|
||||
|
||||
// Bull momentum progress
|
||||
bullProgressText = trend == -1 ? str.tostring(bullMomentumBars) + "/" + str.tostring(barsNeeded) + " bars" : "—"
|
||||
table.cell(dbg, 0, 8, "Bull Flip", text_color=color.white)
|
||||
table.cell(dbg, 1, 8, bullProgressText, text_color=bullMomentumBars > 0 ? color.yellow : color.gray)
|
||||
|
||||
// Bear momentum progress
|
||||
bearProgressText = trend == 1 ? str.tostring(bearMomentumBars) + "/" + str.tostring(barsNeeded) + " bars" : "—"
|
||||
table.cell(dbg, 0, 9, "Bear Flip", text_color=color.white)
|
||||
table.cell(dbg, 1, 9, bearProgressText, text_color=bearMomentumBars > 0 ? color.orange : color.gray)
|
||||
|
||||
// Filters ready status - show relevant direction based on mode
|
||||
filtersStatus = directionMode == "Long Only" ? (allLongFiltersPass ? "LONG ✓" : "NOT READY") : directionMode == "Short Only" ? (allShortFiltersPass ? "SHORT ✓" : "NOT READY") : trend == -1 ? (allLongFiltersPass ? "LONG ✓" : "NOT READY") : (allShortFiltersPass ? "SHORT ✓" : "NOT READY")
|
||||
filtersColor = directionMode == "Long Only" ? (allLongFiltersPass ? color.lime : color.red) : directionMode == "Short Only" ? (allShortFiltersPass ? color.lime : color.red) : trend == -1 ? (allLongFiltersPass ? color.lime : color.red) : (allShortFiltersPass ? color.lime : color.red)
|
||||
table.cell(dbg, 0, 10, "Filters", text_color=color.white)
|
||||
table.cell(dbg, 1, 10, filtersStatus, text_color=filtersColor)
|
||||
|
||||
// Last flip info - helps debug "why didn't signal fire?"
|
||||
lastFlipText = barsSinceLastBullFlip < barsSinceLastBearFlip ?
|
||||
"BULL " + str.tostring(barsSinceLastBullFlip) + " bars ago" :
|
||||
barsSinceLastBearFlip < 999 ? "BEAR " + str.tostring(barsSinceLastBearFlip) + " bars ago" : "None"
|
||||
table.cell(dbg, 0, 11, "Last Flip", text_color=color.white)
|
||||
table.cell(dbg, 1, 11, lastFlipText, text_color=barsSinceLastBullFlip < 5 ? color.lime : barsSinceLastBearFlip < 5 ? color.red : color.gray)
|
||||
|
||||
// buyReady status - did we pass the confirmation bar requirement?
|
||||
buyReadyText = buyReady ? "READY!" : buyFlip ? "JUST FLIPPED" : barsSinceLastBullFlip < 10 ? "Confirm: " + str.tostring(barsSinceLastBullFlip) + "/" + str.tostring(confirmBars) : "—"
|
||||
table.cell(dbg, 0, 12, "Buy Ready", text_color=color.white)
|
||||
table.cell(dbg, 1, 12, buyReadyText, text_color=buyReady ? color.lime : buyFlip ? color.yellow : color.gray)
|
||||
|
||||
// Signal row
|
||||
table.cell(dbg, 0, 13, "Signal", text_color=color.white)
|
||||
table.cell(dbg, 1, 13, finalLongSignal ? "BUY!" : finalShortSignal ? "SELL!" : "—", text_color=finalLongSignal ? color.lime : finalShortSignal ? color.red : color.gray)
|
||||
Reference in New Issue
Block a user