Getting parameters of listed options & futures in Interactive Brokers API

偶尔善良 提交于 2019-11-28 23:23:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!