Skip to content

Orders

All order methods return OrderResult:

python
OrderResult(
    success=True,
    order_id=738082887,
    message=None,
    raw={'result': [...], 'status': 'success'}
)

Market Orders

python
result = client.buy_market("SPY", 10)
result = client.sell_market("SPY", 10)

Example response:

python
OrderResult(
    success=True,
    order_id=1093165422,
    message=None,
    raw={
        'status': 'success',
        'result': [{
            'order_id': '1093165422',
            'local_order_id': 'AQC-XXXX-1769537231772',
            'order_status': 'PreSubmitted',
            'encrypt_message': '1'
        }]
    }
)

Sell market example:

python
OrderResult(
    success=True,
    order_id=1093165452,
    message=None,
    raw={
        'status': 'success',
        'result': [{
            'order_id': '1093165452',
            'local_order_id': 'AQC-XXXX-1769537923167',
            'order_status': 'PreSubmitted',
            'encrypt_message': '1'
        }]
    }
)

Limit Orders

python
result = client.buy_limit("SPY", 10, price=690.50)
result = client.sell_limit("SPY", 10, price=695.00)

Example response:

python
OrderResult(
    success=True,
    order_id=1093165424,
    message=None,
    raw={
        'status': 'success',
        'result': [{
            'order_id': '1093165424',
            'local_order_id': 'AQC-XXXX-1769537238542',
            'order_status': 'Submitted',
            'encrypt_message': '1'
        }]
    }
)

Sell limit example:

python
OrderResult(
    success=True,
    order_id=1093165453,
    message=None,
    raw={
        'status': 'success',
        'result': [{
            'order_id': '1093165453',
            'local_order_id': 'AQC-XXXX-1769537931033',
            'order_status': 'Submitted',
            'encrypt_message': '1'
        }]
    }
)

Stop Orders

python
result = client.buy_stop("SPY", 10, stop_price=695.00)
result = client.sell_stop("SPY", 10, stop_price=685.00)

Example (rejected):

text
sell_stop: OrderResult(
    success=True,
    order_id=None,
    message=None,
    raw={'status': 'success', 'result': {'error': 'Invalid order price fields'}}
)

Stop-Limit Orders

python
result = client.buy_stop_limit("SPY", 10, stop_price=695.00, limit_price=695.50)
result = client.sell_stop_limit("SPY", 10, stop_price=685.00, limit_price=684.50)

Example (submitted):

text
sell_stop_limit: OrderResult(
    success=True,
    order_id='1093166084',
    message=None,
    raw={'status': 'success', 'result': [{'order_id': '1093166084', 'local_order_id': 'AQC-XXXX-1769541324981', 'order_status': 'PreSubmitted', 'encrypt_message': '1'}]}
)
order status: {'order_id': '1093166084', 'status': 'PreSubmitted', 'symbol': 'SPY', 'side': 'SELL', 'quantity': 1.0, 'filled_quantity': 0.0, 'remaining_quantity': 1.0, 'avg_fill_price': None, 'limit_price': '0.01', 'order_type': 'Stop Limit', 'tif': 'CLOSE'}

Common Parameters

ParameterTypeDefaultDescription
symbolstrrequiredTicker symbol
quantityintrequiredOrder quantity
pricefloat-Limit price
stop_pricefloat-Stop trigger price
limit_pricefloat-Limit price for stop-limit
conidintNoneContract ID (auto-resolved if None)
tifstr"DAY"Time in force: DAY, GTC, IOC, OPG
exchangestr"SMART"Routing exchange
forceboolTrueAuto-confirm IBKR warnings

Cancel Order

python
success = client.cancel_order(738082887)  # Returns bool

Cancel All Orders

Cancels all open orders for the strategy in a single call:

python
cancelled_count = client.cancel_all_orders()  # Returns int

Returns: Number of orders cancelled.

Wait for Fill

python
status = client.wait_for_fill(order_id, timeout=30)

Returns: Dict

