Advanced orders¶
Stop orders, take-profit, trailing stops, and execution flags. Every order type below is exposed through every binding — only the method name differs.
Order types¶
| Type | Use case |
|---|---|
STOP_MARKET |
Stop loss, breakout entry |
STOP_LIMIT |
Stop with price control |
TAKE_PROFIT_MARKET |
Lock in profits |
TAKE_PROFIT_LIMIT |
Lock in profits with price control |
TRAILING_STOP |
Dynamic stop that follows price |
ICEBERG |
Large order shown in slices — see Iceberg orders |
OCO is not an OrderType and has no emit method. It is an executor-side call — Executor.submit_oco(order1, order2) in Python, submitOco(order1, order2) in Node — backed by the separate supportsOCO capability flag. From a strategy, use the manual TP/SL bracket below or bracket orders.
Stop orders¶
Stop trigger logic: SELL stop fires when price <= trigger; BUY stop fires when price >= trigger.
Take-profit orders¶
SELL TP fires when price >= trigger (lock profit on a long); BUY TP fires when price <= trigger.
Trailing stops¶
SELL trailing trigger follows price up; when price drops to trigger, the order executes.
Time-in-force¶
IOC (immediate-or-cancel), FOK (fill-or-kill), POST_ONLY (maker-only — reject if would cross spread).
POST_ONLY orders that would cross the book are rejected at submit time (matches real-exchange behaviour, including in BacktestRunner since #124).
Close current position¶
close_position issues a reduce-only market order sized to flatten the existing position.
Manual TP/SL bracket¶
A common pattern: on entry-fill, place TP and SL; cancel one when the other fills.
def on_order_filled(self, order):
if order.id == self.entry_id:
entry = order.price
self.tp_id = self.take_profit_market("sell", trigger=entry * 1.06, qty=order.quantity)
self.sl_id = self.stop_market ("sell", trigger=entry * 0.98, qty=order.quantity)
elif order.id == self.tp_id:
self.cancel_order(self.sl_id)
elif order.id == self.sl_id:
self.cancel_order(self.tp_id)
onOrderFilled(order, emit) {
if (order.id === this.entryId) {
const entry = order.price;
this.tpId = emit.takeProfitMarket("sell", entry * 1.06, order.quantity);
this.slId = emit.stopMarket ("sell", entry * 0.98, order.quantity);
} else if (order.id === this.tpId) {
emit.cancel(this.slId);
} else if (order.id === this.slId) {
emit.cancel(this.tpId);
}
}
void onOrderFilled(const Order& order) {
if (order.id == _entryId) {
auto entry = order.price.toDouble();
_tpId = emitTakeProfitMarket(order.symbol, Side::SELL,
Price::fromDouble(entry * 1.06), order.quantity);
_slId = emitStopMarket (order.symbol, Side::SELL,
Price::fromDouble(entry * 0.98), order.quantity);
} else if (order.id == _tpId) {
emitCancel(_slId);
} else if (order.id == _slId) {
emitCancel(_tpId);
}
}
Checking exchange capabilities¶
Real exchanges support different subsets of order types. Before using an advanced feature in live trading, ask the executor what it supports.
caps = executor.capabilities() # flox_py.ExchangeCapabilities
has_trailing = caps.trailing_stop
has_oco = caps.oco
ExchangeCapabilities carries one bool per feature: stop_market, stop_limit,
take_profit_market, take_profit_limit, trailing_stop, iceberg, oco,
gtc, ioc, fok, gtd, post_only, reduce_only, close_position.
There is no supports(OrderType) helper in the bindings — read the flag directly.
capabilities() is a hook on Executor; a binding-supplied executor overrides it
and the engine queries it inline. SimulatedExecutor does not expose it.
const caps = executor.capabilities();
const hasTrailing = caps.trailingStop;
const hasOco = caps.oco;
Same flags, camelCased, all optional. Executor is an interface you implement;
capabilities() is queried by the engine.
Capabilities introspection is not exposed in the Codon API — check the exchange's connector source or fall back to manual TP/SL.