Appearance
Strategy Migration Guide
Use this when refactoring an ib_insync or ib_async strategy to the AQC SDK.
The goal is not just API translation. The goal is to preserve the original strategy's trading and operational behavior.
Core rule
Do not call a migration complete just because the script runs without exceptions.
For trading parity, verify:
- same expiry universe
- same exact contracts
- same pricing inputs
- same order lifecycle
- same restart and recovery behavior
Best practices
- Preserve the original decision path before cleaning up style.
- Keep the same config values first:
- DTE windows
- strike widths
- thresholds
- walk logic
- timeouts
- order budget
- For options, qualify on exact expiry, strike, and right.
- Keep
SMARTon IBKR option discovery and combo legs unless the original strategy explicitly used something else. - Treat the execution engine as part of runtime behavior, not just a transport layer.
- Reconcile live broker state on restart. Missing local state does not mean flat.
- For combo strategies, verify entry and exit leg directions, ratios, and exchanges exactly.
- Verify post-fill behavior explicitly:
- GTC placement
- stop placement
- pending-close reconciliation
- DTE-stop handling
Common mistakes
- Replacing exact expiries with approximate dates or month placeholders.
- Using endpoints that return
200but the wrong contract universe. - Omitting
SMARTin option secdef discovery or combo-leg exchange fields. - Porting only entry logic and forgetting exit, GTC, stop, or reconciliation logic.
- Assuming local
positions_fileorrisk_fileis the source of truth. - Treating endpoint health as strategy parity.
- Changing economic logic during the migration:
- capital basis
- carry treatment
- P&L math
- daily loss accounting
- Re-qualifying the same option contracts repeatedly inside one cycle when the original logic reused them.
Practical translation patterns
Quote
python
# ib_insync / ib_async
contract = Stock("QQQ", "SMART", "USD")
ib.qualifyContracts(contract)
# SDK
quote = await client.get_quote("QQQ")
price = float(quote.get("last") or quote.get("mid") or quote.get("close") or 0)Historical bars
python
# ib_insync / ib_async
bars = ib.reqHistoricalData(contract, endDateTime="", durationStr="2 M", barSizeSetting="1 day")
# SDK
bars = await client.get_historical_bars("QQQ", duration="2 M", bar_size="1 day")Positions and open orders
python
# ib_insync / ib_async
positions = ib.positions()
orders = ib.openTrades()
# SDK
positions = await client.get_positions()
orders = await client.get_open_trades()Contract order placement
python
# ib_insync / ib_async
trade = ib.placeOrder(contract, order)
# SDK
result = await client.place_contract_order(
contract,
side="BUY",
quantity=10,
order_type="MKT",
)Required parity checks
Before trusting a migrated strategy live, verify:
- Expiry parity:
- same DTE-filtered expiry set as the original
- Contract parity:
- same expiry, strike, right, and conid target
- Pricing parity:
- same quote and greeks inputs for selected legs
- Execution parity:
- same entry order shape
- same walk and cancel behavior
- same GTC or stop placement sequence
- State parity:
- same behavior after restart with live positions or open orders