python
{
    'status': 'Filled',
    'filled_quantity': 10,
    'avg_fill_price': 690.54
}

Wait for Submitted

Waits until an order is acknowledged by the exchange. Critical for multi-leg strategies where you need to confirm the first leg is accepted before placing subsequent legs.

python
acknowledged = client.wait_for_submitted(order_id, timeout=30, poll_interval=0.3)

Returns: bool - True if order reached submitted/presubmitted/filled status, False if rejected/cancelled/timeout.

Parameters:

ParameterTypeDefaultDescription
order_idstr|intrequiredOrder ID to monitor
timeoutint30Max seconds to wait
poll_intervalfloat0.3Seconds between status checks

Example - Iron Condor leg sequencing:

python
# Place first leg
result = client.place_order(symbol="SPX", quantity=1, side="SELL", ...)

if result.success and result.order_id:
    # Wait for exchange acknowledgment before placing next leg
    if client.wait_for_submitted(result.order_id, timeout=15):
        # Safe to place second leg
        client.place_order(symbol="SPX", quantity=1, side="BUY", ...)
    else:
        # First leg rejected - don't place second leg
        logger.error("First leg not acknowledged")

Order Status

python
status = client.get_order_status(order_id)

Returns: Dict

python
{
    'order_id': 1093165422,
    'status': 'Filled',
    'symbol': 'SPY',
    'side': 'BUY',
    'quantity': 1.0,
    'filled_quantity': 1.0,
    'remaining_quantity': 0.0,
    'avg_fill_price': '695.01',
    'limit_price': '',
    'order_type': 'Market',
    'tif': 'CLOSE',
    'raw': { ... }
}

Sell status example:

python
{
    'order_id': 1093165452,
    'status': 'Filled',
    'symbol': 'SPY',
    'side': 'SELL',
    'quantity': 1.0,
    'filled_quantity': 1.0,
    'remaining_quantity': 0.0,
    'avg_fill_price': '695.64',
    'limit_price': '',
    'order_type': 'Market',
    'tif': 'CLOSE',
    'raw': { ... }
}

Bracket Orders

python
result = client.place_bracket_order(
    symbol="SPY",
    quantity=10,
    side="BUY",
    entry_price=690.00,
    stop_loss=685.00,
    take_profit=700.00,
    entry_type="LMT"
)

Trailing Stop

python
result = client.place_trailing_stop(
    symbol="SPY",
    quantity=10,
    side="SELL",
    trail_amount=2.00,      # or trail_percent=0.5
)

Combo Orders

Combo orders (spreads) allow you to trade multiple option legs as a single order. This is essential for strategies like vertical spreads, iron condors, and butterflies.

ComboLeg Parameters

python
from aqc_trading_sdk import ComboLeg

ComboLeg(
    conid=123456,      # Contract ID (required)
    ratio=1,           # Leg ratio (required)
    action="SELL",     # "BUY" or "SELL" (required)
    exchange="CBOE"    # Routing exchange (required for options)
)

Exchange Routing

Important

The exchange parameter is required for option combo legs and must match the underlying:

UnderlyingExchangeDescription
SPX/SPXWCBOEIndex options route through CBOE
SPY, QQQ, TQQQSMARTETF options use SMART routing

Combo Order Side

Key Concept

For combo orders, side="BUY" means you are buying the spread structure (opening the position), regardless of whether it's a credit or debit spread. The individual leg actions (action="SELL" or action="BUY") determine which legs are sold and bought.

Bear Call Spread (Credit Spread)

Sell a lower-strike call, buy a higher-strike call:

python
from aqc_trading_sdk import ComboLeg

# Get option contracts first
short_call = client.get_option_contract(
    symbol="SPX", expiry="20260130", strike=6100, right="C", trading_class="SPXW"
)
long_call = client.get_option_contract(
    symbol="SPX", expiry="20260130", strike=6110, right="C", trading_class="SPXW"
)

