Pine Script Strategies and Indicators
If a strategy or an indicator runs on TradingView, you can paste it into CrossTrade and run it in NinjaTrader 8. CrossTrade converts the Pine source into a script the CrossTrade add-on compiles and runs, with the same inputs, the same plots, and for a strategy the same entries, exits and order logic. Pine versions 1 through 6 are supported. A script that starts with strategy( runs as a strategy and places its own orders; one that starts with indicator( or study( runs as an indicator (see Indicators).
Conversion is deterministic. The same script always converts the same way, and nothing is guessed, summarised or rewritten by AI.
Paste and convert
Open Strategies in the sidebar and press New strategy. Fill in four fields, paste the script, and press Save & convert.
| Field | What it means |
|---|---|
| Name | Any name you like. It is how the strategy appears in My strategies |
| Instrument | The market it trades, from the list below |
| Account | A strategy only: the NinjaTrader account it places orders on. A Sim account is picked for you when you have one. An indicator places no orders and has no account |
| Bar interval | The chart interval it runs on. Use the interval of the TradingView chart you tested it on |
When the script converts, the page tells you what came across, how many contracts each entry places, and whether NinjaTrader is ready for you to start it. Your script is saved either way, so you can come back to it.
Pasting from a chat, a blog or a code viewer
A copy from somewhere other than TradingView's Pine Editor often brings extra text with it. CrossTrade repairs the common damage before it saves and tells you what it changed, for example "We tidied your paste: removed the Markdown code fence (```) around the script." It removes a Markdown code fence and the text around it, line numbers copied from a code viewer, and invisible characters; it turns curly quotes and HTML entities such as < back into code; and it keeps one copy of a script pasted twice. Text inside strings and comments is never changed, and a script copied straight from TradingView is saved exactly as you pasted it.
On a TradingView script page, long code is folded under an Expand button. Copying the page without pressing it copies only the first part of the script, and the conversion says so: press Expand (or open the script in the Pine Editor), then copy all of it.
If a script has no //@version line, it is read as Pine v1, the way TradingView reads it. A script written for a newer Pine then fails on its newer features, and the message says so: put the version line it was written for (for example //@version=6) first.
Instruments
| Root | Market | Root | Market |
|---|---|---|---|
| ES | E-mini S&P 500 | MES | Micro S&P 500 |
| NQ | E-mini Nasdaq 100 | MNQ | Micro Nasdaq |
| YM | E-mini Dow | MYM | Micro Dow |
| RTY | Russell 2000 | M2K | Micro Russell 2000 |
| CL | Crude Oil | MCL | Micro Crude |
| GC | Gold | MGC | Micro Gold |
| SI | Silver | ZB | 30-Year Bond |
| 6E | Euro FX |
You pick the root. When the strategy starts, CrossTrade resolves it to the front-month contract in NinjaTrader, for example MES 12-26, and the strategy trades that contract for the whole run.
Bar intervals
1m, 5m, 15m, 30m, 1h, 4h, 1D and 1W. Intraday and daily intervals work best. Monthly intervals are not offered, because NinjaTrader rarely has enough monthly history to warm a strategy up, and even on weekly bars it often has too little (see Limitations).
Inputs
Every input.* in the script appears under Settings > Inputs with its TradingView label, its default, and its limits (minval, maxval, options). Press Edit inputs, change the values and press Save inputs.
CrossTrade writes your new values into the Pine itself as the inputs' defaults, the same way the Pine Editor would, and converts the script again. Your script and what runs never drift apart: the Pine Script tab always shows exactly what the strategy runs. A value the input cannot take is refused with its limits, for example "Fast length must be from 1 to 50."
An input whose default is worked out by the script (input.int(math.max(2, len), ...)) is shown but cannot be changed there. Change it in the Pine.
Order size
Settings > Order size shows how many contracts each entry places. It is TradingView's Order size setting, stored as default_qty_value in the script's strategy() line, and you can change it from 1 to 999 contracts. Like inputs, the new size is written into the Pine and the script converts again.
Two cases are different. If the script sizes its own orders, for example strategy.entry("L", strategy.long, qty=2), that quantity wins for those orders, as on TradingView. If the script sizes by strategy.percent_of_equity or strategy.cash, the size comes from the strategy's own simulated equity (its initial_capital plus its results), not from your account balance, and there is no fixed size to set. A percent-of-equity size leaves room for the script's commission, as TradingView does.
No entry is bigger than 999 contracts. Scripts written for forex or crypto often set sizes in units, such as default_qty_value=100000 for one forex lot. On a futures account that would be 100,000 contracts, so CrossTrade does not start a strategy whose order size is above 999 (Settings > Order size says so), and a running strategy that works out a bigger entry, from its own qty= or its sizing, stops before placing it. Set the size to the number of contracts you mean.
Libraries
TradingView's own libraries are built in. A script that imports one of TradingView's open-source libraries (ta, Strategy, ZigZag, TechnicalRating, RelativeValue, RiskMetrics, ValueAtTime or Color), for example import TradingView/ta/7 as tvta, converts as it is in any published version: there is nothing to paste. Its Request and LibraryCOT libraries are built in too, but they read FRED, FINRA, open interest and COT data that NinjaTrader does not have, so a script that uses them stops at that line. Each import runs exactly the version the script names, with that version's own Pine rules, including a Pine v5 version inside a v6 script, as on TradingView. A script that writes import TradingView/ta/5 as ta keeps the built-in ta.ema and the other functions the library does not define.
Community libraries are built in too. CrossTrade bundles the published open-source libraries scripts commonly import, about 380 libraries in every published version, including the popular ones such as jdehorty/KernelFunctions, jdehorty/MLExtensions, the PineCoders libraries, HeWhoMustNotBeNamed/ta and the loxx libraries. Each import runs exactly the version it names. A library that is private or invite-only on TradingView cannot be bundled; paste its source as below.
Other libraries need their source. A library that is not built in, usually one that is private or invite-only on TradingView, needs its source. When you paste a script that imports one, a Pine libraries this script imports section appears under the editor: open the library on TradingView, copy its source, paste it there with Add library, and press Save & convert. CrossTrade keeps that exact copy with your strategy, so a later change to the library on TradingView never changes your strategy behind your back.
Indicators
An indicator runs in NinjaTrader the way it runs on a TradingView chart. It updates with every price change, draws its plots and shapes on the chart on its Overview tab, and places no orders itself. What it does with its signals is up to its alerts.
Alerts, one per condition. Under Settings > Alerts, each alert listens to one of the indicator's alertcondition() calls, by its title, or to any alert, and does one thing:
| Action | What it does |
|---|---|
| Notify me | Email, Telegram, Discord, mobile push or your My Account webhook |
| Call a webhook | Sends the alert to a URL of your own. The body defaults to {{message}}, the condition's message or the alert() text |
| Place a CrossTrade order | Sends a CrossTrade command, the same text you would put in a TradingView alert, for example COMMAND=PLACE;ACCOUNT=Sim101;INSTRUMENT=MES 12-26;ACTION=BUY;QTY=1;ORDER_TYPE=MARKET;TIF=DAY;. Leave it as {{message}} when the condition's message already holds the command. Account rules, rate limits and the kill switch apply as they do to your webhooks |
This is the TradingView alert you would create for each condition, with no TradingView in between. Nothing is sent until you add an alert. Notify me and Call a webhook are part of the Pro plan; Place a CrossTrade order works on every paid plan. Placeholders in an alertcondition() message ({{ticker}}, {{close}}, {{interval}}, {{time}} and the others TradingView documents) are filled in when the alert triggers.
When alerts trigger. An alertcondition() triggers once per bar close when its condition is true, like TradingView's Once Per Bar Close setting. An alert() call triggers as often as the script tells it to with its freq argument.
Alerts
TradingView strategies often carry alerts: alert() calls, and alert_message on strategy.entry, strategy.exit, strategy.order or strategy.close for the message each order fill sends. They convert with the script, and nothing is sent until you choose where they go.
When your script has alerts, the page says so after it converts, with a Choose where alerts go button. The same choice is under Settings > Alerts for every strategy, so a script without alerts can still tell you when it opens or closes a trade.
| Destination | What it sends |
|---|---|
| Notify me | A notification by email, Telegram, Discord, mobile push or your My Account webhook |
| Call a webhook | A request to a URL of your own. The body defaults to {{message}}, which sends what a TradingView alert would: the alert() text for a script alert, and the order's alert_message (or the script's //@strategy_alert_message text) for an order fill. TradingView's placeholders such as {{ticker}}, {{close}} and {{strategy.order.action}} work in the body too |
For each destination you pick which events reach it: script alerts (your alert() calls), order fills (each carries its alert_message), trades opened, trades closed, problems, and start-up notices. Changes apply from the next start.
Notify me and Call a webhook are part of the Pro plan. On every plan, each alert is also recorded in your alert history. If you set them up on a trial or on Pro and your plan no longer includes them, they stay saved but paused, and the strategies page says so until you upgrade or remove them.
The strategy places its own orders in NinjaTrader. If your alert_message strings are CrossTrade order commands from a TradingView webhook setup (ACTION=BUY;QTY=1;...), you do not need them here, and they are never sent as orders: a CrossTrade webhook URL is refused as a destination, because sending one would trade twice.
When a script cannot convert
CrossTrade never converts part of a script. If anything in it cannot run, nothing runs, and the page lists the reasons line by line, for example "Line 5: request.economic reads economic indicators (GDP, rates, inflation), which NinjaTrader does not provide. Remove the call, or replace its value with an input you set by hand." Edit the line in the editor and press Save & convert again.
The common causes are listed in Limitations. If a script runs on TradingView and you need it here, send it to support.
What matches TradingView
CrossTrade follows TradingView's own rules wherever NinjaTrader allows it.
Warm-up on history. When a strategy starts, it first runs over the most recent closed bars NinjaTrader has (400 by default, more when the script reads further back or declares a larger max_bars_back; see Limitations), exactly as a TradingView strategy runs over a chart's history. Orders on those bars are filled by a model of TradingView's broker emulator: the same open, high, low and close path through each bar, the same stop and limit fill rules, and the pyramiding, process_orders_on_close, commission_*, slippage and margin settings in your strategy() line. Indicators are fully warmed up before the first live bar.
From history to live. A position the strategy holds at the end of history is closed on paper at the last historical price, so a new run starts flat and never inherits a trade it did not place. The orders that were waiting on that position (its stop and target, and a pending entry that would have reversed it) go with it. When history ends flat, an entry still pending carries over and goes live on the first live price, as it would on TradingView's next bar. So if the last closed bar signalled a market entry, the strategy enters within seconds of Start, at the price then.
Live orders are real orders. Entries, exits and reversals go to your broker through NinjaTrader, and results come from real executions. A strategy.exit with a stop and a target becomes a pair of real orders linked one-cancels-other at the broker, so the position stays protected even if NinjaTrader loses its connection to CrossTrade. A trailing stop is moved by the strategy as the price moves.
A stop the market has already passed. TradingView fills a stop at once when the market is already beyond it. NinjaTrader refuses such an order, so CrossTrade sends it at market instead (a stop-limit goes in as its limit order), and the run shows a one-time notice.
Reversals. A stop or limit entry against an open position works beside that position's stop and target, as on TradingView: whichever price the market reaches first fills first.
Intrabar strategies. calc_on_every_tick=true and calc_on_order_fills=true are honoured on live bars.
Where a NinjaTrader run can differ
A strategy can only match TradingView as closely as its data does. NinjaTrader builds bars from your data feed, which is not TradingView's, so a price can differ by a tick and a bar can open or close slightly differently. Sessions follow the contract's trading hours in NinjaTrader. Live fills come from your broker and include real slippage, where TradingView's backtest uses its own fill rules. Settings you changed in TradingView's strategy Properties dialog rather than in the code are not part of the script and do not come across. Limitations lists every difference to look out for.
Changing a strategy
Edits apply at the next start. A running strategy keeps the script, inputs, order size, account, instrument and bar interval it started with, and the strategy's page says when a newer saved version is waiting. Stop it and start it again to pick up the change. A changed bar interval converts the Pine again. When CrossTrade updates its converter, each strategy converts again from its saved Pine the next time it starts (or resumes after NinjaTrader restarts), so it always runs the current version; if the new version cannot convert a script, Start says why and the Pine Script tab shows the reason.