Raw orders & brackets
Raw orders & brackets
When managed intent is not enough: submit order requests directly, attach a server-side protective bracket, and modify or cancel by id.
Raw orders & brackets
For full control over price, type and time-in-force, submit an OrderRequest directly with
PlaceOrder. Unlike managed intent, a raw order does not reason about your position — it
does exactly what you ask — so you own the lifecycle. Results arrive asynchronously through
OnOrderUpdate and OnFill, which is where you react to fills, rejections and
cancels. The request's Instrument must equal the run's Instrument — a
strategy trades only the instrument it runs on.
To get a protective stop and target without managing the OCO yourself, attach a BracketSpec
to the entry. The provider places the bracket server-side and cancels the remaining leg when one fills.
Bracket prices are absolute (not offsets) — the strategy knows the chart, and absolute
prices keep the spec venue-neutral.
C#using TradeStrike.Pipeline.Trading;
// Market entry with a server-side bracket (absolute prices).
PlaceOrder(new OrderRequest(
Instrument: Instrument,
Side: OrderSide.Buy,
Type: OrderType.Market,
Quantity: 5m,
Bracket: new BracketSpec(StopLossPrice: 4340m, TakeProfitPrice: 4360m)));
// Resting limit order:
PlaceOrder(new OrderRequest(Instrument, OrderSide.Buy, OrderType.Limit, 2m, LimitPrice: 4350.25m));
ModifyOrder(orderId, new OrderModification(NewLimitPrice: 4351m));
CancelOrder(orderId);
Flatten(); // close this run's open position now
The constructor draws on a small set of enums. A BracketSpec needs at least one of its two
prices, and for a buy the stop must be below the target (flipped for a sell) — validated at
construction.
| Type | Values |
|---|---|
OrderSide |
Buy, Sell
|
OrderType |
Market, Limit, Stop, StopLimit
|
TimeInForce |
Day, Gtc, Ioc, Fok
|
OrderState |
Pending → Working → PartiallyFilled → Filled (or Cancelled / Rejected / Expired / Stale) |
Limit requires a positive LimitPrice, Stop a positive
StopPrice, StopLimit both, and Market neither —
Validate() enforces this. Stale is a soft-terminal a provider re-evaluates on
reconnect; the other terminals are final.
The full OrderRequest
The examples above use the common arguments, but OrderRequest carries a few more for cases
that need them. The complete shape is:
OrderRequest.csnew OrderRequest(
Instrument, Side, Type, Quantity,
LimitPrice: null, StopPrice: null,
TimeInForce: TimeInForce.Day,
Bracket: null, // BracketSpec for a server-side stop/target
OcoGroupId: null, // link orders into one one-cancels-other group
ClientTag: null, // your own label, echoed back on the resulting Order
InstrumentKey: null, // cross-venue routing: the canonical instrument id…
InstrumentVenue: null, // …and the venue the symbol is native to (data feed A, broker B)
OriginId: null); // owner provenance — stamps which component created the order
-
OcoGroupIdties several working orders into one one-cancels-other group (a manual OCO, whereBracketSpecis the automatic two-leg case). -
ClientTagis a free label echoed back on the resultingOrderto correlate it with your own bookkeeping. -
InstrumentKey/InstrumentVenuedrive cross-venue routing — sourcing data from one venue while routing the order to another; the execution layer localises the wire symbol.nullmeans same-venue (no rewrite). -
OriginIdrecords which component created the order, so an auto-management engine (a chart-trader ATM, the copier) only acts on positions it opened.
Call request.Validate() to fail fast on an inconsistent request; the same validation runs on
submit. Modifications travel as an OrderModification delta — null fields mean "leave
unchanged".
Reading orders & fills
OnOrderUpdate(Order) hands you the live order snapshot. Beyond State it carries
FilledQuantity, AverageFillPrice, RemainingQuantity,
BrokerOrderId, RejectReason, the originally-submitted
OriginalRequest, and IsTerminal (true once it can no longer change). Orders are
keyed by OrderId (a GUID wrapper); keep the id to modify or cancel later. The run's own live
orders are also available as the WorkingOrders list.
OnFill(Fill) carries each raw execution — Quantity, Price,
Commission, TimestampUtc — while OnOrderUpdate fires
alongside with the rolled-up order state. Use OnFill for per-execution bookkeeping
(commission tracking, fill logs) and OnOrderUpdate for state transitions.
C#protected override void OnOrderUpdate(Order order)
{
if (order.State == OrderState.Rejected)
Log($"rejected: {order.RejectReason}");
else if (order.IsTerminal && order.State == OrderState.Filled)
Log($"filled {order.FilledQuantity} @ {order.AverageFillPrice}");
}
protected override void OnFill(Fill fill)
=> Log($"exec {fill.Quantity} @ {fill.Price} (comm {fill.Commission})");
Reusable bracket presets
For named SL/TP templates independent of a running strategy, the
TradeStrike.Pipeline.Trading.Brackets namespace offers BracketPreset (a name plus
stop / target offsets in Price or Ticks, as positive magnitudes) and
the pure helper BracketPresetMath.ComputeBracketPrices(entryPrice, side, preset, tickSize),
which resolves the magnitudes into the absolute SL/TP prices a BracketSpec wants. Long
entries put the stop below and target above; shorts flip. See the
Trading reference.