Market Orders
How to submit market orders in QuantJourney order mode and how they fill on bars.
Market orders are the simplest order-mode primitive. They express execution certainty, not price control.
Source
backtester/execution/order_types.py + backtester/execution/fill_engine.pyLayerOrder execution
ModeOrder mode
Input
OrderType.MARKET, side, quantity, current barOutputfill at bar open or close, after slippage and commission
Primary API
Order(..., order_type=OrderType.MARKET)Main caveatMarket orders always fill in the model; this can overstate realism for illiquid assets.
Level 1: Market Entry
Buy 15 percent of NAV
python
qty = int(nav * 0.15 / bars["AAPL"].close)
self.fill_engine.submit(Order(
instrument="AAPL",
side=OrderSide.BUY,
quantity=qty,
order_type=OrderType.MARKET,
))Level 2: Market Exit
Cancel resting exits before flattening, so stale stops or limits do not remain after the strategy leaves the position.
Cancel exits and sell current position
python
pos = current_positions.get("AAPL", 0.0)
if pos > 0 and sell_signal:
self.fill_engine.cancel_all(instrument="AAPL")
self.fill_engine.submit(Order(
instrument="AAPL",
side=OrderSide.SELL,
quantity=pos,
order_type=OrderType.MARKET,
))Level 3: Crossover Strategy Skeleton
Market orders from SMA signals
python
class MarketCrossover(Backtester):
def __init__(self, **kwargs):
super().__init__(execution_mode="orders", **kwargs)
self._prev_signal = {}
def _compute_orders(self, date, bars, current_positions, nav):
fast = self.instruments_data.get_feature("SMA_20_close")
slow = self.instruments_data.get_feature("SMA_50_close")
for inst in self.instruments:
if date not in fast.index or inst not in fast.columns:
continue
signal = 1 if fast.loc[date, inst] > slow.loc[date, inst] else 0
prev = self._prev_signal.get(inst, 0)
pos = current_positions.get(inst, 0.0)
if signal == 1 and prev == 0 and pos == 0:
qty = int(nav * 0.15 / bars[inst].close)
self.fill_engine.submit(Order(inst, OrderSide.BUY, qty, OrderType.MARKET))
elif signal == 0 and prev == 1 and pos > 0:
self.fill_engine.cancel_all(instrument=inst)
self.fill_engine.submit(Order(inst, OrderSide.SELL, pos, OrderType.MARKET))
self._prev_signal[inst] = signalFill Rule
For OrderType.MARKET, FillEngine uses
bar.open by default. If configured with fill_at="close", it uses bar.close. Slippage and commission are applied after the theoretical fill price is selected.
Failure Modes
- Forgetting
execution_mode="orders". - Submitting a new market entry on every bar while already long.
- Failing to cancel existing stop/limit exits before a manual market exit.
- Assuming market fill price equals the signal bar close.
- Using market orders for illiquid assets without a realistic slippage model.