Part 1 of 3
Building an Opening Range Breakout System in NinjaTrader with ScalpTrader TradeEvents Integration

Part 1: The Idea

June 30, 2026

·

4 min read

NinjaTrader

This is the first post in a three-part series where I build a small demo strategy in NinjaTrader, wire it up to ScalpTrader’s TradeEvents dashboard, and walk through what good trade telemetry actually looks like.

The series:

  1. The idea (this post) — what the strategy does and why it’s a good showcase
  2. Implementing it in NinjaScript — the actual code, state machine, and order handling
  3. Closing the loop — sending webhook events and reading the TradeEvents dashboard

Before writing any code, I wanted a strategy that was simple enough to explain in a few paragraphs, but with a trade lifecycle rich enough to generate interesting events. That ruled out anything that holds positions for days, and anything with a pile of tunable parameters. What I landed on was a classic Opening Range Breakout (ORB).

What is an Opening Range Breakout?

The opening range breakout is one of the oldest intraday setups around. The idea is simple: the first few minutes after the market opens tend to set a “range” as early orders get worked. Once price breaks outside that range, it’s often read as a signal that one side (buyers or sellers) has taken control for the session.

It’s a popular teaching example because the logic is entirely visual — you can draw the range as a box on the chart and watch price either respect it or break out of it — and because it naturally produces a small, bounded number of trades per day instead of constant chop.

The specific rules for this demo

For this strategy (ORBDemo_Full, running on a 1-minute ES chart), the rules are:

  • Wait for the New York session open (9:30 AM ET).
  • Track the high and low of the first 15 minutes after the open. This becomes the “opening range.”
  • Once the range is set:
    • Enter long if a bar closes above the range high.
    • Enter short if a bar closes below the range low.
  • Exit the trade when either:
    • Price closes back through the opposite side of the range (a close below the range low for longs, above the range high for shorts), or
    • The session ends (4:00 PM ET), in which case the position is flattened.
  • One trade per session, maximum. Once a trade has played out — win, loss, or no breakout at all — the strategy goes idle for the rest of the day.

A few deliberate choices worth calling out:

  • Close-based, not touch-based, breakouts. Entries and the range-flip exit both trigger on a bar close beyond the level, not an intrabar touch. This cuts down on getting faked out by a single wick through the range.
  • The range itself doubles as the stop. Instead of a separate fixed-tick stop loss, the opposite edge of the opening range is the stop. If you went long on a breakout above the range high, a close back below the range low says the breakout failed.
  • No re-entries. Real ORB systems often allow multiple attempts per session. This one deliberately doesn’t, to keep the event stream — and the explanation — simple.

This is a demo strategy, not a live trading system. It’s intentionally under-engineered: no volatility filters, no volume confirmation, no session-by-session optimization. The goal isn’t edge, it’s a clean, realistic trade lifecycle to build the rest of the series around.

Why this is a good showcase for TradeEvents

The reason ORB works well here is that it produces a small set of clearly defined events, each with an unambiguous trigger:

EventWhen it fires
cardEvery minute — current status, a human-readable state description, price, and range/position detail
position_openedThe instant a breakout entry fills
position_closedExit via range-flip stop, session close, or external flatten

Because the strategy moves through a predictable sequence of states each day — waiting, building the range, waiting for breakout, in a position, done — every event has clear context behind it. That makes it a good fixture for demonstrating a dashboard: you can watch a single session unfold from a flat line, to a range box, to an entry marker, to an exit, and see each of those moments show up as a discrete event in TradeEvents.

It also keeps the volume of events sane. One card a minute and at most one open/close pair a day is plenty to prove out the integration without flooding a webhook endpoint — something that matters a lot more once you’re testing against a real service instead of a mock.

What’s next

In Part 2, I’ll go through the actual NinjaScript implementation — the state machine that drives the strategy, how entries and exits are handled differently in warmup versus realtime, and the order/execution callbacks that detect fills (and the occasional external flatten). Then in Part 3, I’ll wire up the webhook calls and walk through what shows up on the TradeEvents dashboard once the strategy is actually running.

The series is based on ORBDemo_Full.cs, which includes warmup replay — on go-live it replays any trades from the current day’s historical bars so the dashboard has context immediately. If you only need live events and want a simpler starting point, ORBDemo_Simple.cs covers the same trading logic without the warmup section. Both files are on GitHub.