Pine Script Boilerplate for CrossTrade
Copy the template below into the TradingView Pine editor. Replace the signal logic with your own (moving average cross, RSI, breakout — whatever). The webhook payload, position sizing, stop/target handling, and alert firing are already wired for CrossTrade. You just provide the edge.
The full template (Pine Script v6)
//@version=6
strategy(
title = "CrossTrade Strategy Template",
overlay = true,
initial_capital = 50000,
default_qty_type = strategy.fixed,
default_qty_value = 1,
commission_type = strategy.commission.cash_per_contract,
commission_value = 2.50,
calc_on_every_tick = false,
process_orders_on_close = true
)
// ==========================================================
// SECTION 1 — CrossTrade webhook configuration
// These inputs appear in the script's Settings dialog.
// ==========================================================
grpCT = "CrossTrade Webhook"
secretKey = input.string("YOUR-SECRET-KEY", "Secret key", group=grpCT)
account = input.string("Sim101", "NT account", group=grpCT)
instrument = input.string("ES 06-26", "NT instrument", group=grpCT)
tif = input.string("day", "Time in force", options=["day","gtc"], group=grpCT)
syncStrat = input.bool(true, "Sync NT with strategy", group=grpCT)
// ==========================================================
// SECTION 2 — Position-sizing inputs
// ==========================================================
grpRisk = "Risk"
riskPct = input.float(1.0, "Risk % per trade", minval=0.1, step=0.1, group=grpRisk)
pointValue = input.float(50, "Point value per contract", group=grpRisk, tooltip="ES=50, NQ=20, MES=5, MNQ=2, CL=1000 per $, etc.")
stopAtrMlt = input.float(1.5, "Stop = N × ATR", group=grpRisk)
atrLen = input.int(14, "ATR length", group=grpRisk)
// ==========================================================
// SECTION 3 — REPLACE THIS BLOCK WITH YOUR LOGIC
// Provide two boolean series: longSignal and shortSignal.
// ==========================================================
fastLen = input.int(9, "Fast EMA length", group="Signal")
slowLen = input.int(21, "Slow EMA length", group="Signal")
fastEma = ta.ema(close, fastLen)
slowEma = ta.ema(close, slowLen)
longSignal = ta.crossover(fastEma, slowEma)
shortSignal = ta.crossunder(fastEma, slowEma)
plot(fastEma, color=color.yellow, linewidth=2, title="Fast EMA")
plot(slowEma, color=color.blue, linewidth=2, title="Slow EMA")
// ==========================================================
// SECTION 4 — Stop/target sizing from ATR
// ==========================================================
atrVal = ta.atr(atrLen)
stopDist = stopAtrMlt * atrVal
// Compute contracts from risk budget
riskDollars = strategy.equity * (riskPct / 100.0)
perContract = stopDist * pointValue
qty = perContract > 0 ? math.max(1, math.floor(riskDollars / perContract)) : 1
// ==========================================================
// SECTION 5 — Entries and exits
// ==========================================================
if longSignal and strategy.position_size <= 0
if strategy.position_size < 0
strategy.close("Short")
strategy.entry("Long", strategy.long, qty=qty)
strategy.exit("Long Exit", "Long", stop=close - stopDist)
if shortSignal and strategy.position_size >= 0
if strategy.position_size > 0
strategy.close("Long")
strategy.entry("Short", strategy.short, qty=qty)
strategy.exit("Short Exit", "Short", stop=close + stopDist)
// ==========================================================
// SECTION 6 — CrossTrade webhook payload
// One alert() call formatted for CrossTrade. Pair with an alert
// configured as "Any alert() function call" with the webhook URL
// set to your CrossTrade endpoint.
// ==========================================================
payload =
"key=" + secretKey +
";command=place" +
";account=" + account +
";instrument=" + instrument +
";action={{strategy.order.action}}" +
";qty={{strategy.order.contracts}}" +
";order_type=market" +
";tif=" + tif +
(syncStrat ?
";sync_strategy=true" +
";market_position={{strategy.market_position}}" +
";prev_market_position={{strategy.prev_market_position}}" +
";out_of_sync=flatten"
: "")
if longSignal or shortSignal
alert(payload, alert.freq_once_per_bar_close)
How to use
- Copy the template into the TradingView Pine editor
- Replace Section 3 with your own signal logic — give the script two booleans named
longSignalandshortSignal. Everything else stays the same. - Add to chart and verify signals in the Strategy Tester panel
- Configure the CrossTrade webhook inputs — secret key, account, instrument
- Create an alert:
- Condition: your strategy
- "Any alert() function call"
- Frequency: "Once per bar close"
- Webhook URL: your CrossTrade endpoint
- Test in sim before going live
What the template gives you
- Position sizing based on account equity and ATR-scaled stops (1% default)
- ATR-based stops that adapt to volatility
- Reversal handling — closes the opposite position before opening a new one
- Sync flags so NinjaTrader follows TradingView's strategy state
out_of_sync=flattenso NT defaults to flat if it ever disagrees with TradingView- A single
alert()call — simpler to wire than multiple alerts
Variations
Bracket with profit target:
Add a target alongside the stop in strategy.exit:
targetMult = input.float(2.0, "Target = N × stop distance")
// ...
strategy.exit("Long Exit", "Long", stop=close - stopDist, limit=close + targetMult * stopDist)
Time-filter (RTH only):
Wrap entry conditions in a session check:
inRTH = (hour * 100 + minute) >= 930 and (hour * 100 + minute) < 1600
if longSignal and inRTH and strategy.position_size <= 0
// ... entry logic
End-of-session flatten:
if hour == 15 and minute >= 55
strategy.close_all("EOD flatten")
Trailing stop:
trailAtrMult = input.float(2.0, "Trail = N × ATR")
if strategy.position_size > 0
trailStop = close - trailAtrMult * atrVal
strategy.exit("Trail", "Long", stop=trailStop)
Testing checklist before going live
- Backtest shows acceptable profit factor (>1.3) with commissions included
- Drawdown is within your account's tolerance
- Strategy fires fewer than ~50 alerts/month (else you'll burn through TradingView plan limits)
- CrossTrade Alert History shows successful payload parsing on sim for multiple sessions
- NinjaTrader sim account shows matching fills to TradingView's strategy tester
- 2FA is enabled on your TradingView account (required for webhooks)
- Your broker's day-margin cutoff is respected by the strategy's flatten logic
When to deviate from the template
- Scalping strategies (sub-minute) — disable
process_orders_on_closeand consider intra-bar signals. Use caution: intra-bar strategies often backtest optimistically. - Pyramiding strategies — set
pyramidingparameter on thestrategy()declaration. Update the entry logic to stack positions. - Portfolio strategies — TradingView's one-strategy-per-chart limit means you'll want separate charts per strategy or a more advanced setup.
Frequently Asked Questions
Can I just copy-paste this Pine Script and run it?
Yes — after updating the 'YOUR-SECRET-KEY' placeholder with your actual CrossTrade secret, configuring the account and instrument inputs, and creating an alert pointed at your CrossTrade webhook URL. The default 9/21 EMA logic is functional but not particularly profitable on its own — replace Section 3 with your own strategy.
Why does the template close opposite positions before entering?
To handle reversals cleanly. If you're long and a short signal fires, the template closes the long first, then opens the short. Without this, strategy.entry('Short') would flip the position but the CrossTrade sync_strategy logic handles the NT-side transition smoothly.
What's 'out_of_sync=flatten' doing?
If CrossTrade detects that NinjaTrader's actual position doesn't match what the TradingView strategy thinks it is (e.g., a manual trade was placed, or an alert was missed), CrossTrade will flatten the NT position rather than guess. It's a safety default.
Do I need to change the template for MNQ vs ES?
Only the 'pointValue' input (ES=50, NQ=20, MES=5, MNQ=2) and the 'instrument' input. The logic, stops, and position sizing math work identically across instruments.