Raw orders & brackets
Raw orders & brackets
When managed intent is not enough: submit order requests directly, attach a protective bracket, and modify or cancel by id.
Raw orders & brackets
For full control over price, type and time in force, build an OrderRequest and submit it with
PlaceOrder. A raw order does exactly what it says, independent of your position, so the
lifecycle is yours. Results arrive through OnOrderUpdate and OnFill, 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. A structurally invalid request
throws on the strategy thread when you call PlaceOrder. Raw quantities are in venue units; see
Instrument metadata & sizing.
To get a protective stop and target without managing the OCO yourself, attach a BracketSpec
to the entry. The provider places the bracket and cancels the remaining leg when one fills. Bracket prices
are absolute, which keeps the spec venue-neutral.
C#using SabrTrader.Pipeline.Venues.Trading;
// Market entry with a 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
A BracketSpec needs at least one of its two prices, and for a buy the stop must be below the
target (reversed for a sell); BracketSpec.Validate(entrySide) checks this and runs as part of
the request's validation. The request uses these enums:
| Type | Values |
|---|---|
OrderSide |
Buy, Sell
|
OrderType |
Market, Limit, Stop, StopLimit
|
TimeInForce |
Day (default), Gtc, Ioc, Fok
|
OrderSession |
Regular (default), PreMarket, PostMarket, Extended; set on OrderRequest.Session. See Time in force & session for what a venue takes.
|
OrderState |
Pending, Working, PartiallyFilled, Filled, Cancelled, Rejected, Expired, Stale
|
Limit requires a positive LimitPrice, Stop a positive
StopPrice, StopLimit both, and Market neither;
Validate() enforces this. Filled, Cancelled, Rejected
and Expired are terminal (Order.IsTerminal). Stale marks an order
whose state the provider re-checks after a reconnect.
The full OrderRequest
The examples use the common arguments. The complete constructor is:
OrderRequest.csnew OrderRequest(
Instrument, Side, Type, Quantity,
LimitPrice: null, StopPrice: null,
TimeInForce: TimeInForce.Day,
Bracket: null, // BracketSpec: protective stop / target
OcoGroupId: null, // links 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
OriginId: null); // which component created the order
-
OcoGroupIdties several working orders into one one-cancels-other group (a manual OCO;BracketSpecis the automatic two-leg case).OcoGroupKind(Alternatives,ProtectiveExits) says what the members are to each other. -
ClientTagis a free label echoed back on the resultingOrder. Use it to recognise your orders inOnOrderUpdate, sincePlaceOrderreturns before the order has an id. -
InstrumentKey/InstrumentVenueroute an order to a broker on a different venue than the data feed; the execution layer translates the symbol. Null means same venue. -
OriginIdrecords which component created the order, so an automatic manager (a chart-trader ATM, the copier) acts only on positions it opened.
A few venue-specific fields are init-only properties outside the constructor:
ReduceOnly, PostOnly, PositionEffect (Open,
Close), NativeInstrumentId and NativeInstrumentType. Set them with an
object initializer or a with expression. Call request.Validate() to fail fast on
an inconsistent request; the same validation runs on submit. Modifications travel as an
OrderModification (NewQuantity, NewLimitPrice,
NewStopPrice, NewTimeInForce), where a null field means "leave unchanged".
Reading orders & fills
OnOrderUpdate(Order) hands you the order's latest state. Besides State it carries
Id, FilledQuantity, AverageFillPrice, RemainingQuantity,
BrokerOrderId, RejectReason, the current Request, the
OriginalRequest as first submitted, and IsTerminal. Keep the OrderId
(a GUID wrapper) to modify or cancel later. The run's live orders are also available as
WorkingOrders.
OnFill(Fill) carries each execution (OrderId, Quantity,
Price, Commission, TimestampUtc, ExecutionId), and
OnOrderUpdate fires alongside with the rolled-up order state. Use OnFill for
per-execution bookkeeping and OnOrderUpdate for state transitions.
C#protected override void OnOrderUpdate(Order order)
{
if (order.State == OrderState.Rejected)
Log($"rejected: {order.RejectReason}");
else if (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})");
CancelOrder on an order that fills first produces a fill, not a cancel; that race is normal.
Reusable bracket presets
For named stop/target templates, the SabrTrader.Pipeline.Venues.Trading.Brackets namespace
offers BracketPreset (a name plus stop and target offsets as positive magnitudes, in
Price, Ticks or Pips) and
BracketPresetMath.ComputeBracketPrices(entryPrice, side, preset, tickSize, pipSize), which
turns the offsets into the absolute prices a BracketSpec takes. Long entries put the stop below
and the target above; shorts reverse it. See the Trading
reference.