PitBridge
Join the waitlist

NinjaTrader and AI agents

Is there a NinjaTrader 8 Python API?

There is no official NinjaTrader 8 Python API. The platform automates in C# through NinjaScript, and everything else is a bridge: the ATI file or DLL route, a third-party cloud REST relay, or a local daemon your Python code drives. This walks the real options, their tradeoffs, and where a local-first Python daemon that speaks REST and MCP fits.

On this page

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.

Propertyninjascript (c#)ati (oif / dll)cloud rest bridgelocal daemon
language you writeC# inside NinjaTraderany language writes OIF; .NET for the DLLany language over RESTany language over REST or MCP
where it runsinside the platformthe Windows NT8 boxyour code anywhere, cloud relaysyour machine, localhost
order pathinside the platformlocal file or DLL into NT8through the vendor cloudlocal, daemon to AddOn
risk checks on the orderyour strategy codenone built insplit across vendor and add-ondeterministic guardrail engine before NT8
official or third partyofficialofficialthird partythird 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
Four routes from code to a NinjaTrader account. NinjaScript is C# and native; the ATI is official but blunt and Windows-local; the two bridges differ on where the order path runs and what inspects the order.

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.

python client, shown as curl
$ 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.

Read the pillar: NinjaTrader 8 MCP bridge

Questions

Does NinjaTrader 8 have a Python API?

No. NinjaTrader 8 automates through NinjaScript, its in-platform C# environment, and ships no official Python API or SDK. To drive it from Python you go around the platform with a bridge: the built-in Automated Trading Interface (files or a .NET DLL), a third-party cloud REST relay, or a local daemon that exposes a localhost API your Python code calls.

Can I control NinjaTrader from Python?

Yes, indirectly. Python cannot run inside NinjaTrader, but it can drive it through a bridge. The simplest official route is writing Order Instruction Files that the ATI reads. A richer route is a bridge that gives you REST or MCP. With PitBridge the daemon is Python, so your Python script POSTs an order to http://127.0.0.1:8873/v1/place_order on localhost and a C# AddOn does the NinjaTrader side.

What is the NinjaTrader ATI?

The Automated Trading Interface is NinjaTrader's official way in from an outside program. It has a file interface that reads semicolon-delimited Order Instruction Files named oif*.txt from an incoming folder, and a DLL interface, NTDirect.dll, shipped as NinjaTrader.Client.dll. Both run only on the Windows box where NinjaTrader runs, and both submit orders without any risk checks of their own. Source: ninjatrader.com ATI help guide, retrieved 2026-07-10.

How does PitBridge let Python place an order?

Run uvx pitbridge run and the daemon serves a localhost REST API at /v1/*, a WebSocket event feed, and MCP over HTTP at http://127.0.0.1:8873/mcp. Your Python posts a JSON order to /v1/place_order, it passes the same deterministic guardrail engine as an agent's tool call, and only an allowed order continues to NinjaTrader 8. A blocked order returns a structured reason code, not an exception.

Do I need Windows and the C# AddOn to try it?

Not to try it. With no config, uvx pitbridge mcp boots a safe paper demo sandbox with a fake account and every guardrail on, so a script or agent can read state and exercise the tools. Real routing into NinjaTrader 8 is the Windows piece: the C# AddOn runs next to NinjaTrader and connects out to the daemon. The daemon itself runs on macOS, Linux, or Windows.

Is it safe to place orders this way, and does it go live?

Every order through the daemon passes a deterministic guardrail engine that refuses anything past the limits you configure, and no order routes through a PitBridge server. The open core is paper and simulation only: arm-live refuses there because live execution ships as a separate closed component, and no agent or script has a 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. Futures trading carries substantial risk of loss. This is not financial advice.

PitBridge is in development. NinjaTrader 8 is first.

Tell us your platform and we email you when your setup is supported. Nothing else.