Add ability to submit combo option orders (e.g., spreads)

This commit is contained in:
moshferatu 2023-11-16 09:15:36 -08:00
parent 7e72def611
commit fe99f740a2
7 changed files with 81 additions and 6 deletions

View File

@ -0,0 +1,13 @@
from datetime import datetime
from ibkr import Client as IBKR, OptionLeg
from ibkr.option_type import CALL, PUT
from ibkr.order_action import BUY, SELL
client = IBKR()
symbol, sub_symbol = 'SPX', 'SPXW'
expiration = datetime.now()
short_leg = OptionLeg(symbol, expiration, 4525.0, CALL, SELL, sub_symbol)
long_leg = OptionLeg(symbol, expiration, 4550.0, CALL, BUY, sub_symbol)
client.submit_combo_option_order([short_leg, long_leg], 1)

View File

@ -1 +1,2 @@
from .client import Client from .client import Client
from .option_leg import OptionLeg

View File

@ -1,15 +1,18 @@
import pandas as pd import pandas as pd
from datetime import datetime from datetime import datetime
from .exchange import SMART from ib_insync import ComboLeg, Contract, IB, Index, Option, Order
from ib_insync import Contract, IB, Index, Option
from ib_insync.util import isNan from ib_insync.util import isNan
from typing import Callable, List
from .currency import USD
from .exchange import SMART
from .market_data_type import LIVE from .market_data_type import LIVE
from typing import Callable from .option_leg import OptionLeg
class Client: class Client:
def __init__(self, host: str, port: int, client_id = 1) -> None: def __init__(self, host: str = '127.0.0.1', port: int = 7497, client_id = 1) -> None:
self.ib = IB() self.ib = IB()
self.ib.connect(host, port, clientId = client_id) self.ib.connect(host, port, clientId = client_id)
self.ib.reqMarketDataType(LIVE) self.ib.reqMarketDataType(LIVE)
@ -57,4 +60,45 @@ class Client:
'Delta': option.modelGreeks.delta, 'Delta': option.modelGreeks.delta,
}) })
return pd.DataFrame(option_chain) return pd.DataFrame(option_chain)
def get_option_contract(self, option_leg: OptionLeg) -> Option:
expiration_date = option_leg.expiration.strftime('%Y%m%d')
option_contract = Option(
option_leg.symbol,
expiration_date,
option_leg.strike,
option_leg.option_type,
exchange = SMART,
currency = USD
)
if option_leg.sub_symbol:
option_contract.tradingClass = option_leg.sub_symbol
self.ib.qualifyContracts(option_contract)
return option_contract
def submit_combo_option_order(self, legs: List[OptionLeg], quantity: int) -> None:
combo_legs = []
for leg in legs:
option_contract = self.get_option_contract(leg)
combo_leg = ComboLeg()
combo_leg.conId = option_contract.conId
combo_leg.ratio = 1
combo_leg.action = leg.action
combo_leg.exchange = SMART
combo_legs.append(combo_leg)
combo_contract = Contract()
combo_contract.symbol = legs[0].symbol # Assuming all legs are for the same symbol.
combo_contract.secType = 'BAG'
combo_contract.currency = USD
combo_contract.exchange = SMART
combo_contract.comboLegs = combo_legs
combo_order = Order()
combo_order.action = 'BUY' # TODO: Document the logic behind this.
combo_order.orderType = 'MKT' # TODO: Limit order support.
combo_order.totalQuantity = quantity
combo_order.transmit = True
self.ib.placeOrder(combo_contract, combo_order)

1
ibkr/currency.py Normal file
View File

@ -0,0 +1 @@
USD = 'USD'

12
ibkr/option_leg.py Normal file
View File

@ -0,0 +1,12 @@
from dataclasses import dataclass
from datetime import datetime
from typing import Literal
@dataclass
class OptionLeg:
symbol: str
expiration: datetime
strike: float
option_type: Literal['C', 'P']
action: Literal['BUY', 'SELL']
sub_symbol: str = None

2
ibkr/option_type.py Normal file
View File

@ -0,0 +1,2 @@
CALL = 'C'
PUT = 'P'

2
ibkr/order_action.py Normal file
View File

@ -0,0 +1,2 @@
BUY = 'BUY'
SELL = 'SELL'