Orderflow
Orderflow ADVANCED
Per-price-level bid/ask volume per bar — the data behind footprint, delta and POC tools. Opt in once, and the framework pre-aggregates it for you.
On this page
Opting in
Footprint-class indicators need per-level, per-side traded volume. Computing that from raw ticks is
expensive, so the framework only does it for indicators that ask. Tag the indicator with
[RequiresOrderFlow] and read the per-bar data through
ctx.OrderFlow(seriesIndex), an ISeries<OrderFlowBar> aligned 1:1 with
the bars.
OrderFlow without the attribute throws. The runtime
rejects an un-opted-in indicator with an InvalidOperationException — a deliberate
guard that catches the "I forgot the attribute" bug rather than silently returning empty data.
The data is delivered for history and live: a pre-aggregated OrderFlowBar reaches
you through OnDataLoaded and OnBarUpdate, never as raw historical ticks. If
you also want the raw live trade stream, opt into ProcessesMarketData separately —
the two compose.
PocMarker.csusing TradeStrike.Pipeline.Indicators;
using TradeStrike.Pipeline.OrderFlow;
using TradeStrike.Pipeline.Plots;
using TradeStrike.Pipeline.Series;
[IndicatorDescription("Marks each bar's volume Point of Control — the price level with the most traded volume.")]
[IndicatorCategory(IndicatorCategory.OrderFlow)]
[IndicatorInput(IndicatorInputKind.None)]
[RequiresOrderFlow] // <-- gates ctx.OrderFlow(...)
public sealed class PocMarker : IndicatorBase
{
private readonly ChunkedSeries<double> _poc = new();
public PocMarker(IIndicator? parent = null) : base(parent)
{
AddPlot(new Plot("POC", _poc, PlotStyle.Dots, new ChartColor(255, 152, 0), 4.0));
}
public override void OnDataLoaded(IIndicatorContext ctx)
{
var of = ctx.OrderFlow(0);
for (int i = of.Count - 1; i >= 0; i--)
_poc.Append(PocOf(of[i]));
}
public override void OnBarUpdate(IIndicatorContext ctx)
{
_poc.Append(PocOf(ctx.OrderFlow(0)[0]));
}
private static double PocOf(in OrderFlowBar bar)
=> bar.TryGetPoc(out double price, out _) ? price : double.NaN;
}
What an OrderFlowBar gives you
An OrderFlowBar is a value type wrapping the underlying Bar plus its
per-price-level volume, designed for allocation-free reads in tight render loops. The key surface:
| Member | Meaning |
|---|---|
Bar |
The OHLCV bar this orderflow snapshot corresponds to. |
LevelCount / GetLevel(i)
|
Number of price levels and the level at index i (index 0 = lowest price). |
TryGetLevelAtPrice(price, out level) |
Look up the level at a specific price (true when it lines up on a tick). |
TryGetPoc(out price, out volume) |
Point of Control — the highest-total-volume level (ties resolve to the lower price). |
Delta / TotalBidVolume / TotalAskVolume / TotalTradeCount
|
Bar-level aggregates, all O(1) (precomputed). |
LocalDeltaHigh / LocalDeltaLow
|
Intra-bar running-delta extremes (0-floored) — power cumulative-delta candle wicks. |
TickSize / LowTicks
|
The price grid the levels are indexed on. |
Each OrderFlowLevel carries Price, BidVolume,
AskVolume, TradeCount, plus computed TotalVolume and
Delta (= Ask − Bid). When the producer tracked a per-side print split,
HasTradeCountSplit is true and you can read GetBidTradeCount(i) /
GetAskTradeCount(i).
Per-bar statistics
Some quantities can only be computed during tick aggregation (they depend on tick order). When
available, OrderFlowBar.HasStats is true and Stats (an
OrderFlowBarStats) exposes RunningDeltaMax/Min,
VolumePerSecond, and commitment-of-traders helpers CotHigh /
CotLow. Bars built without a tick aggregator (empty bars, MTF seeding) carry
Stats == null, so read defensively.
Backfill resolution
OrderFlowResolution controls how much history is fetched: Tick (finest,
exact aggressor and delta), Second, Minute (coarsest, fastest, with
estimated bid/ask), and Auto (the default — derived from the chart's bar period).
Surface it as a user choice by implementing IOrderFlowResolutionAware; every
IndicatorBase already provides the backing OrderFlowResolution property, and
the settings dialog synthesizes a "Resolution" dropdown only for indicators marked
[RequiresOrderFlow] — so the dropdown never appears on an ordinary SMA.
Open Interest
For the venue-reported Open Interest channel, tag the indicator with
[RequiresOpenInterest] and read ctx.OpenInterest(seriesIndex) — a
scalar series aligned 1:1 with the bars, with double.NaN on bars that report no OI.
Unlike orderflow, this is a default member: contexts without an OI channel return a safe empty series,
so read defensively (TryGet → NaN). The attribute only steers backfill routing; the
channel is always reachable.
Orderflow gives you the data; turning it into footprint cells, profile columns or POC lines is a rendering job — see Custom rendering.