//@version=6 strategy('SMC_MT5_040925', shorttitle='SMC_MT5_040925', overlay=true, pyramiding=1, initial_capital=100000, commission_type=strategy.commission.percent, commission_value=0.00, margin_long=0, margin_short=0, calc_on_every_tick=true, process_orders_on_close=false, use_bar_magnifier=true) // === Inputs === enable_long_strategy = input.bool(true, title='Enable Long Strategy') enable_short_strategy = input.bool(true, title='Enable Short Strategy') period = input.int(5, 'Length', minval=1) tp_perc = input.float(0.5, 'TP (%)', step=0.1) sl_perc = input.float(0.1, 'SL (%)', step=0.1) // Order size inputs order_size_mode = input.string("USD", title="Order Size Mode", options=["USD", "Lots"]) order_size_value = input.float(250000, title="Order Size", minval=0.01, step=0.01) contract_size = input.float(10, title="Contract Size (units per lot)", tooltip="For XAUUSD: 100, for US30: 10") showPivotLabels = input.bool(false, title="Show Static Pivot Labels") // === helper to format numbers for display (round to 2 decimals, force leading zero) === format2(_x) => float rnd = math.round(_x * 100.0) / 100.0 str.tostring(rnd, "0.00") // === Colors & Styles === color GREEN = color.rgb(2, 133, 69) color RED = color.rgb(246, 7, 7) color OFF = color.new(color.red, 100) StyleSwitch = line.style_dotted // === Vars === var float UpdatedHigh = na var float UpdatedLow = na var int HighIndex = na var int LowIndex = na var bool phActive = false var bool plActive = false var bool BUY = false var bool SELL = false int Sync = bar_index var float entryQty = na var float longTpPrice = na var float longSlPrice = na var float shortTpPrice = na var float shortSlPrice = na // --- Variables for last pivot tracking --- var float lastPH = na var float lastPL = na var int lastPHIndex = na var int lastPLIndex = na var line lastPHLine = na var line lastPLLine = na var bool phTaken = false var bool plTaken = false // === NEW: Visuals for active trades === var line tpLine = na var line slLine = na var line entryLine = na var label tpLabel = na var label slLabel = na var label entryLabel = na labelTransparency = 100 // higher = more transparent // === Active Pivot Labels === var label activePHLabel = na var label activePLLabel = na // === Pivot Detection === PH = ta.pivothigh(high, period, period) PL = ta.pivotlow(low, period, period) if ta.change(fixnan(PH)) != 0 UpdatedHigh := PH phActive := true HighIndex := Sync - period line.new(HighIndex, UpdatedHigh, Sync, UpdatedHigh, color=color.gray, style=line.style_dashed, width=1) if showPivotLabels label.new(HighIndex, UpdatedHigh, "Pivot High", style=label.style_label_down, color=color.new(color.gray, 100), textcolor=color.black, size=size.small) lastPH := PH lastPHIndex := HighIndex phTaken := false if na(activePHLabel) activePHLabel := label.new(bar_index - 1, UpdatedHigh, "Active PH: " + format2(UpdatedHigh), style=label.style_label_lower_left, textcolor=color.black, color=color.new(color.orange, 100), size=size.normal) else label.set_x(activePHLabel, bar_index) label.set_y(activePHLabel, UpdatedHigh) label.set_text(activePHLabel, "Active PH: " + format2(UpdatedHigh)) if ta.change(fixnan(PL)) != 0 UpdatedLow := PL plActive := true LowIndex := Sync - period line.new(LowIndex, UpdatedLow, Sync, UpdatedLow, color=color.gray, style=line.style_dashed, width=1) if showPivotLabels label.new(LowIndex, UpdatedLow, "Pivot Low", style=label.style_label_up, color=color.new(color.gray, 100), textcolor=color.black, size=size.small) lastPL := PL lastPLIndex := LowIndex plTaken := false if na(activePLLabel) activePLLabel := label.new(bar_index - 1 , UpdatedLow, "Active PL: " + format2(UpdatedLow), style=label.style_label_upper_left, textcolor=color.black, color=color.new(color.teal, 100), size=size.normal) else label.set_x(activePLLabel, bar_index) label.set_y(activePLLabel, UpdatedLow) label.set_text(activePLLabel, "Active PL: " + format2(UpdatedLow)) // Draw/update last PH line if not taken if not na(lastPH) and not phTaken if na(lastPHLine) lastPHLine := line.new(lastPHIndex, lastPH, bar_index, lastPH, color=color.green, style=line.style_solid, width=2) else line.set_xy1(lastPHLine, lastPHIndex, lastPH) line.set_xy2(lastPHLine, bar_index, lastPH) // Draw/update last PL line if not taken if not na(lastPL) and not plTaken if na(lastPLLine) lastPLLine := line.new(lastPLIndex, lastPL, bar_index, lastPL, color=color.red, style=line.style_solid, width=2) else line.set_xy1(lastPLLine, lastPLIndex, lastPL) line.set_xy2(lastPLLine, bar_index, lastPL) // === Breakout BUY/SELL detection === BUY := false SELL := false if high > UpdatedHigh and phActive and bar_index > HighIndex BUY := true phActive := false phTaken := true if not na(lastPHLine) line.delete(lastPHLine) lastPHLine := na if not na(activePHLabel) label.delete(activePHLabel) activePHLabel := na if low < UpdatedLow and plActive and bar_index > LowIndex SELL := true plActive := false plTaken := true if not na(lastPLLine) line.delete(lastPLLine) lastPLLine := na if not na(activePLLabel) label.delete(activePLLabel) activePLLabel := na if BUY line.new(HighIndex, UpdatedHigh, Sync, UpdatedHigh, color=GREEN, style=StyleSwitch, width=2) label.new(math.floor(Sync - (Sync - HighIndex) / 2), UpdatedHigh, "BUY", color=color.new(color.red, 100), textcolor=color.green, style=label.style_label_down, size=size.small) if SELL line.new(LowIndex, UpdatedLow, Sync, UpdatedLow, color=RED, style=StyleSwitch, width=2) label.new(math.floor(Sync - (Sync - LowIndex) / 2), UpdatedLow, "SELL", color=color.new(color.red, 100), textcolor=color.red, style=label.style_label_up, size=size.small) // === Position Sizing === // returns float lots (full precision) — do NOT round here so orders use full precision getPositionSize(currentPrice) => float size = na if order_size_mode == "USD" // units = USD / price -> number of underlying units float units = order_size_value / currentPrice // lots = units / contract_size (units per lot) size := units / contract_size else size := order_size_value size // === Entry Logic === if phActive and enable_long_strategy float currentPrice = UpdatedHigh entryQty := getPositionSize(currentPrice) // full precision for actual order qty strategy.entry('Long', strategy.long, qty=entryQty, stop=UpdatedHigh) if plActive and enable_short_strategy float currentPrice = UpdatedLow entryQty := getPositionSize(currentPrice) strategy.entry('Short', strategy.short, qty=entryQty, stop=UpdatedLow) // === SL/TP Exit Setup === if strategy.position_size > 0 float entryPrice = strategy.position_avg_price longTpPrice := entryPrice * (1 + tp_perc / 100) longSlPrice := entryPrice * (1 - sl_perc / 100) strategy.exit("Exit Long", from_entry="Long", limit=longTpPrice, stop=longSlPrice) if strategy.position_size < 0 float entryPrice = strategy.position_avg_price shortTpPrice := entryPrice * (1 - tp_perc / 100) shortSlPrice := entryPrice * (1 + sl_perc / 100) strategy.exit("Exit Short", from_entry="Short", limit=shortTpPrice, stop=shortSlPrice) // === Draw Entry/TP/SL horizontal lines & labels (display rounded) === if strategy.position_size != 0 float entryPrice = strategy.position_avg_price bool isLong = strategy.position_size > 0 float tp = isLong ? longTpPrice : shortTpPrice float sl = isLong ? longSlPrice : shortSlPrice color entryCol = isLong ? GREEN : RED color tpCol = GREEN color slCol = RED int offsetBars = 5 if na(entryLine) entryLine := line.new(bar_index, entryPrice, bar_index + offsetBars, entryPrice, color=entryCol, style=line.style_solid, width=2) else line.set_xy1(entryLine, bar_index, entryPrice) line.set_xy2(entryLine, bar_index + offsetBars, entryPrice) line.set_color(entryLine, entryCol) // display price and lots in the label (lots from strategy.position_size so actual executed size is shown) float displayLots = math.abs(strategy.position_size) string displayLotsStr = format2(displayLots) string entryTxt = (isLong ? "LONG ENTRY: " : "SHORT ENTRY: ") + str.tostring(entryPrice, "0.00") + " / " + displayLotsStr if na(entryLabel) entryLabel := label.new(bar_index + offsetBars, entryPrice, entryTxt, style=label.style_label_left, textcolor=color.black, color=color.new(entryCol, labelTransparency), size=size.normal) else label.set_x(entryLabel, bar_index + offsetBars) label.set_y(entryLabel, entryPrice) label.set_text(entryLabel, entryTxt) label.set_color(entryLabel, color.new(entryCol, labelTransparency)) if na(tpLine) tpLine := line.new(bar_index, tp, bar_index + offsetBars, tp, color=tpCol, style=line.style_solid, width=2) else line.set_xy1(tpLine, bar_index, tp) line.set_xy2(tpLine, bar_index + offsetBars, tp) line.set_color(tpLine, tpCol) string tpTxt = 'TP: ' + str.tostring(tp, "0.00") if na(tpLabel) tpLabel := label.new(bar_index + offsetBars, tp, tpTxt, style=label.style_label_left, textcolor=color.black, color=color.new(tpCol, labelTransparency), size=size.normal) else label.set_x(tpLabel, bar_index + offsetBars) label.set_y(tpLabel, tp) label.set_text(tpLabel, tpTxt) label.set_color(tpLabel, color.new(tpCol, labelTransparency)) if na(slLine) slLine := line.new(bar_index, sl, bar_index + offsetBars, sl, color=slCol, style=line.style_solid, width=2) else line.set_xy1(slLine, bar_index, sl) line.set_xy2(slLine, bar_index + offsetBars, sl) line.set_color(slLine, slCol) string slTxt = 'SL: ' + str.tostring(sl, "0.00") if na(slLabel) slLabel := label.new(bar_index + offsetBars, sl, slTxt, style=label.style_label_left, textcolor=color.black, color=color.new(slCol, labelTransparency), size=size.normal) else label.set_x(slLabel, bar_index + offsetBars) label.set_y(slLabel, sl) label.set_text(slLabel, slTxt) label.set_color(slLabel, color.new(slCol, labelTransparency)) else if not na(entryLine) line.delete(entryLine), entryLine := na if not na(tpLine) line.delete(tpLine), tpLine := na if not na(slLine) line.delete(slLine), slLine := na if not na(entryLabel) label.delete(entryLabel), entryLabel := na if not na(tpLabel) label.delete(tpLabel), tpLabel := na if not na(slLabel) label.delete(slLabel), slLabel := na // === ENTRY ALERT with trade_id === var int lastEntryTradeBar = na if strategy.opentrades > 0 int openTrade = strategy.opentrades - 1 int tradeID = strategy.opentrades.entry_bar_index(openTrade) if na(lastEntryTradeBar) or tradeID != lastEntryTradeBar float entryPrice = strategy.position_avg_price float tradeVolume = math.abs(strategy.opentrades.size(openTrade)) // lots (full precision) string action = strategy.position_size > 0 ? "buy" : "sell" // use display rounded string (two decimals, leading zero) string tradeVolStr = format2(tradeVolume) string jsonEntry = '{"symbol":"' + syminfo.ticker + '","action":"' + action + '","order_type":"market","volume":' + tradeVolStr + ',"trade_id":"' + str.tostring(tradeID) + '","comment":"' + action + ' TV SMC"}' alert(jsonEntry, alert.freq_once_per_bar) lastEntryTradeBar := tradeID // === EXIT ALERT with SL/TP === var int lastClosedTradeID = na if strategy.closedtrades > 0 int closedTrade = strategy.closedtrades - 1 int closedTradeID = strategy.closedtrades.entry_bar_index(closedTrade) if na(lastClosedTradeID) or closedTradeID != lastClosedTradeID float entryPrice = strategy.closedtrades.entry_price(closedTrade) float exitPrice = strategy.closedtrades.exit_price(closedTrade) float tradeVolume = math.abs(strategy.closedtrades.size(closedTrade)) bool wasLong = strategy.closedtrades.size(closedTrade) > 0 float expectedTP = wasLong ? entryPrice * (1 + tp_perc / 100) : entryPrice * (1 - tp_perc / 100) float expectedSL = wasLong ? entryPrice * (1 - sl_perc / 100) : entryPrice * (1 + sl_perc / 100) float tolerance = syminfo.mintick * 10 bool isTPHit = wasLong ? exitPrice >= expectedTP - tolerance : exitPrice <= expectedTP + tolerance bool isSLHit = wasLong ? exitPrice <= expectedSL + tolerance : exitPrice >= expectedSL - tolerance if isTPHit or isSLHit string reason = isTPHit ? "TP" : "SL" string posType = wasLong ? "long" : "short" string tradeID = str.tostring(closedTradeID) string tradeVolStr = format2(tradeVolume) string jsonExit = '{"symbol":"' + syminfo.ticker + '","action":"close","order_type":"market","position_type":"' + posType + '","volume":' + tradeVolStr + ',"trade_id":"' + tradeID + '", "comment":"' + reason + ' TV SMC"}' alert(jsonExit, alert.freq_once_per_bar) lastClosedTradeID := closedTradeID // === Info Table === var table infoTable = table.new(position.top_right, 5, 2, border_width=1, frame_color=color.gray, border_color=color.gray) if barstate.isfirst table.cell(infoTable, 0, 0, "Entry", text_color=color.white, bgcolor=color.rgb(40,40,40)) table.cell(infoTable, 1, 0, "TP", text_color=color.white, bgcolor=color.rgb(40,40,40)) table.cell(infoTable, 2, 0, "SL", text_color=color.white, bgcolor=color.rgb(40,40,40)) table.cell(infoTable, 3, 0, "Active PH", text_color=color.white, bgcolor=color.rgb(40,40,40)) table.cell(infoTable, 4, 0, "Active PL", text_color=color.white, bgcolor=color.rgb(40,40,40)) var string entryStr = "NA" var string tpStr = "NA" var string slStr = "NA" var string phStr = "NA" var string plStr = "NA" if strategy.position_size != 0 float entryPrice = strategy.position_avg_price // show price and actual executed lots in the Entry cell float executedLots = math.abs(strategy.position_size) entryStr := str.tostring(entryPrice, "0.00") + " / " + format2(executedLots) tpStr := strategy.position_size > 0 ? str.tostring(longTpPrice, "0.00") : str.tostring(shortTpPrice, "0.00") slStr := strategy.position_size > 0 ? str.tostring(longSlPrice, "0.00") : str.tostring(shortSlPrice, "0.00") else entryStr := "Flat" tpStr := "NA" slStr := "NA" phStr := phActive ? format2(UpdatedHigh) : "NA" plStr := plActive ? format2(UpdatedLow) : "NA" table.cell(infoTable, 0, 1, entryStr, text_color=color.black, bgcolor=color.new(color.black, 80)) table.cell(infoTable, 1, 1, tpStr, text_color=color.blue, bgcolor=color.new(color.black, 80)) table.cell(infoTable, 2, 1, slStr, text_color=color.red, bgcolor=color.new(color.black, 80)) table.cell(infoTable, 3, 1, phStr, text_color=color.blue, bgcolor=color.new(color.black, 80)) table.cell(infoTable, 4, 1, plStr, text_color=color.red, bgcolor=color.new(color.black, 80)) 0