If you searched for a NinjaTrader 8 Python API, here is the short version: there is not one. NinjaTrader 8 automates in C# through NinjaScript, its in-platform scripting environment, and it ships no official Python API or SDK. That is not a gap you close with the right import. It is a design fact, and the honest routes from Python to a NinjaTrader account all go around it rather than through it. This is a map of those routes, what each one costs you, and where a local Python daemon fits if you want your logic in Python without handing it an unchecked line to the platform.
Why NinjaScript, and why not Python
NinjaTrader’s native automation path is NinjaScript: strategies, indicators, and AddOns written in C#, edited in the platform’s own editor, then compiled and hosted inside NinjaTrader against live data. NinjaTrader frames automation as either NinjaScript or an outside program via its Automated Trading Interface, and there is no Python path in either (NinjaTrader ATI help, retrieved 2026-07-10). NinjaScript itself is C# on .NET, which the PitBridge AddOn targets directly (net48, the NinjaTrader.Cbi account API). If your strategy can be expressed as a compiled C# strategy that runs in the platform, that is the supported, lowest-friction path, and you should probably take it.
The reason people keep searching for a Python API is that their logic already lives in Python: a model, a research stack, a data pipeline, an agent. Rewriting that in C# to live inside NinjaTrader is a real cost, and often the wrong one. So the practical question is not “where is the Python API”, it is “what is the least bad bridge from my Python to my NinjaTrader account”.
The ATI: NinjaTrader’s own external door
NinjaTrader does expose an official way in from outside the platform, the Automated Trading Interface. Its own help guide states it plainly: NinjaTrader provides methods for automated trading through NinjaScript or from an outside source via the ATI (NinjaTrader ATI help, retrieved 2026-07-10). The ATI comes in two flavors, and both are reachable from Python with some effort.
The file interface reads Order Instruction Files. You write a plain text file into your NinjaTrader documents folder under an incoming directory, named oif*.txt, with semicolon-delimited fields, and NinjaTrader processes it the instant it lands on disk (OIF reference, retrieved 2026-07-10). Any language that can write a file can drive it, Python included. It is also as blunt as it sounds: one file per instruction, local only, and easy to get subtly wrong. One sharp edge alone is that the filename has to start with oif or the file is silently ignored.
The DLL interface is NTDirect.dll, a .NET managed assembly shipped as NinjaTrader.Client.dll in the platform’s bin directory (DLL interface, retrieved 2026-07-10). Because it is managed .NET rather than a C ABI, calling it from Python means bridging the CLR (via pythonnet or a small C# shim), not a clean ctypes load. Either ATI route runs only on the Windows box where NinjaTrader runs, speaks order instructions rather than a rich account API, and leaves every risk decision to whatever wrote the file or called the function.
Third-party bridges: cloud relay vs local daemon
Because the native routes are C# or file-based, a market of bridges exists to give Python a nicer door. They come in two shapes, and the difference is where your orders travel.
A cloud REST bridge exposes a hosted REST and WebSocket API in front of your NinjaTrader. You write Python anywhere, call the vendor’s endpoint, and a small add-on inside your NinjaTrader executes. CrossTrade is the established one and publishes a Python trading-bot walkthrough for exactly this. The tradeoff is structural: the vendor’s cloud sits in the path of every order (crosstrade.io/mcp-trading, verified 2026-07-09). For many people the managed convenience is worth it. If it is not, the alternative is to keep the whole path local.
A local-first daemon runs on your own machine and exposes the same kind of API there. Your Python talks to localhost, and nothing about the order route touches a vendor server. This is where PitBridge sits, and the rest of this walks how a Python program drives it.
| Property | ninjascript (c#) | ati (oif / dll) | cloud rest bridge | local daemon |
|---|---|---|---|---|
| language you write | C# inside NinjaTrader | any language writes OIF; .NET for the DLL | any language over REST | any language over REST or MCP |
| where it runs | inside the platform | the Windows NT8 box | your code anywhere, cloud relays | your machine, localhost |
| order path | inside the platform | local file or DLL into NT8 | through the vendor cloud | local, daemon to AddOn |
| risk checks on the order | your strategy code | none built in | split across vendor and add-on | deterministic guardrail engine before NT8 |
| official or third party | official | official | third party | third party, open core |
ninjascript (c#)
- language you write
- C# inside NinjaTrader
- where it runs
- inside the platform
- order path
- inside the platform
- risk checks on the order
- your strategy code
- official or third party
- official
ati (oif / dll)
- language you write
- any language writes OIF; .NET for the DLL
- where it runs
- the Windows NT8 box
- order path
- local file or DLL into NT8
- risk checks on the order
- none built in
- official or third party
- official
cloud rest bridge
- language you write
- any language over REST
- where it runs
- your code anywhere, cloud relays
- order path
- through the vendor cloud
- risk checks on the order
- split across vendor and add-on
- official or third party
- third party
local daemon
- language you write
- any language over REST or MCP
- where it runs
- your machine, localhost
- order path
- local, daemon to AddOn
- risk checks on the order
- deterministic guardrail engine before NT8
- official or third party
- third party, open core
Where a local Python daemon fits
PitBridge is a bridge of the last kind, built Python-first. The daemon is Python (it runs on macOS, Linux, or Windows), and the piece that touches NinjaTrader is a thin C# AddOn that connects out to the daemon and places orders through the official NinjaTrader.Cbi account API. Your Python never speaks to NinjaTrader directly; it speaks to the daemon on localhost, and the daemon speaks to the AddOn. In between sits a deterministic guardrail engine that checks every order before it can leave your machine.
PitBridge is published on PyPI, so uvx resolves and runs it with no separate install step. Start the daemon and it exposes three local surfaces at once.
$ uvx pitbridge run # daemon up on 127.0.0.1:8873 # REST at /v1/*, WebSocket at /v1/ws, MCP over HTTP at /mcp # a Python client can POST orders to: # http://127.0.0.1:8873/v1/place_order # an MCP-over-HTTP client points at: # http://127.0.0.1:8873/mcp
Streamable HTTP MCP has been served next to stdio and REST since 0.2.0. On a localhost bind the agent token is optional; a non-localhost bind requires a token.
For a Python script, the REST route is the direct one. Post a JSON order to /v1/place_order and it travels the same pipeline as an agent’s MCP tool call: schema check, permission check, guardrails, then submit. The response is a structured result, not an exception, so your code reads the outcome and moves on.
$ curl -s http://127.0.0.1:8873/v1/place_order \ -H 'content-type: application/json' \ -d '{"account":"sim","instrument":"MES 09-26","side":"BUY","qty":2}' # {"outcome":"SUBMITTED","order_id":"...","status":"FILLED"} # paper fill, guardrails passed # the same call with an oversized qty comes back refused, not executed: $ curl -s http://127.0.0.1:8873/v1/place_order \ -H 'content-type: application/json' \ -d '{"account":"sim","instrument":"MES 09-26","side":"BUY","qty":10}' # {"outcome":"BLOCKED","reason_code":"MAX_CONTRACTS_PER_ORDER"}
Real request fields (account, instrument, side, qty) and the real response keys (outcome, reason_code). Fills are synthetic simulation fills, not live results. The block is a value your code can branch on, not a thrown error.
Two properties are worth being explicit about. First, the check is deterministic and runs out of process: the same order and config always produce the same decision, and there is no model or heuristic in the adjudication. Second, the write surface is small and fixed. Over REST or MCP the caller can place, cancel, close, and flatten, and read account and guardrail state, and that is all. There is no route to weaken a limit, release the kill switch, or arm live trading. Those live on an operator-only CLI, so a bug or a compromised script cannot raise its own ceiling. If you want the shape of the full tool surface, what a trading MCP server does lays out the nine tools.
If the thing on the Python side is an agent
Plenty of people asking for a Python API are really wiring up an AI agent, not a fixed script. The bridge is the same, and so is the guardrail engine, but the failure modes are different: a language model produces a distribution of outputs, and the tail of that distribution includes the wrong size or the wrong side. That is a separate discussion, covered in how to connect an AI agent to NinjaTrader 8, which walks the agent path and the risk it carries. The point that carries over is that the enforcement has to live below the caller, in code it cannot rewrite, whether the caller is your script or a model.
Honest status: paper by default, live gated
Everything above runs against a paper or simulation account. In the open core mode = "live" is intentionally out of reach: arm-live refuses, because live execution ships separately as a paid, closed component, and there is no REST route or agent tool to change that. Live execution has been in production on a funded futures account since 30 July 2026, behind an operator-run arm step. The upside for a developer is that you can exercise the entire pipeline, every reason code, on a Mac with a fake AddOn before any real money is in scope.
So: no NinjaTrader 8 Python API exists, and probably will not, because NinjaScript is the platform’s C# story. What exists instead is a set of bridges. The ATI is official but blunt and Windows-local; a cloud bridge is convenient but puts a vendor in the order path; a local-first daemon keeps the path on your machine and puts a deterministic check in front of every order. The NinjaTrader 8 MCP bridge is the front door, the quickstart has the uvx pitbridge setup per runtime, and the guardrails page lists exactly what the engine refuses. If a local, guardrailed bridge from your Python to NinjaTrader is what you want, tell us your platform on the waitlist. PitBridge is trading infrastructure, not financial advice: it enforces the limits you configure and does not promise any trading outcome. Futures trading carries a substantial risk of loss.