# Filter for exact expiry
short_conid = [c for c in short_call if c.get("maturityDate") == "20260130"][0]["conid"]
long_conid = [c for c in long_call if c.get("maturityDate") == "20260130"][0]["conid"]

# Build combo legs - CBOE for SPX options
legs = [
    ComboLeg(conid=short_conid, ratio=1, action="SELL", exchange="CBOE"),
    ComboLeg(conid=long_conid, ratio=1, action="BUY", exchange="CBOE")
]

# Place the combo order
result = client.place_combo_order(
    legs=legs,
    quantity=1,
    side="BUY",        # "BUY" the spread structure
    order_type="MKT",  # or "LMT" with price
    price=None
)

Bull Put Spread (Credit Spread)

Sell a higher-strike put, buy a lower-strike put:

python
from aqc_trading_sdk import ComboLeg

# Get option contracts
short_put = client.get_option_contract(
    symbol="SPX", expiry="20260130", strike=6000, right="P", trading_class="SPXW"
)
long_put = client.get_option_contract(
    symbol="SPX", expiry="20260130", strike=5990, right="P", trading_class="SPXW"
)

short_conid = [c for c in short_put if c.get("maturityDate") == "20260130"][0]["conid"]
long_conid = [c for c in long_put if c.get("maturityDate") == "20260130"][0]["conid"]

legs = [
    ComboLeg(conid=short_conid, ratio=1, action="SELL", exchange="CBOE"),
    ComboLeg(conid=long_conid, ratio=1, action="BUY", exchange="CBOE")
]

result = client.place_combo_order(
    legs=legs,
    quantity=1,
    side="BUY",
    order_type="MKT",
    price=None
)

ETF Options (SPY Example)

For ETF options, use exchange="SMART":

python
from aqc_trading_sdk import ComboLeg

# SPY Bear Call Spread
short_conid = 123456  # SPY call conid
long_conid = 789012   # SPY call conid (higher strike)

legs = [
    ComboLeg(conid=short_conid, ratio=1, action="SELL", exchange="SMART"),
    ComboLeg(conid=long_conid, ratio=1, action="BUY", exchange="SMART")
]

result = client.place_combo_order(
    legs=legs,
    quantity=1,
    side="BUY",
    order_type="LMT",
    price=0.50  # Net credit/debit
)

Combo Order Response

Successful combo order:

python
OrderResult(
    success=True,
    order_id='500500259',
    message=None,
    raw={
        'status': 'success',
        'result': [{
            'order_id': '500500259',
            'local_order_id': 'AQC-XXXX-1769654321000',
            'order_status': 'PreSubmitted'
        }]
    }
)

Error Handling

If IBKR rejects the combo, the SDK returns success=False with the error message:

python
OrderResult(
    success=False,
    order_id=None,
    message='Riskless combination orders are not allowed',
    raw={'error': 'Riskless combination orders are not allowed'}
)

Common rejection reasons:

  • "Riskless combination orders are not allowed" - Both legs have same strike/expiry
  • "The size of the order is invalid" - Quantity is 0 or negative
  • Missing exchange parameter - Legs don't specify routing exchange

How Combo Orders Work (Server-Side)

For combo orders, IBKR requires a spread conidex string. The server builds it as:

{spread_conid}@{exchange};;;{leg_conid1}/{signed_ratio},{leg_conid2}/{signed_ratio}
  • signed_ratio is positive for BUY legs and negative for SELL legs
  • For index options (e.g., SPXW), the server uses spread_conid=0 and the leg exchange (CBOE)
  • Final conidex example: 0@CBOE;;;843975599/-1,843975601/1

Options with conid

For options, always provide the conid:

python
# Get option conid first
contracts = client.get_option_contract(
    symbol="SPX", expiry="20260126", strike=6900, right="P", trading_class="SPXW"
)
opt_conid = contracts[0]["conid"]

# Place order with conid
result = client.buy_limit("SPX", 1, price=5.00, conid=opt_conid)