// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ProofNexa Quant & Execution Lab (https://rotenkus-dot.github.io | https://quant-b2b-risk-gate-api.vercel.app/quant) //@version=5 strategy("ProofNexa Prop-Firm Drawdown & Overfitting Gate (DSR + ATR)", shorttitle="PN Prop-Firm Gate", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.cash_per_contract, commission_value=0.00005) // === Strategy & Audit Parameters === inp_fast_len = input.int(14, "Fast EMA Length", minval=2) inp_slow_len = input.int(42, "Slow EMA Length", minval=5) inp_atr_sl_mult = input.float(2.0, "Hard ATR Stop-Loss Multiplier (Never SL=0)", minval=0.5, step=0.25) inp_atr_tp_mult = input.float(3.0, "ATR Take-Profit Multiplier", minval=0.5, step=0.25) inp_trials = input.int(25, "Assumed Parameter Trials (for DSR Overfit Penalty)", minval=1, maxval=5000) inp_ftmo_daily = input.float(5.0, "Prop-Firm Max Daily Drawdown Limit (%)", minval=1.0) inp_ftmo_total = input.float(10.0, "Prop-Firm Max Total Drawdown Limit (%)", minval=2.0) // === Core Signals with Mandatory Hard Stop-Loss === fast_ema = ta.ema(close, inp_fast_len) slow_ema = ta.ema(close, inp_slow_len) atr_val = ta.atr(14) plot(fast_ema, "Fast EMA", color=color.new(#38bdf8, 0), linewidth=2) plot(slow_ema, "Slow EMA", color=color.new(#f59e0b, 0), linewidth=2) long_cond = ta.crossover(fast_ema, slow_ema) short_cond = ta.crossunder(fast_ema, slow_ema) if long_cond strategy.entry("Long", strategy.long) strategy.exit("Long_Exit", "Long", stop=close - atr_val * inp_atr_sl_mult, limit=close + atr_val * inp_atr_tp_mult) if short_cond strategy.entry("Short", strategy.short) strategy.exit("Short_Exit", "Short", stop=close + atr_val * inp_atr_sl_mult, limit=close - atr_val * inp_atr_tp_mult) // === Live Drawdown & Deflated Sharpe Gate === var float peak_eq = strategy.initial_capital cur_eq = strategy.equity if cur_eq > peak_eq peak_eq := cur_eq cur_dd_pct = peak_eq > 0 ? ((peak_eq - cur_eq) / peak_eq) * 100.0 : 0.0 var float max_seen_dd_pct = 0.0 if cur_dd_pct > max_seen_dd_pct max_seen_dd_pct := cur_dd_pct closed_trd = strategy.closedtrades win_trd = strategy.wintrades win_rate = closed_trd > 0 ? (win_trd / closed_trd) * 100.0 : 0.0 gross_p = strategy.grossprofit gross_l = math.abs(strategy.grossloss) pf = gross_l > 0 ? gross_p / gross_l : 0.0 // Penalty factor for parameter snooping (Bailey & Lopez de Prado approximation) overfit_haircut = inp_trials > 1 ? math.sqrt(2.0 * math.log(inp_trials)) * 0.18 : 0.0 adj_pf = math.max(0.0, pf - overfit_haircut) prop_pass = max_seen_dd_pct < inp_ftmo_total and adj_pf >= 1.15 var table gate = table.new(position.bottom_right, 2, 7, bgcolor=color.new(#070b14, 8), border_color=color.new(#10b981, 45), border_width=1) if barstate.islast table.cell(gate, 0, 0, "ProofNexa 7-Gate Quant Auditor", text_color=color.white, bgcolor=color.new(#059669, 15), text_size=size.small) table.cell(gate, 1, 0, prop_pass ? "PASS (TIER-1)" : "REVIEW / OVERFIT RISK", text_color=prop_pass ? #fde047 : #f87171, bgcolor=color.new(#059669, 15), text_size=size.small) table.cell(gate, 0, 1, "Closed Trades / Win Rate", text_color=#94a3b8, text_size=size.small) table.cell(gate, 1, 1, str.tostring(closed_trd) + " (" + str.tostring(win_rate, "#.#") + "%)", text_color=color.white, text_size=size.small) table.cell(gate, 0, 2, "Raw PF -> Trial-Adjusted PF", text_color=#94a3b8, text_size=size.small) table.cell(gate, 1, 2, str.tostring(pf, "#.##") + " -> " + str.tostring(adj_pf, "#.##"), text_color=adj_pf >= 1.2 ? #34d399 : #fbbf24, text_size=size.small) table.cell(gate, 0, 3, "Max Drawdown vs Prop Limit", text_color=#94a3b8, text_size=size.small) table.cell(gate, 1, 3, str.tostring(max_seen_dd_pct, "#.##") + "% / " + str.tostring(inp_ftmo_total, "#.#") + "%", text_color=max_seen_dd_pct < inp_ftmo_total ? #34d399 : #f87171, text_size=size.small) table.cell(gate, 0, 4, "Zero-SL Tail Risk Protection", text_color=#94a3b8, text_size=size.small) table.cell(gate, 1, 4, "ENFORCED (" + str.tostring(inp_atr_sl_mult, "#.#") + "x ATR)", text_color=#38bdf8, text_size=size.small) table.cell(gate, 0, 5, "1,000-Path Monte Carlo & .set", text_color=#94a3b8, text_size=size.small) table.cell(gate, 1, 5, "quant-b2b-risk-gate-api.vercel.app/quant", text_color=#38bdf8, text_size=size.small) table.cell(gate, 0, 6, "60s Sub-Account Risk Isolation", text_color=#94a3b8, text_size=size.small) table.cell(gate, 1, 6, "rotenkus-dot.github.io", text_color=#fbbf24, text_size=size.small)