问题
There are a lot of examples showing how to get particular asset's price from Interactive Brokers. However, when I want to get the whole chain of options for one asset, I don't know which particular strikes are listed. Same for futures, I don't know which expirations are available at the moment. So, i.e., for options, I just loop through all possible strikes and reqMktData
for each, also making a sleep(1)
every 100 messages to avoid hitting the limit for number of requests per second. Obviously, many of these messages return with error "No security definition has been found for the request".
This looks like the wrong approach as it wastes lots of time on non-existing assets. Is there any more clean way to do this, or a special function for such purpose?
回答1:
Implementing handler for contractDetailsEnd as suggested by Donn Lee. Thanks to both shashkello and Donn Lee.
from ib.ext.Contract import Contract
from ib.ext.ContractDetails import ContractDetails
from ib.opt import ibConnection, message
import time
def watcher(msg):
print msg
def contractDetailsHandler(msg):
contracts.append(msg.contractDetails.m_summary)
def contractDetailsEndHandler(msg):
global DataWait
DataWait = False
con = ibConnection()
con.registerAll(watcher)
con.register(contractDetailsHandler, 'ContractDetails')
con.register(contractDetailsEndHandler, 'ContractDetailsEnd')
con.connect()
contract = Contract()
contract.m_exchange = "SMART"
contract.m_secType = "OPT"
contract.m_symbol = "VTR"
#contract.m_multiplier = "100"
contract.m_currency = "USD"
con.reqContractDetails(1, contract)
contracts = [] # to store all the contracts
DataWait = True ; i = 0
while DataWait and i < 90:
i += 1 ; print i,
time.sleep(1)
con.disconnect()
con.close()
print contracts
回答2:
I started working with IbPy not that long ago and also saw the time.sleep
idiom in the samples and now in the answers above. Because ibpy
has a thread running in the background and the message receiving methods/functions are therefore called in that thread it seemed natural to move to a queue
based approach.
Here the code and below the output for the two contract specifications from above.
from __future__ import (absolute_import, division, print_function,)
# unicode_literals)
import sys
if sys.version_info.major == 2:
import Queue as queue
else: # >= 3
import queue
import ib.opt
import ib.ext.Contract
class IbManager(object):
def __init__(self, timeout=20, **kwargs):
self.q = queue.Queue()
self.timeout = 20
self.con = ib.opt.ibConnection(**kwargs)
self.con.registerAll(self.watcher)
self.msgs = {
ib.opt.message.error: self.errors,
ib.opt.message.contractDetails: self.contractDetailsHandler,
ib.opt.message.contractDetailsEnd: self.contractDetailsHandler
}
self.skipmsgs = tuple(self.msgs.keys())
for msgtype, handler in self.msgs.items():
self.con.register(handler, msgtype)
self.con.connect()
def watcher(self, msg):
if isinstance(msg, ib.opt.message.error):
if msg.errorCode > 2000: # informative message
print('-' * 10, msg)
elif not isinstance(msg, self.skipmsgs):
print('-' * 10, msg)
def errors(self, msg):
if msg.id is None: # something is very wrong in the connection to tws
self.q.put((True, -1, 'Lost Connection to TWS'))
elif msg.errorCode < 1000:
self.q.put((True, msg.errorCode, msg.errorMsg))
def contractDetailsHandler(self, msg):
if isinstance(msg, ib.opt.message.contractDetailsEnd):
self.q.put((False, msg.reqId, msg))
else:
self.q.put((False, msg.reqId, msg.contractDetails))
def get_contract_details(self, symbol, sectype, exch='SMART', curr='USD'):
contract = ib.ext.Contract.Contract()
contract.m_symbol = symbol
contract.m_exchange = exch
contract.m_currency = curr
contract.m_secType = sectype
self.con.reqContractDetails(1, contract)
cdetails = list()
while True:
try:
err, mid, msg = self.q.get(block=True, timeout=self.timeout)
except queue.Empty:
err, mid, msg = True, -1, "Timeout receiving information"
break
if isinstance(msg, ib.opt.message.contractDetailsEnd):
mid, msg = None, None
break
cdetails.append(msg) # must be contractDetails
# return list of contract details, followed by:
# last return code (False means no error / True Error)
# last error code or None if no error
# last error message or None if no error
# last error message
return cdetails, err, mid, msg
ibm = IbManager(clientId=5001)
cs = (
('VTR', 'OPT', 'SMART'),
('ES', 'FUT', 'GLOBEX'),
)
for c in cs:
cdetails, err, errid, errmsg = ibm.get_contract_details(*c)
if err:
print('Last Error %d: %s' % (errid, errmsg))
print('-' * 50)
print('-- ', c)
for cdetail in cdetails:
# m_summary is the contract in details
print('Expiry:', cdetail.m_summary.m_expiry)
sys.exit(0) # Ensure ib thread is terminated
The output:
Server Version: 76
TWS Time at connection:20160112 23:17:15 CET
---------- <managedAccounts accountsList=D999999>
---------- <nextValidId orderId=1>
---------- <error id=-1, errorCode=2104, errorMsg=Market data farm connection is OK:usfuture>
---------- <error id=-1, errorCode=2104, errorMsg=Market data farm connection is OK:eufarm>
---------- <error id=-1, errorCode=2104, errorMsg=Market data farm connection is OK:cashfarm>
---------- <error id=-1, errorCode=2104, errorMsg=Market data farm connection is OK:usfarm.us>
---------- <error id=-1, errorCode=2106, errorMsg=HMDS data farm connection is OK:ushmds.us>
---------- <error id=-1, errorCode=2106, errorMsg=HMDS data farm connection is OK:ilhmds>
---------- <error id=-1, errorCode=2106, errorMsg=HMDS data farm connection is OK:cashhmds>
---------- <error id=-1, errorCode=2106, errorMsg=HMDS data farm connection is OK:ethmds>
--------------------------------------------------
-- ('VTR', 'OPT', 'SMART')
Expiry: 20160219
Expiry: 20160219
...
...
...
Expiry: 20160819
Expiry: 20160819
--------------------------------------------------
-- ('ES', 'FUT', 'GLOBEX')
Expiry: 20160318
Expiry: 20160617
Expiry: 20160916
Expiry: 20161216
Expiry: 20170317
回答3:
Figured this out myself.
There is a function which is able to request the details of listed securities, reqContractDetails
. Some sample code requesting E-mini SPX futures (symbol ES) is shown below.
from ib.ext.Contract import Contract
from ib.ext.ContractDetails import ContractDetails
from ib.opt import ibConnection, message
import time
def watcher(msg):
print msg
contracts = [] # to store all the contracts
def contractDetailsHandler(msg):
contracts.append(msg.contractDetails.m_summary)
con = ibConnection()
con.registerAll(watcher)
con.register(contractDetailsHandler, 'ContractDetails')
con.connect()
contract = Contract()
contract.m_symbol = "ES"
contract.m_exchange = "GLOBEX"
contract.m_currency = "USD"
contract.m_secType = "FUT"
con.reqContractDetails(1, contract)
time.sleep(2)
con.disconnect()
Now the contracts are saved in the contracts
list, we can get all available expirations by:
for c in contracts:
print c.m_expiry
Output:
20140919
20141219
20150320
20150619
20150918
In an obvious way, this can be extended to options as well.
来源:https://stackoverflow.com/questions/25299539/getting-parameters-of-listed-options-futures-in-interactive-brokers-api