52 lines
2.1 KiB
Python
52 lines
2.1 KiB
Python
import pandas as pd
|
|
|
|
from datetime import datetime
|
|
from exchange import SMART
|
|
from ib_insync import IB, Index, Option
|
|
from ib_insync.util import isNan
|
|
from market_data_type import LIVE
|
|
from typing import Callable
|
|
|
|
class Client:
|
|
|
|
def __init__(self, host: str, port: int, client_id = 1) -> None:
|
|
self.ib = IB()
|
|
self.ib.connect(host, port, clientId = client_id)
|
|
self.ib.reqMarketDataType(LIVE)
|
|
|
|
def get_ticker(self, symbol: str, exchange: str):
|
|
underlying = Index(symbol, exchange)
|
|
self.ib.qualifyContracts(underlying)
|
|
return self.ib.reqTickers(underlying)[0]
|
|
|
|
def get_option_chain(self, symbol: str, expiration: datetime, sub_symbol: str = None,
|
|
contract_filter: Callable = None) -> pd.DataFrame:
|
|
expiration_date = expiration.strftime('%Y%m%d')
|
|
contract_details = self.ib.reqContractDetails(Option(symbol, expiration_date, exchange = SMART))
|
|
contracts = [_.contract for _ in contract_details if not sub_symbol or _.contract.tradingClass == sub_symbol]
|
|
if contract_filter:
|
|
contracts = list(filter(contract_filter, contracts))
|
|
|
|
option_data = []
|
|
for contract in contracts:
|
|
option = Option(symbol, expiration_date, contract.strike, contract.right, exchange = SMART, currency = 'USD')
|
|
if sub_symbol:
|
|
option.tradingClass = sub_symbol
|
|
option_data_snapshot = self.ib.reqMktData(option, '', True, False)
|
|
option_data.append(option_data_snapshot)
|
|
|
|
option_chain = []
|
|
for option in option_data:
|
|
print('Processing Option: ', option)
|
|
while isNan(option.bid) or isNan(option.ask) or option.modelGreeks is None:
|
|
# TODO: Add a timeout?
|
|
self.ib.sleep()
|
|
option_chain.append({
|
|
'Strike': option.contract.strike,
|
|
'Type': option.contract.right, # 'C' for Call, 'P' for Put.
|
|
'Bid': option.bid,
|
|
'Ask': option.ask,
|
|
'Delta': option.modelGreeks.delta,
|
|
})
|
|
|
|
return pd.DataFrame(option_chain) |