QuantJourney Backtester

QuantJourney Backtester

Share product feedback

✓

Thank you.

Your note is now in the QuantJourney inbox.

docs/engine/limit-orders.mdx

Limit Orders and Take Profit

Limit entries, take-profit exits, expiry and stale-order hygiene.

A limit order expresses price control. It can improve execution price, but it also introduces pending state: the order may remain live, expire, or never fill.

Sourcebacktester/execution/order_types.py + backtester/execution/fill_engine.py
LayerOrder execution / price-controlled entry or exit
ModeOrder mode
InputOrderType.LIMIT, side, quantity, limit price, time-in-force
Outputfill if high/low reaches the limit, or pending/expired state
Primary APIOrder(..., order_type=OrderType.LIMIT, limit_price=...)
Main caveatA touched limit is not exchange queue realism. It is a bar-level trigger assumption.

Fill Rules

  • Buy limit fills when bar.low <= limit_price.
  • Sell limit fills when bar.high >= limit_price.
  • Buy theoretical fill is min(limit_price, bar.open).
  • Sell theoretical fill is max(limit_price, bar.open).
  • Slippage and commission are applied after the theoretical price.

Native Expiry

Use TimeInForce.DAY, expire_at or expires_after_bars instead of manually counting stale orders when the intended policy is simple.

Limit entry with three-bar expiry
python
from backtester.execution import Order, OrderSide, OrderType

self.fill_engine.submit(Order(
    instrument="AAPL",
    side=OrderSide.BUY,
    quantity=100,
    order_type=OrderType.LIMIT,
    limit_price=round(bars["AAPL"].close * 0.98, 2),
    expires_after_bars=3,
))

DAY Order

A TimeInForce.DAY order expires after the first eligible bar if it does not fill.

Day limit order
python
self.fill_engine.submit(Order(
    instrument=inst,
    side=OrderSide.BUY,
    quantity=shares,
    order_type=OrderType.LIMIT,
    limit_price=entry_limit,
    time_in_force=TimeInForce.DAY,
))

Take-Profit Exit

A take-profit is usually a sell limit for a long position or buy limit for a short position.

Sell take-profit
python
take_profit = round(entry_price * 1.08, 2)

self.fill_engine.submit(Order(
    instrument=inst,
    side=OrderSide.SELL,
    quantity=pos,
    order_type=OrderType.LIMIT,
    limit_price=take_profit,
))

Failure Modes

  • Forgetting that a pending limit order can outlive the signal that created it.
  • Submitting duplicate take-profit orders on every bar.
  • Ignoring same-bar ambiguity when a stop and take-profit both touch.
  • Assuming limit orders remove the need for slippage modeling.
  • Treating a touched limit as guaranteed execution in an illiquid market.

Audit Checklist

  • Which orders are still pending after each bar?
  • Did the limit expire by DAY, GTD or bars-live policy?
  • Did the strategy cancel stale orders when signal state changed?
  • Did a gap improve the theoretical fill price?