//@version=5 strategy("BTC Trend Breakout — Risk Managed", overlay = true, initial_capital = 10000, currency = currency.USD, pyramiding = 0, commission_type = strategy.commission.percent, commission_value = 0.10, slippage = 10, margin_long = 100, margin_short = 100, calc_on_every_tick = false, calc_on_order_fills = false, process_orders_on_close = false) // Intended for standard BTC/USD or BTC/USDT charts. // Position sizing assumes a linear instrument quoted in USD or USDT. // ── Inputs ──────────────────────────────────────────────────────────────── breakoutLength = input.int(20, "Breakout lookback", minval = 2) trendLength = input.int(200, "Trend EMA length", minval = 2) slopeLookback = input.int(10, "Trend slope lookback", minval = 1) exitLength = input.int(50, "Exit EMA length", minval = 2) atrLength = input.int(14, "ATR length", minval = 1) stopATR = input.float(2.5, "Stop distance: ATR multiple", minval = 0.5, step = 0.1) rewardRisk = input.float(3.0, "Profit target: reward/risk", minval = 0.5, step = 0.25) riskPercent = input.float(1.0, "Equity risk per trade (%)", minval = 0.1, maxval = 5.0, step = 0.1) allocationPct = input.float(95.0, "Maximum capital allocation (%)", minval = 1.0, maxval = 100.0, step = 1.0) // ── Indicators ──────────────────────────────────────────────────────────── trendEMA = ta.ema(close, trendLength) exitEMA = ta.ema(close, exitLength) atrValue = ta.atr(atrLength) // Exclude the current bar from the breakout level. breakoutLevel = ta.highest(high, breakoutLength)[1] ready = not na(trendEMA[slopeLookback]) and not na(breakoutLevel) and not na(atrValue) uptrend = close > trendEMA and trendEMA > trendEMA[slopeLookback] breakout = ta.crossover(close, breakoutLevel) // Store the initial trade's stop distance in ticks. var int tradeStopTicks = na var int tradeTargetTicks = na // ── Entry and position sizing ──────────────────────────────────────────── if barstate.isconfirmed and ready and strategy.position_size == 0 if uptrend and breakout and strategy.equity > 0 stopTicks = int(math.max(1.0, math.ceil(atrValue * stopATR / syminfo.mintick))) stopDistance = stopTicks * syminfo.mintick riskCash = strategy.equity * riskPercent / 100.0 riskQuantity = riskCash / (stopDistance * syminfo.pointvalue) capitalQuantity = (strategy.equity * allocationPct / 100.0) / (close * syminfo.pointvalue) quantity = math.min(riskQuantity, capitalQuantity) if quantity > 0 tradeStopTicks := stopTicks tradeTargetTicks := int(math.max(1.0, math.round(stopTicks * rewardRisk))) strategy.entry("Long", strategy.long, qty = quantity) // Relative tick distances anchor the bracket to the fill price. // Submit protection alongside the entry order. strategy.exit("Bracket", from_entry = "Long", loss = tradeStopTicks, profit = tradeTargetTicks) // Keep the original bracket active; ATR changes do not widen the stop. if strategy.position_size > 0 strategy.exit("Bracket", from_entry = "Long", loss = tradeStopTicks, profit = tradeTargetTicks) if barstate.isconfirmed and close < exitEMA strategy.close("Long", comment = "Trend exit") // ── Chart display ───────────────────────────────────────────────────────── stopPrice = strategy.position_size > 0 ? strategy.position_avg_price - tradeStopTicks * syminfo.mintick : na targetPrice = strategy.position_size > 0 ? strategy.position_avg_price + tradeTargetTicks * syminfo.mintick : na plot(trendEMA, "Trend EMA", color = color.orange, linewidth = 2) plot(exitEMA, "Exit EMA", color = color.blue) plot(breakoutLevel, "Previous breakout high", color = color.gray) plot(stopPrice, "Stop", color = color.red, style = plot.style_linebr) plot(targetPrice, "Target", color = color.green, style = plot.style_linebr)