// This Pine Scriptβ„’ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // Β© TFlab - Asher SMT FVG Pro Edition (Safe & Clean Version) //@version=5 strategy('Asher SMT FVG Strategy', shorttitle = 'Asher SMT FVG Strategy', overlay = true, max_bars_back = 200, max_labels_count = 500, max_lines_count = 500, max_boxes_count = 500, initial_capital = 50000, default_qty_type = strategy.fixed, default_qty_value = 1, process_orders_on_close = false, calc_on_every_tick = true, calc_on_order_fills = true) groupSession = "⏰ Operating Hours & Auto Close" useSessionFilter = input.bool(true, "Enable Daily Hours Filter?", group=groupSession) sessionStartHour = input.int(14, "🟒 Trading Window START - Hour (Israel, 24h)", minval=0, maxval=23, group=groupSession) sessionStartMinute = input.int(0, "🟒 Trading Window START - Minute", minval=0, maxval=59, group=groupSession) sessionEndHour = input.int(19, "πŸ”΄ Trading Window END - Hour (Israel, 24h)", minval=0, maxval=23, group=groupSession) sessionEndMinute = input.int(0, "πŸ”΄ Trading Window END - Minute", minval=0, maxval=59, group=groupSession) groupQuarters = "⏰ Quarters Session Filter" enableQ1 = input.bool(true, "Enable Q1 (01:00 - 07:00)?", group=groupQuarters) enableQ2 = input.bool(true, "Enable Q2 (07:00 - 13:00)?", group=groupQuarters) enableQ3 = input.bool(true, "Enable Q3 (13:00 - 19:00)?", group=groupQuarters) enableQ4 = input.bool(true, "Enable Q4 (19:00 - 01:00)?", group=groupQuarters) groupApex = "πŸ›‘οΈ Apex Risk Management" useDailyLossLimit = input.bool(false, "Enable Daily Max Loss Limit?", group=groupApex) maxDailyLossUSD = input.float(350.0, "Max Daily Loss ($)", minval=10.0, group=groupApex) useTrailingGuard = input.bool(true, "Enable Trailing Drawdown Guard?", group=groupApex) trailingGuardLimit = input.float(1500.0, "Trailing Guard Limit ($)", minval=100.0, group=groupApex) groupWebhook = "πŸ€– PickMyTrade Automation Settings" alertOutputMode = input.string("Testing - Full Lifecycle", "Alert Output Mode", options=["Testing - Full Lifecycle", "Box Signal Only", "PickMyTrade Limit Execution"], group=groupWebhook, tooltip="Testing: one TradingView alert receives Box/Entry/Exit text alerts from the Pine box-touch engine. Box Signal Only: setup notification only. PickMyTrade Limit Execution: submits one broker-side LMT order with the frozen Entry/SL/TP when the box is created; use only for the PickMyTrade webhook alert.") pmtSymbol = input.string("MNQ1!", "PickMyTrade Symbol", group=groupWebhook) pmtStrategyName = input.string("", "PickMyTrade Strategy Name (optional)", group=groupWebhook) pmtAuthToken = input.string("YOUR_AUTH_TOKEN_HERE", "PickMyTrade Auth Token", group=groupWebhook) pmtAccountId = input.string("YOUR_ACCOUNT_ID", "PickMyTrade Account ID", group=groupWebhook) tradeQuantity = input.int(1, "Contracts Quantity", minval=1, group=groupWebhook) bool alertsTestingMode = alertOutputMode == "Testing - Full Lifecycle" bool alertsBoxOnlyMode = alertOutputMode == "Box Signal Only" bool alertsPickMyTradeMode = alertOutputMode == "PickMyTrade Limit Execution" // Escape user-entered strings before embedding them in JSON. f_jsonEscape(string _value) => string _escaped = str.replace_all(_value, "\\", "\\\\") str.replace_all(_escaped, "\"", "\\\"") // Build the PickMyTrade payload from the exact frozen box values. // Production entries use a broker-side LIMIT order so the order is already resting // at the box Entry before price reaches it. TP/SL are sent with the same snapshot. f_pmtJson(string _action, float _price, float _tp, float _sl, string _orderType, float _breakeven) => string _date = str.format_time(timenow, "yyyy-MM-dd'T'HH:mm:ss'Z'", "UTC") string _priceText = str.tostring(_price, format.mintick) string _tpText = str.tostring(_tp, format.mintick) string _slText = str.tostring(_sl, format.mintick) string _beText = str.tostring(_breakeven, format.mintick) string _qtyText = str.tostring(tradeQuantity) string _symbol = f_jsonEscape(pmtSymbol) string _strategyName = f_jsonEscape(pmtStrategyName) string _token = f_jsonEscape(pmtAuthToken) string _account = f_jsonEscape(pmtAccountId) "{" + "\"symbol\":\"" + _symbol + "\"," + "\"strategy_name\":\"" + _strategyName + "\"," + "\"date\":\"" + _date + "\"," + "\"data\":\"" + _action + "\"," + "\"quantity\":" + _qtyText + "," + "\"risk_percentage\":0," + "\"price\":" + _priceText + "," + "\"tp\":" + _tpText + "," + "\"percentage_tp\":0," + "\"dollar_tp\":0," + "\"sl\":" + _slText + "," + "\"dollar_sl\":0," + "\"percentage_sl\":0," + "\"trail\":0," + "\"trail_stop\":0," + "\"trail_trigger\":0," + "\"trail_freq\":0," + "\"update_tp\":false," + "\"update_sl\":false," + "\"breakeven\":" + _beText + "," + "\"breakeven_offset\":0," + "\"token\":\"" + _token + "\"," + "\"pyramid\":false," + "\"same_direction_ignore\":false," + "\"reverse_order_close\":false," + "\"order_type\":\"" + _orderType + "\"," + "\"multiple_accounts\":[{" + "\"token\":\"" + _token + "\"," + "\"account_id\":\"" + _account + "\"," + "\"risk_percentage\":0," + "\"quantity_multiplier\":1" + "}]}" // CLOSE is used only to flatten/cancel broker-side orders when the existing strategy // cancels a still-pending setup (expiry/session/EOD). It is not used for normal TP/SL, // because those protection orders are already attached to the broker-side LMT entry. f_pmtCloseJson(float _price) => f_pmtJson("close", _price, 0.0, 0.0, "MKT", 0.0) groupSym = "🌐 Multi-Asset SMT Settings" sym1 = input.symbol('DXY', 'Asset 1 Symbol (Default)', group=groupSym) useSym2 = input.bool(false, 'Enable Asset 2 SMT?', group=groupSym) sym2 = input.symbol('ES1!', 'Asset 2 Symbol', group=groupSym) useSym3 = input.bool(false, 'Enable Asset 3 SMT?', group=groupSym) sym3 = input.symbol('YM1!', 'Asset 3 Symbol', group=groupSym) groupEngine = "βš™οΈ Core Engine & FVG Execution Settings" pivotMode = input.string("Fast (1 Bar)", "Pivot Type", options=["Fast (1 Bar)", "Standard (2 Bars)"], group=groupEngine) entryMode = input.string("FVG Retracement", "Entry Strategy", options=["FVG Retracement", "Limit Retracement (Swing)", "Confirmation Close", "Swing Price (Unrealistic)"], group=groupEngine) fvgEntryLevel = input.string("FVG Edge (Top/Bottom)", "FVG Fill Level", options=["FVG Edge (Top/Bottom)", "50% FVG (Consequent Encroachment)"], group=groupEngine) maxLimitWait = input.int(6, "⏱️ Max Bars to Wait for Fill", minval=1, maxval=50, group=groupEngine) smtLookbackBars = input.int(30, "⏱️ SMT Lookback Bars Window", minval=5, maxval=100, group=groupEngine) requireFlatBeforeEntry = input.bool(true, "Require Flat Position Before New Entry?", group=groupEngine) useEmaFilter = input.bool(true, "Use EMA Trend Filter?", group=groupEngine) emaLength = input.int(150, "EMA Length", group=groupEngine) groupDisplay = "πŸ‘οΈ Display & Direction Filters" Bull_Line = input.bool(true, 'Show SMT Line (Bull)', group=groupDisplay) Bull_Label = input.bool(true, 'Show SMT Label & Trade (Bull)', group=groupDisplay) Bear_Line = input.bool(true, 'Show SMT Line (Bear)', group=groupDisplay) Bear_Label = input.bool(true, 'Show SMT Label & Trade (Bear)', group=groupDisplay) showQuartersColumns = input.bool(false, 'πŸ“Š Show Quarters Columns (Q1-Q4)?', group=groupDisplay) groupTrade = "🎯 Risk & Reward Settings" useFixedPointsRisk = input.bool(true, "πŸ“Œ Use Fixed Points SL (instead of ATR)?", group=groupTrade) slPoints = input.float(50.0, "πŸ“Œ Stop Loss (Points, e.g. MNQ)", minval=1.0, step=1.0, group=groupTrade) useFixedTP = input.bool(true, "🎯 Use Fixed Points TP (instead of RR)?", group=groupTrade) tpPointsInput = input.float(100.0, "🎯 Take Profit (Points, e.g. MNQ)", minval=1.0, step=1.0, group=groupTrade) atrLen = input.int(14, "πŸ“ ATR Length (used only if Fixed Points is off)", minval=1, group=groupTrade) slAtrMult = input.float(1.5, "πŸ›‘οΈ SL ATR Multiplier (used only if Fixed Points is off)", minval=0.1, step=0.1, group=groupTrade) tpRRInput = input.string("2R", "🎯 Take Profit RR (used only if Fixed Points TP is off)", options=["1R", "1.5R", "1.6R", "1.7R", "1.8R", "1.9R", "2R", "2.5R", "3R", "4R"], group=groupTrade) boxWidth = input.int(6, "πŸ“¦ Box Width (Bars)", minval=1, maxval=30, group=groupTrade) minBarsBetween = input.int(9, "⏱️ Min Bars Between Trades", minval=1, maxval=50, group=groupTrade) groupBE = "πŸ”’ Breakeven Stop" useBreakeven = input.bool(true, "πŸ”’ Enable Breakeven Stop?", group=groupBE) breakevenTriggerRR = input.float(1.18, "πŸ”’ Breakeven Trigger (R multiple)", minval=0.1, step=0.01, group=groupBE) int _nowMinutesIL = hour(time, "Asia/Jerusalem") * 60 + minute(time, "Asia/Jerusalem") int _startMinutesIL = sessionStartHour * 60 + sessionStartMinute int _endMinutesIL = sessionEndHour * 60 + sessionEndMinute bool inAllowedSession = _nowMinutesIL >= _startMinutesIL and _nowMinutesIL < _endMinutesIL isSessionAllowed = useSessionFilter ? inAllowedSession : true int curHourIL = hour(time, "Asia/Jerusalem") int curMinIL = minute(time, "Asia/Jerusalem") bool isEodExit = (curHourIL == 23 and curMinIL >= 55) float todaysClosedProfit = 0.0 if strategy.closedtrades > 0 int todayStartMs = timestamp("Asia/Jerusalem", year(time, "Asia/Jerusalem"), month(time, "Asia/Jerusalem"), dayofmonth(time, "Asia/Jerusalem"), 0, 0, 0) for i = 0 to strategy.closedtrades - 1 if strategy.closedtrades.exit_time(i) >= todayStartMs todaysClosedProfit += strategy.closedtrades.profit(i) bool apexLossLimitReached = useDailyLossLimit and (todaysClosedProfit <= -maxDailyLossUSD) if isEodExit and strategy.position_size != 0 if alertsTestingMode alert("EOD close signal", alert.freq_all) else if alertsPickMyTradeMode // Production webhook channel receives only executable JSON. alert(f_pmtCloseJson(close), alert.freq_all) if isEodExit strategy.close_all(comment="EOD Exit 23:55") int currentHour = hour(time, "Asia/Jerusalem") bool isQ1 = currentHour >= 1 and currentHour < 7 bool isQ2 = currentHour >= 7 and currentHour < 13 bool isQ3 = currentHour >= 13 and currentHour < 19 bool isQ4 = currentHour >= 19 or currentHour < 1 bool isQuarterAllowed = (isQ1 and enableQ1) or (isQ2 and enableQ2) or (isQ3 and enableQ3) or (isQ4 and enableQ4) [s1_Open, s1_High, s1_Low, s1_Close] = request.security(sym1, timeframe.period, [open, high, low, close]) [s2_Open, s2_High, s2_Low, s2_Close] = request.security(sym2, timeframe.period, [open, high, low, close]) [s3_Open, s3_High, s3_Low, s3_Close] = request.security(sym3, timeframe.period, [open, high, low, close]) float emaVal = ta.ema(close, emaLength) bool isBullTrend = useEmaFilter ? close > emaVal : true bool isBearTrend = useEmaFilter ? close < emaVal : true bool IsSwingHigh = false bool IsSwingLow = false if pivotMode == "Fast (1 Bar)" IsSwingHigh := high[1] > high[2] and high[1] > high IsSwingLow := low[1] < low[2] and low[1] < low else IsSwingHigh := high[2] > high[3] and high[2] > high[4] and high[2] > high[1] and high[2] > high IsSwingLow := low[2] < low[3] and low[2] < low[4] and low[2] < low[1] and low[2] < low var float swingHighPrice = na var float swingHighSym1 = na var float swingHighSym2 = na var float swingHighSym3 = na var int swingHighBar = na var int swingHighTime = na var float swingLowPrice = na var float swingLowSym1 = na var float swingLowSym2 = na var float swingLowSym3 = na var int swingLowBar = na var int swingLowTime = na var float prevSwingHighPrice = na var float prevSwingHighSym1 = na var float prevSwingHighSym2 = na var float prevSwingHighSym3 = na var int prevSwingHighBar = na var float prevSwingLowPrice = na var float prevSwingLowSym1 = na var float prevSwingLowSym2 = na var float prevSwingLowSym3 = na var int prevSwingLowBar = na int offset = pivotMode == "Fast (1 Bar)" ? 1 : 2 if IsSwingHigh prevSwingHighPrice := swingHighPrice prevSwingHighSym1 := swingHighSym1 prevSwingHighSym2 := swingHighSym2 prevSwingHighSym3 := swingHighSym3 prevSwingHighBar := swingHighBar swingHighPrice := high[offset] swingHighSym1 := s1_High[offset] swingHighSym2 := s2_High[offset] swingHighSym3 := s3_High[offset] swingHighBar := bar_index - offset swingHighTime := time[offset] if IsSwingLow prevSwingLowPrice := swingLowPrice prevSwingLowSym1 := swingLowSym1 prevSwingLowSym2 := swingLowSym2 prevSwingLowSym3 := swingLowSym3 prevSwingLowBar := swingLowBar swingLowPrice := low[offset] swingLowSym1 := s1_Low[offset] swingLowSym2 := s2_Low[offset] swingLowSym3 := s3_Low[offset] swingLowBar := bar_index - offset swingLowTime := time[offset] bool smt1_bear = ((swingHighPrice > prevSwingHighPrice and swingHighSym1 < prevSwingHighSym1) or (swingHighPrice < prevSwingHighPrice and swingHighSym1 > prevSwingHighSym1)) bool smt2_bear = not useSym2 or ((swingHighPrice > prevSwingHighPrice and swingHighSym2 < prevSwingHighSym2) or (swingHighPrice < prevSwingHighPrice and swingHighSym2 > prevSwingHighSym2)) bool smt3_bear = not useSym3 or ((swingHighPrice > prevSwingHighPrice and swingHighSym3 < prevSwingHighSym3) or (swingHighPrice < prevSwingHighPrice and swingHighSym3 > prevSwingHighSym3)) Time_Condition_Bear = swingHighBar + smtLookbackBars > bar_index Is_Bear_SMT = IsSwingHigh and Time_Condition_Bear and not na(prevSwingHighPrice) and smt1_bear and smt2_bear and smt3_bear bool smt1_bull = ((swingLowPrice < prevSwingLowPrice and swingLowSym1 > prevSwingLowSym1) or (swingLowPrice > prevSwingLowPrice and swingLowSym1 < prevSwingLowSym1)) bool smt2_bull = not useSym2 or ((swingLowPrice < prevSwingLowPrice and swingLowSym2 > prevSwingLowSym2) or (swingLowPrice > prevSwingLowPrice and swingLowSym2 < prevSwingLowSym2)) bool smt3_bull = not useSym3 or ((swingLowPrice < prevSwingLowPrice and swingLowSym3 > prevSwingLowSym3) or (swingLowPrice > prevSwingLowPrice and swingLowSym3 < prevSwingLowSym3)) Time_Condition_Bull = swingLowBar + smtLookbackBars > bar_index Is_Bull_SMT = IsSwingLow and Time_Condition_Bull and not na(prevSwingLowPrice) and smt1_bull and smt2_bull and smt3_bull bool hasBullFVG = high[2] < low[0] float fvgBullEdge = low[0] float fvgBullCE = (low[0] + high[2]) / 2.0 bool hasBearFVG = low[2] > high[0] float fvgBearEdge = high[0] float fvgBearCE = (low[2] + high[0]) / 2.0 bool final_alert = false atrValue = ta.atr(atrLen) tpRR = tpRRInput == "1R" ? 1.0 : tpRRInput == "1.5R" ? 1.5 : tpRRInput == "1.6R" ? 1.6 : tpRRInput == "1.7R" ? 1.7 : tpRRInput == "1.8R" ? 1.8 : tpRRInput == "1.9R" ? 1.9 : tpRRInput == "2R" ? 2.0 : tpRRInput == "2.5R" ? 2.5 : tpRRInput == "3R" ? 3.0 : 4.0 type TradeRecord box tpBox box slBox line entryLine line slLine line tpLine label entryLabel int openTime var array trades = array.new() var int lastTradeBar = -999 var float activeEntryPrice = na var float activeRisk = na var float activeSL = na var float activeTP = na var bool activeIsLong = true var bool beTriggered = false f_deleteTradeDrawings(TradeRecord _tr) => box.delete(_tr.tpBox) box.delete(_tr.slBox) line.delete(_tr.entryLine) line.delete(_tr.slLine) line.delete(_tr.tpLine) if not na(_tr.entryLabel) label.delete(_tr.entryLabel) if array.size(trades) > 2000 TradeRecord oldestTrade = array.get(trades, 0) f_deleteTradeDrawings(oldestTrade) array.shift(trades) f_addTrade(int _startBar, int _dir, float _entry, float _sl, float _tp, int _width, int _openTime, string _lblText) => int rightBar = _startBar + _width float tpTop = _dir == 1 ? _tp : _entry float tpBot = _dir == 1 ? _entry : _tp float slTop = _dir == 1 ? _entry : _sl float slBot = _dir == 1 ? _sl : _entry box tpBox = box.new(_startBar, tpTop, rightBar, tpBot, xloc=xloc.bar_index, bgcolor=color.new(color.green, 82), border_color=color.new(color.green, 0)) box slBox = box.new(_startBar, slTop, rightBar, slBot, xloc=xloc.bar_index, bgcolor=color.new(color.red, 82), border_color=color.new(color.red, 0)) line entryLine = line.new(_startBar, _entry, rightBar, _entry, xloc=xloc.bar_index, color=color.white, width=2) line slLine = line.new(_startBar, _sl, rightBar, _sl, xloc=xloc.bar_index, color=color.red, width=2) line tpLine = line.new(_startBar, _tp, rightBar, _tp, xloc=xloc.bar_index, color=color.green, width=2) label entryLabel = label.new(rightBar, _entry, text=_lblText, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.white, textcolor=color.black, size=size.small) array.push(trades, TradeRecord.new(tpBox, slBox, entryLine, slLine, tpLine, entryLabel, _openTime)) var float peakEquity = 0.0 var bool trailingGuardTripped = false peakEquity := math.max(peakEquity, strategy.netprofit) float liveDrawdown = peakEquity - strategy.netprofit if useTrailingGuard and liveDrawdown >= trailingGuardLimit trailingGuardTripped := true var label guardLabel = na if trailingGuardTripped and na(guardLabel) guardLabel := label.new(bar_index, high, "⚠️ TRAILING GUARD TRIPPED β€” TRADING STOPPED", style=label.style_label_down, color=color.new(color.red,0), textcolor=color.white, size=size.large) var int pendingLongBar = na var int pendingShortBar = na var int pendingLongTime = na var int pendingShortTime = na // --- Realtime synchronized alert lifecycle --- // State: 0 = idle, 1 = waiting for entry touch, 2 = trade active. // `varip` is intentional: these values survive Pine's realtime rollback so each // lifecycle event can fire exactly once on the realtime update that reaches its level. varip int lastBullProcessedBar = na varip int lastBearProcessedBar = na varip int rtLifecycleState = 0 varip int rtLifecycleDir = 0 varip int rtSetupBar = na varip float rtSetupPrice = na varip float rtEntry = na varip float rtRisk = na varip float rtSL = na varip float rtTP = na varip float rtActiveStop = na varip bool rtBeTriggered = false varip bool rtMarketEntry = false // Post-entry extrema are accumulated from realtime `close` updates only AFTER the // entry event. This prevents pre-entry highs/lows from falsely triggering same-bar exits. varip float rtPostEntryHigh = na varip float rtPostEntryLow = na // True only while a broker-side PickMyTrade LMT order is expected to be pending. varip bool rtPmtPendingOrder = false // Realtime marker prices persist for the rest of the event bar, allowing plotshape() // to commit a stable visual marker at the exact price used by the alert state machine. varip float rtMarkLongEntry = na varip float rtMarkShortEntry = na varip float rtMarkTP = na varip float rtMarkSL = na varip float rtMarkBE = na if barstate.isnew rtMarkLongEntry := na rtMarkShortEntry := na rtMarkTP := na rtMarkSL := na rtMarkBE := na // The existing EOD close alert remains authoritative. Clear any realtime lifecycle // state so a closed/cancelled EOD trade cannot generate a stale later level alert. if barstate.isrealtime and isEodExit rtLifecycleState := 0 rtPmtPendingOrder := false bool flatCondition = requireFlatBeforeEntry ? (strategy.position_size == 0) : true bool noPendingOrder = na(pendingLongBar) and na(pendingShortBar) bool canTrade = (bar_index - lastTradeBar >= minBarsBetween) and isSessionAllowed and flatCondition and noPendingOrder and not apexLossLimitReached and not trailingGuardTripped trigger_bull = Is_Bull_SMT and barstate.isconfirmed and canTrade and Bull_Label and isBullTrend and isQuarterAllowed trigger_bear = Is_Bear_SMT and barstate.isconfirmed and canTrade and Bear_Label and isBearTrend and isQuarterAllowed string currentTF = timeframe.period if not na(pendingLongBar) and (bar_index - pendingLongBar) > maxLimitWait strategy.cancel("Long") pendingLongBar := na pendingLongTime := na if barstate.isrealtime and rtLifecycleState == 1 and rtLifecycleDir == 1 if alertsPickMyTradeMode and rtPmtPendingOrder alert(f_pmtCloseJson(close), alert.freq_all) rtPmtPendingOrder := false rtLifecycleState := 0 if not na(pendingShortBar) and (bar_index - pendingShortBar) > maxLimitWait strategy.cancel("Short") pendingShortBar := na pendingShortTime := na if barstate.isrealtime and rtLifecycleState == 1 and rtLifecycleDir == -1 if alertsPickMyTradeMode and rtPmtPendingOrder alert(f_pmtCloseJson(close), alert.freq_all) rtPmtPendingOrder := false rtLifecycleState := 0 int _maxWaitMs = maxLimitWait * 60 * 1000 if not na(pendingLongTime) and (time - pendingLongTime) > _maxWaitMs strategy.cancel("Long") pendingLongBar := na pendingLongTime := na if barstate.isrealtime and rtLifecycleState == 1 and rtLifecycleDir == 1 if alertsPickMyTradeMode and rtPmtPendingOrder alert(f_pmtCloseJson(close), alert.freq_all) rtPmtPendingOrder := false rtLifecycleState := 0 if not na(pendingShortTime) and (time - pendingShortTime) > _maxWaitMs strategy.cancel("Short") pendingShortBar := na pendingShortTime := na if barstate.isrealtime and rtLifecycleState == 1 and rtLifecycleDir == -1 if alertsPickMyTradeMode and rtPmtPendingOrder alert(f_pmtCloseJson(close), alert.freq_all) rtPmtPendingOrder := false rtLifecycleState := 0 if strategy.position_size != 0 pendingLongBar := na pendingShortBar := na pendingLongTime := na pendingShortTime := na if not isSessionAllowed or not isQuarterAllowed if not na(pendingLongBar) strategy.cancel("Long") pendingLongBar := na pendingLongTime := na if barstate.isrealtime and rtLifecycleState == 1 and rtLifecycleDir == 1 if alertsPickMyTradeMode and rtPmtPendingOrder alert(f_pmtCloseJson(close), alert.freq_all) rtPmtPendingOrder := false rtLifecycleState := 0 if not na(pendingShortBar) strategy.cancel("Short") pendingShortBar := na pendingShortTime := na if barstate.isrealtime and rtLifecycleState == 1 and rtLifecycleDir == -1 if alertsPickMyTradeMode and rtPmtPendingOrder alert(f_pmtCloseJson(close), alert.freq_all) rtPmtPendingOrder := false rtLifecycleState := 0 if trigger_bull final_alert := true lastTradeBar := bar_index if Bull_Line line.new(prevSwingLowBar, prevSwingLowPrice, swingLowBar, swingLowPrice, color = color.green, width = 2, style = line.style_dashed) float entryPrice = close string lbl = "ENTRY" if entryMode == "FVG Retracement" entryPrice := fvgEntryLevel == "50% FVG (Consequent Encroachment)" ? fvgBullCE : fvgBullEdge lbl := "FVG LIMIT" else if entryMode == "Limit Retracement (Swing)" entryPrice := swingLowPrice lbl := "SWING LIMIT" else if entryMode == "Swing Price (Unrealistic)" entryPrice := swingLowPrice float risk = useFixedPointsRisk ? slPoints : atrValue * slAtrMult float sl = entryPrice - risk float tp = useFixedTP ? entryPrice + tpPointsInput : entryPrice + risk * tpRR // One immutable snapshot feeds the box, strategy order and realtime alert lifecycle. float syncEntry = entryPrice float syncRisk = risk float syncSL = sl float syncTP = tp f_addTrade(bar_index, 1, syncEntry, syncSL, syncTP, boxWidth, time, lbl) activeEntryPrice := syncEntry activeRisk := syncRisk activeSL := syncSL activeTP := syncTP activeIsLong := true beTriggered := false bool isNewBullAutomationEvent = na(lastBullProcessedBar) or lastBullProcessedBar != bar_index if isNewBullAutomationEvent // Lock BEFORE any external event/order so same-bar realtime recalculation cannot duplicate it. lastBullProcessedBar := bar_index // Arm the Pine-controlled realtime lifecycle from the exact same frozen box values. if barstate.isrealtime rtLifecycleState := 1 rtLifecycleDir := 1 rtSetupBar := bar_index rtSetupPrice := close rtEntry := syncEntry rtRisk := syncRisk rtSL := syncSL rtTP := syncTP rtActiveStop := syncSL rtBeTriggered := false rtMarketEntry := entryMode == "Confirmation Close" rtPostEntryHigh := na rtPostEntryLow := na rtPmtPendingOrder := false // Alert #1 for testing/notification. In production PickMyTrade mode, the same // setup event submits the broker-side order immediately so it can rest at the // exact box Entry before price arrives. if alertsTestingMode or alertsBoxOnlyMode alert("Long signal", alert.freq_once_per_bar_close) else if alertsPickMyTradeMode and barstate.isrealtime float pmtBeTrigger = useBreakeven ? syncRisk * breakevenTriggerRR : 0.0 string pmtOrderType = entryMode == "Confirmation Close" ? "MKT" : "LMT" alert(f_pmtJson("buy", syncEntry, syncTP, syncSL, pmtOrderType, pmtBeTrigger), alert.freq_once_per_bar_close) rtPmtPendingOrder := entryMode != "Confirmation Close" // Existing strategy order logic is preserved; order-fill alerts are no longer the timing source. if entryMode == "Confirmation Close" strategy.entry("Long", strategy.long, qty=tradeQuantity) else strategy.entry("Long", strategy.long, qty=tradeQuantity, limit=syncEntry) if entryMode != "Confirmation Close" and strategy.position_size == 0 pendingLongBar := bar_index pendingLongTime := time if trigger_bear final_alert := true lastTradeBar := bar_index if Bear_Line line.new(prevSwingHighBar, prevSwingHighPrice, swingHighBar, swingHighPrice, color = color.red, width = 2, style = line.style_dashed) float entryPrice = close string lbl = "ENTRY" if entryMode == "FVG Retracement" entryPrice := fvgEntryLevel == "50% FVG (Consequent Encroachment)" ? fvgBearCE : fvgBearEdge lbl := "FVG LIMIT" else if entryMode == "Limit Retracement (Swing)" entryPrice := swingHighPrice lbl := "SWING LIMIT" else if entryMode == "Swing Price (Unrealistic)" entryPrice := swingHighPrice float risk = useFixedPointsRisk ? slPoints : atrValue * slAtrMult float sl = entryPrice + risk float tp = useFixedTP ? entryPrice - tpPointsInput : entryPrice - risk * tpRR float syncEntry = entryPrice float syncRisk = risk float syncSL = sl float syncTP = tp f_addTrade(bar_index, -1, syncEntry, syncSL, syncTP, boxWidth, time, lbl) activeEntryPrice := syncEntry activeRisk := syncRisk activeSL := syncSL activeTP := syncTP activeIsLong := false beTriggered := false bool isNewBearAutomationEvent = na(lastBearProcessedBar) or lastBearProcessedBar != bar_index if isNewBearAutomationEvent lastBearProcessedBar := bar_index if barstate.isrealtime rtLifecycleState := 1 rtLifecycleDir := -1 rtSetupBar := bar_index rtSetupPrice := close rtEntry := syncEntry rtRisk := syncRisk rtSL := syncSL rtTP := syncTP rtActiveStop := syncSL rtBeTriggered := false rtMarketEntry := entryMode == "Confirmation Close" rtPostEntryHigh := na rtPostEntryLow := na rtPmtPendingOrder := false // Alert #1 for testing/notification. In production PickMyTrade mode, the same // setup event submits the broker-side order immediately so it can rest at the // exact box Entry before price arrives. if alertsTestingMode or alertsBoxOnlyMode alert("Short signal", alert.freq_once_per_bar_close) else if alertsPickMyTradeMode and barstate.isrealtime float pmtBeTrigger = useBreakeven ? syncRisk * breakevenTriggerRR : 0.0 string pmtOrderType = entryMode == "Confirmation Close" ? "MKT" : "LMT" alert(f_pmtJson("sell", syncEntry, syncTP, syncSL, pmtOrderType, pmtBeTrigger), alert.freq_once_per_bar_close) rtPmtPendingOrder := entryMode != "Confirmation Close" if entryMode == "Confirmation Close" strategy.entry("Short", strategy.short, qty=tradeQuantity) else strategy.entry("Short", strategy.short, qty=tradeQuantity, limit=syncEntry) if entryMode != "Confirmation Close" and strategy.position_size == 0 pendingShortBar := bar_index pendingShortTime := time // ----------------------------------------------------------------------------- // Pine-controlled realtime BOX-LEVEL touch engine. // The box is authoritative. TradingView strategy arrows/order-fill alerts are ignored // for automation timing. Entry uses the frozen box Entry; exits use the same frozen // TP/SL (and active BE stop) snapshot. // ----------------------------------------------------------------------------- if barstate.isrealtime and rtLifecycleState == 1 and not na(rtEntry) bool entryTouched = false if rtMarketEntry // Confirmation Close belongs to the setup event itself. entryTouched := true else if bar_index == rtSetupBar // On the setup bar, high/low contain price history from BEFORE the box existed. // Use only the current realtime price to avoid a false retroactive touch. entryTouched := rtLifecycleDir == 1 ? (rtEntry >= rtSetupPrice or close <= rtEntry) : (rtEntry <= rtSetupPrice or close >= rtEntry) else // After the box exists, the complete realtime bar range is valid evidence that // the exact box Entry was touched, even if price jumps through and rebounds // before the next visible update. entryTouched := rtLifecycleDir == 1 ? low <= rtEntry : high >= rtEntry if entryTouched // Lock the transition before external alerts. rtLifecycleState := 2 rtActiveStop := rtSL rtBeTriggered := false // Start post-entry extrema from the CURRENT realtime price only. Never import // earlier high/low from this candle, because those extremes may pre-date entry. rtPostEntryHigh := close rtPostEntryLow := close rtPmtPendingOrder := false if rtLifecycleDir == 1 rtMarkLongEntry := rtEntry if alertsTestingMode alert("LONG ENTRY | Entry: " + str.tostring(rtEntry, format.mintick) + " | SL: " + str.tostring(rtSL, format.mintick) + " | TP: " + str.tostring(rtTP, format.mintick), alert.freq_all) else rtMarkShortEntry := rtEntry if alertsTestingMode alert("SHORT ENTRY | Entry: " + str.tostring(rtEntry, format.mintick) + " | SL: " + str.tostring(rtSL, format.mintick) + " | TP: " + str.tostring(rtTP, format.mintick), alert.freq_all) if barstate.isrealtime and rtLifecycleState == 2 and not na(rtEntry) and not na(rtTP) and not na(rtActiveStop) // Accumulate only realtime prices observed AFTER the entry event. This catches a // wick/jump through a level without allowing a pre-entry wick to create a false exit. rtPostEntryHigh := na(rtPostEntryHigh) ? close : math.max(rtPostEntryHigh, close) rtPostEntryLow := na(rtPostEntryLow) ? close : math.min(rtPostEntryLow, close) // First resolve TP/current-stop touches using the stop that was actually active // during the observed price path. This prevents a later BE activation from // retroactively treating an earlier pre-BE price as a breakeven stop hit. bool tpTouched = rtLifecycleDir == 1 ? rtPostEntryHigh >= rtTP : rtPostEntryLow <= rtTP bool stopTouched = rtLifecycleDir == 1 ? rtPostEntryLow <= rtActiveStop : rtPostEntryHigh >= rtActiveStop if tpTouched or stopTouched // If a missed/gapped update spans both levels and tick ordering is unknowable, // resolve stop-first as the conservative risk-preserving outcome. bool resolveAsStop = stopTouched float exitLevel = resolveAsStop ? rtActiveStop : rtTP string exitText = "" if rtLifecycleDir == 1 if resolveAsStop and rtBeTriggered and rtActiveStop == rtEntry exitText := "LONG BREAKEVEN EXIT | Stop: " + str.tostring(rtActiveStop, format.mintick) rtMarkBE := exitLevel else if resolveAsStop exitText := "LONG STOP LOSS HIT | Stop: " + str.tostring(rtActiveStop, format.mintick) rtMarkSL := exitLevel else exitText := "LONG TAKE PROFIT HIT | TP: " + str.tostring(rtTP, format.mintick) rtMarkTP := exitLevel else if resolveAsStop and rtBeTriggered and rtActiveStop == rtEntry exitText := "SHORT BREAKEVEN EXIT | Stop: " + str.tostring(rtActiveStop, format.mintick) rtMarkBE := exitLevel else if resolveAsStop exitText := "SHORT STOP LOSS HIT | Stop: " + str.tostring(rtActiveStop, format.mintick) rtMarkSL := exitLevel else exitText := "SHORT TAKE PROFIT HIT | TP: " + str.tostring(rtTP, format.mintick) rtMarkTP := exitLevel // One-shot lifecycle completion. Production PickMyTrade mode does NOT send a // delayed market CLOSE here: its TP/SL/BE protection was attached at the broker // when the setup LMT was submitted. Testing mode still reports the exact box exit. rtLifecycleState := 0 if alertsTestingMode alert(exitText, alert.freq_all) else if useBreakeven and not rtBeTriggered // Activate BE only after confirming the trade has not already reached TP/SL. bool beActivationTouched = rtLifecycleDir == 1 ? rtPostEntryHigh >= rtEntry + rtRisk * breakevenTriggerRR : rtPostEntryLow <= rtEntry - rtRisk * breakevenTriggerRR if beActivationTouched rtActiveStop := rtEntry rtBeTriggered := true // Reset ONLY the stop-side extreme at the activation tick. Earlier prices // occurred before BE existed and must not trigger the newly moved stop. if rtLifecycleDir == 1 rtPostEntryLow := close else rtPostEntryHigh := close // Stable visual markers for the Pine-controlled realtime events. Unlike TradingView's // built-in strategy arrows, these are plotted at the exact frozen levels used by alerts. plotshape(rtMarkLongEntry, title="Sync Long Entry", style=shape.triangleup, location=location.absolute, color=color.new(color.green, 0), text="SYNC ENTRY", textcolor=color.white, size=size.tiny) plotshape(rtMarkShortEntry, title="Sync Short Entry", style=shape.triangledown, location=location.absolute, color=color.new(color.red, 0), text="SYNC ENTRY", textcolor=color.white, size=size.tiny) plotshape(rtMarkTP, title="Sync Take Profit", style=shape.circle, location=location.absolute, color=color.new(color.green, 0), text="SYNC TP", textcolor=color.white, size=size.tiny) plotshape(rtMarkSL, title="Sync Stop Loss", style=shape.xcross, location=location.absolute, color=color.new(color.red, 0), text="SYNC SL", textcolor=color.white, size=size.tiny) plotshape(rtMarkBE, title="Sync Breakeven", style=shape.diamond, location=location.absolute, color=color.new(color.gray, 0), text="SYNC BE", textcolor=color.white, size=size.tiny) // Existing strategy trade management remains unchanged and continues to drive // chart/backtest orders. Its order-fill notifications are intentionally not used // as the realtime alert timing source anymore. if strategy.position_size != 0 and not na(activeSL) if useBreakeven and not beTriggered if activeIsLong and high >= activeEntryPrice + activeRisk * breakevenTriggerRR activeSL := activeEntryPrice beTriggered := true if not activeIsLong and low <= activeEntryPrice - activeRisk * breakevenTriggerRR activeSL := activeEntryPrice beTriggered := true if activeIsLong strategy.exit("Exit Long", "Long", stop=activeSL, limit=activeTP) else strategy.exit("Exit Short", "Short", stop=activeSL, limit=activeTP) if strategy.position_size == 0 beTriggered := false f_fmtQ(int w, int l) => int tot = w + l if tot == 0 "-" else float wr = (float(w) / float(tot)) * 100.0 str.tostring(w) + "-" + str.tostring(l) + " (" + str.tostring(wr, "#") + "%)" var table dash = table.new(position = position.top_right, columns = 8, rows = 6, bgcolor = color.rgb(12, 12, 16), border_color = color.new(color.gray, 50), border_width = 1) if barstate.islast table.clear(dash, 0, 0, 7, 5) int currentBarTime = time int dailyTotal = 0, dailyWins = 0, dailyLosses = 0 int threeDailyTotal = 0, threeDailyWins = 0, threeDailyLosses = 0 int weeklyTotal = 0, weeklyWins = 0, weeklyLosses = 0 int monthlyTotal = 0, monthlyWins = 0, monthlyLosses = 0 int allTotal = 0, allWins = 0, allLosses = 0 var qWinsDaily = array.new_int(4, 0), qLossesDaily = array.new_int(4, 0) var qWins3Daily = array.new_int(4, 0), qLosses3Daily = array.new_int(4, 0) var qWinsWeekly = array.new_int(4, 0), qLossesWeekly = array.new_int(4, 0) var qWinsMonthly = array.new_int(4, 0), qLossesMonthly = array.new_int(4, 0) var qWinsTotal = array.new_int(4, 0), qLossesTotal = array.new_int(4, 0) array.fill(qWinsDaily, 0), array.fill(qLossesDaily, 0) array.fill(qWins3Daily, 0), array.fill(qLosses3Daily, 0) array.fill(qWinsWeekly, 0), array.fill(qLossesWeekly, 0) array.fill(qWinsMonthly, 0), array.fill(qLossesMonthly, 0) array.fill(qWinsTotal, 0), array.fill(qLossesTotal, 0) if strategy.closedtrades > 0 for i = 0 to strategy.closedtrades - 1 int trTime = strategy.closedtrades.entry_time(i) float trProfit = strategy.closedtrades.profit(i) bool isWin = (trProfit > 0) bool isLoss = (trProfit < 0) bool isDaily = (trTime >= currentBarTime - 86400000) bool isThreeDaily = (trTime >= currentBarTime - 3 * 86400000) bool isWeekly = (trTime >= currentBarTime - 7 * 86400000) bool isMonthly = (trTime >= currentBarTime - 30 * 86400000) int trHour = hour(trTime, "Asia/Jerusalem") int qIdx = 0 if trHour >= 1 and trHour < 7 qIdx := 0 else if trHour >= 7 and trHour < 13 qIdx := 1 else if trHour >= 13 and trHour < 19 qIdx := 2 else qIdx := 3 if isDaily dailyTotal += 1 if isWin dailyWins += 1 array.set(qWinsDaily, qIdx, array.get(qWinsDaily, qIdx) + 1) else if isLoss dailyLosses += 1 array.set(qLossesDaily, qIdx, array.get(qLossesDaily, qIdx) + 1) if isThreeDaily threeDailyTotal += 1 if isWin threeDailyWins += 1 array.set(qWins3Daily, qIdx, array.get(qWins3Daily, qIdx) + 1) else if isLoss threeDailyLosses += 1 array.set(qLosses3Daily, qIdx, array.get(qLosses3Daily, qIdx) + 1) if isWeekly weeklyTotal += 1 if isWin weeklyWins += 1 array.set(qWinsWeekly, qIdx, array.get(qWinsWeekly, qIdx) + 1) else if isLoss weeklyLosses += 1 array.set(qLossesWeekly, qIdx, array.get(qLossesWeekly, qIdx) + 1) if isMonthly monthlyTotal += 1 if isWin monthlyWins += 1 array.set(qWinsMonthly, qIdx, array.get(qWinsMonthly, qIdx) + 1) else if isLoss monthlyLosses += 1 array.set(qLossesMonthly, qIdx, array.get(qLossesMonthly, qIdx) + 1) allTotal += 1 if isWin allWins += 1 array.set(qWinsTotal, qIdx, array.get(qWinsTotal, qIdx) + 1) else if isLoss allLosses += 1 array.set(qLossesTotal, qIdx, array.get(qLossesTotal, qIdx) + 1) float closedDaily = float(dailyWins + dailyLosses) float closedThreeDaily = float(threeDailyWins + threeDailyLosses) float closedWeekly = float(weeklyWins + weeklyLosses) float closedMonthly = float(monthlyWins + monthlyLosses) float closedAll = float(allWins + allLosses) float dailyWr = closedDaily > 0 ? (float(dailyWins) / closedDaily) * 100.0 : 0.0 float threeDailyWr = closedThreeDaily > 0 ? (float(threeDailyWins) / closedThreeDaily) * 100.0 : 0.0 float weeklyWr = closedWeekly > 0 ? (float(weeklyWins) / closedWeekly) * 100.0 : 0.0 float monthlyWr = closedMonthly > 0 ? (float(monthlyWins) / closedMonthly) * 100.0 : 0.0 float allWr = closedAll > 0 ? (float(allWins) / closedAll) * 100.0 : 0.0 table.cell(dash, 0, 0, "Period", text_color = color.white, text_size = size.small) table.cell(dash, 1, 0, "Trades", text_color = color.white, text_size = size.small) table.cell(dash, 2, 0, "W - L", text_color = color.orange, text_size = size.small) table.cell(dash, 3, 0, "Win %", text_color = color.aqua, text_size = size.small) if showQuartersColumns table.cell(dash, 4, 0, "Q1 (01-07)", text_color = color.yellow, text_size = size.small) table.cell(dash, 5, 0, "Q2 (07-13)", text_color = color.yellow, text_size = size.small) table.cell(dash, 6, 0, "Q3 (13-19)", text_color = color.yellow, text_size = size.small) table.cell(dash, 7, 0, "Q4 (19-01)", text_color = color.yellow, text_size = size.small) table.cell(dash, 0, 1, "Daily", text_color = color.white, text_size = size.small) table.cell(dash, 1, 1, str.tostring(dailyTotal), text_color = color.white, text_size = size.small) table.cell(dash, 2, 1, str.tostring(dailyWins) + " - " + str.tostring(dailyLosses), text_color = color.green, text_size = size.small) table.cell(dash, 3, 1, str.tostring(dailyWr, "#.##") + "%", text_color = color.aqua, text_size = size.small) if showQuartersColumns table.cell(dash, 4, 1, f_fmtQ(array.get(qWinsDaily, 0), array.get(qLossesDaily, 0)), text_color = color.white, text_size = size.small) table.cell(dash, 5, 1, f_fmtQ(array.get(qWinsDaily, 1), array.get(qLossesDaily, 1)), text_color = color.white, text_size = size.small) table.cell(dash, 6, 1, f_fmtQ(array.get(qWinsDaily, 2), array.get(qLossesDaily, 2)), text_color = color.white, text_size = size.small) table.cell(dash, 7, 1, f_fmtQ(array.get(qWinsDaily, 3), array.get(qLossesDaily, 3)), text_color = color.white, text_size = size.small) table.cell(dash, 0, 2, "3 Daily", text_color = color.white, text_size = size.small) table.cell(dash, 1, 2, str.tostring(threeDailyTotal), text_color = color.white, text_size = size.small) table.cell(dash, 2, 2, str.tostring(threeDailyWins) + " - " + str.tostring(threeDailyLosses), text_color = color.green, text_size = size.small) table.cell(dash, 3, 2, str.tostring(threeDailyWr, "#.##") + "%", text_color = color.aqua, text_size = size.small) if showQuartersColumns table.cell(dash, 4, 2, f_fmtQ(array.get(qWins3Daily, 0), array.get(qLosses3Daily, 0)), text_color = color.white, text_size = size.small) table.cell(dash, 5, 2, f_fmtQ(array.get(qWins3Daily, 1), array.get(qLosses3Daily, 1)), text_color = color.white, text_size = size.small) table.cell(dash, 6, 2, f_fmtQ(array.get(qWins3Daily, 2), array.get(qLosses3Daily, 2)), text_color = color.white, text_size = size.small) table.cell(dash, 7, 2, f_fmtQ(array.get(qWins3Daily, 3), array.get(qLosses3Daily, 3)), text_color = color.white, text_size = size.small) table.cell(dash, 0, 3, "Weekly", text_color = color.white, text_size = size.small) table.cell(dash, 1, 3, str.tostring(weeklyTotal), text_color = color.white, text_size = size.small) table.cell(dash, 2, 3, str.tostring(weeklyWins) + " - " + str.tostring(weeklyLosses), text_color = color.green, text_size = size.small) table.cell(dash, 3, 3, str.tostring(weeklyWr, "#.##") + "%", text_color = color.aqua, text_size = size.small) if showQuartersColumns table.cell(dash, 4, 3, f_fmtQ(array.get(qWinsWeekly, 0), array.get(qLossesWeekly, 0)), text_color = color.white, text_size = size.small) table.cell(dash, 5, 3, f_fmtQ(array.get(qWinsWeekly, 1), array.get(qLossesWeekly, 1)), text_color = color.white, text_size = size.small) table.cell(dash, 6, 3, f_fmtQ(array.get(qWinsWeekly, 2), array.get(qLossesWeekly, 2)), text_color = color.white, text_size = size.small) table.cell(dash, 7, 3, f_fmtQ(array.get(qWinsWeekly, 3), array.get(qLossesWeekly, 3)), text_color = color.white, text_size = size.small) table.cell(dash, 0, 4, "Monthly", text_color = color.white, text_size = size.small) table.cell(dash, 1, 4, str.tostring(monthlyTotal), text_color = color.white, text_size = size.small) table.cell(dash, 2, 4, str.tostring(monthlyWins) + " - " + str.tostring(monthlyLosses), text_color = color.green, text_size = size.small) table.cell(dash, 3, 4, str.tostring(monthlyWr, "#.##") + "%", text_color = color.aqua, text_size = size.small) if showQuartersColumns table.cell(dash, 4, 4, f_fmtQ(array.get(qWinsMonthly, 0), array.get(qLossesMonthly, 0)), text_color = color.white, text_size = size.small) table.cell(dash, 5, 4, f_fmtQ(array.get(qWinsMonthly, 1), array.get(qLossesMonthly, 1)), text_color = color.white, text_size = size.small) table.cell(dash, 6, 4, f_fmtQ(array.get(qWinsMonthly, 2), array.get(qLossesMonthly, 2)), text_color = color.white, text_size = size.small) table.cell(dash, 7, 4, f_fmtQ(array.get(qWinsMonthly, 3), array.get(qLossesMonthly, 3)), text_color = color.white, text_size = size.small) table.cell(dash, 0, 5, "All Time", text_color = color.white, text_size = size.small) table.cell(dash, 1, 5, str.tostring(allTotal), text_color = color.white, text_size = size.small) table.cell(dash, 2, 5, str.tostring(allWins) + " - " + str.tostring(allLosses), text_color = color.green, text_size = size.small) table.cell(dash, 3, 5, str.tostring(allWr, "#.##") + "%", text_color = color.aqua, text_size = size.small) if showQuartersColumns table.cell(dash, 4, 5, f_fmtQ(array.get(qWinsTotal, 0), array.get(qLossesTotal, 0)), text_color = color.white, text_size = size.small) table.cell(dash, 5, 5, f_fmtQ(array.get(qWinsTotal, 1), array.get(qLossesTotal, 1)), text_color = color.white, text_size = size.small) table.cell(dash, 6, 5, f_fmtQ(array.get(qWinsTotal, 2), array.get(qLossesTotal, 2)), text_color = color.white, text_size = size.small) table.cell(dash, 7, 5, f_fmtQ(array.get(qWinsTotal, 3), array.get(qLossesTotal, 3)), text_color = color.white, text_size = size.small)