Skip to main content

Pine Script Boilerplate for CrossTrade

TL;DR

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

  1. Copy the template into the TradingView Pine editor
  2. Replace Section 3 with your own signal logic — give the script two booleans named longSignal and shortSignal. Everything else stays the same.
  3. Add to chart and verify signals in the Strategy Tester panel
  4. Configure the CrossTrade webhook inputs — secret key, account, instrument
  5. Create an alert:
    • Condition: your strategy
    • "Any alert() function call"
    • Frequency: "Once per bar close"
    • Webhook URL: your CrossTrade endpoint
  6. 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=flatten so 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_close and consider intra-bar signals. Use caution: intra-bar strategies often backtest optimistically.
  • Pyramiding strategies — set pyramiding parameter on the strategy() 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.