ibpy获取投资组合信息:交互式代理、Python

ibpy获取投资组合信息:交互式代理、Python,python,ibpy,Python,Ibpy,我已成功编写代码,以使用代码从TWS演示版中提取有关我职位的信息: tws_conn = conn.Connection.create(port=7497, clientId=100) tws_conn.register( acct_update, msg.updateAccountValue, msg.updateAccountTime, msg.updatePortfolio) tws_conn.connect() tws_conn.req

我已成功编写代码,以使用代码从TWS演示版中提取有关我职位的信息:

    tws_conn = conn.Connection.create(port=7497, clientId=100)    
    tws_conn.register( acct_update, msg.updateAccountValue,  
    msg.updateAccountTime, msg.updatePortfolio)
    tws_conn.connect()
    tws_conn.reqPositions()
    tws_conn.reqAccountUpdates(True,'DU15181')
但是,它会将信息转储为:

<updatePortfolio contract=<Packages.IbPy.ib.ext.Contract.Contract object at 0x06B0FE30>, position=-10, marketPrice=3.4000001, marketValue=-3400.0, averageCost=334.345, unrealizedPNL=-56.55, realizedPNL=0.0, accountName=DU15181>

我想知道,如果列表中的每个条目本身就是一个列表,“列”的要求在某种程度上是模糊的,因为一个列表已经满足了要求,如果列表中的每个条目都是一个列表,那么如何将上述信息存储到一个数组中,并在不同的列中列出合同或股票代码、投资组合中的数量和购买价格(子列表中的每个索引位置始终包含相同的字段)

您收到的消息将发送到您在tws注册的回调。每个“转储”字段都可以使用“点”符号或类似dict的方法(如“键”、“值”和“项”)进行访问

主要的挑战是合同:IB提供了对大量交易所和不同交易资产的访问。“合同”对象(以及IB后端中的信息)似乎反映了提供对所有事物的统一/统一访问的努力,同时表明他们必须在现有基础设施的基础上进行构建

您提到了“股票代码”,所以我想您可能会对以下内容感到满意:IBM-STK-SMART,带有“ib”行业标准符号(第2个字段表示它是股票,第3个字段表示ib将使用智能路由进行订单和价格更新)

让我们看一个列表:

def acct_update(self, msg):
    # Assume the function is a method in a class with access to a member
    # 'portfolio' which is a list

    if isinstance(msg, ib.opt.message.updatePortfolio):
        c = msg.contract
        ticker = '%s-%s-%s' % (contract.m_symbol, c.m_secType, c.m_exchange)
        entry = [ticker]
        entry.extend(msg.values)
        self.portfolio.append(entry)
不幸的是,
ibpy
消息中的“keys”方法不是
classmethod
,但名称实际上是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
。在持有
帐户更新
方法的类中,您可以执行以下操作:

class MyClass(object):
    portfields = ['ticker'] + ib.opt.message.updatePortfolio.__slots__
import IB_API

print("Testing IB's API as an imported library:")

all_positions = IB_API.read_positions()
all_navs = IB_API.read_navs()

print("Test ended")
如果您不希望通过索引访问列表中的字段,而是希望使用ibpy已经提供的字段名称,那么还可以对dict进行dict

def __init__(self, ...)
    self.portfolio = collections.OrderedDict()

def acct_update(self, msg):
    # Assume the function is a method in a class with access to a member
    # 'portfolio' which is a list

    if isinstance(msg, ib.opt.message.updatePortfolio):
        c = msg.contract
        ticker = '%s-%s-%s' % (contract.m_symbol, c.m_secType, c.m_exchange)
        self.portfolio[ticker] = collections.OrderedDict(msg.items())
这将允许您按名称获取最新的股票行情信息,并按名称访问字段

如果您需要保存每台股票的历史记录

def __init__(self, ...)
    self.portfolio = collections.defaultdict(list)

def acct_update(self, msg):
    # Assume the function is a method in a class with access to a member
    # 'portfolio' which is a list

    if isinstance(msg, ib.opt.message.updatePortfolio):
        c = msg.contract
        ticker = '%s-%s-%s' % (contract.m_symbol, c.m_secType, c.m_exchange)
        self.portfolio[ticker].extend(msg.values())

您可以存储“项”而不是值,然后在需要时访问元组。

根据长度和主要更改添加另一个答案。考虑到我正在编写某段代码,我用它回答了另一个问题,并且稍加修改也可以用于公文包

代码:

来自未来导入(绝对导入、分割、打印功能)
#unicode(字符)
导入集合
导入系统
如果sys.version_info.major==2:
将队列作为队列导入
进口itertools
map=itertools.imap
其他:#>=3
导入队列
导入ib.opt
导入ib.ext合同
类管理器(对象):
定义初始化(自身,超时=20,**kwargs):
self.q=queue.queue()
self.timeout=20
self.con=ib.opt.ibConnection(**kwargs)
自我监控注册(自我监控)
self.msgs={
ib.opt.message.error:self.errors,
ib.opt.message.updatePortfolio:self.acct\u更新,
ib.opt.message.accountDownloadEnd:self.acct\u更新,
}
#从acctUpdate跳过已注册的加上嘈杂的
self.skipmsgs=元组(self.msgs.keys())+(
ib.opt.message.updateAccountValue,
ib.opt.message.updateAccountTime)
对于msgtype,self.msgs.items()中的处理程序:
self.con.register(处理程序,msgtype)
self.con.connect()
def监视程序(自我,消息):
如果isinstance(消息,ib.opt.message.error):
如果msg.errorCode>2000:#信息性消息
打印('-'*10,msg)
elif不存在(消息,self.skipmsgs):
打印('-'*10,msg)
def错误(self,msg):
如果msg.id为None:#与tws的连接出现严重错误
self.q.put((True,-1,‘与TWS的连接中断’)
elif msg.errorCode<1000:
self.q.put((True,msg.errorCode,msg.errorMsg))
def账户更新(自我,消息):
self.q.put((False,-1,msg))
def获取帐户更新(自我):
self.con.reqAccountUpdates(True,'D999999')
公文包=列表()
尽管如此:
尝试:
err,mid,msg=self.q.get(block=True,timeout=self.timeout)
队列除外。空:
err,mid,msg=True,-1,“接收信息超时”
打破
如果isinstance(消息,ib.opt.message.accountDownloadEnd):
打破
如果isinstance(msg,ib.opt.message.updatePortfolio):
c=味精合同
股票代码=“%s-%s-%s%”(c.m_符号,c.m_扇区类型,c.m_交换)
条目=collections.OrderedDict(msg.items())
#如果以后需要引用合同对象,请不要执行此操作
条目['contract']=ticker#用ticker替换对象
公文包追加(条目)
#返回合同详细信息列表,然后是:
#最后返回代码(False表示无错误/True错误)
#最后一个错误代码,如果没有错误,则为无
#最后一条错误消息,如果没有错误,则为无
#最后一条错误消息
返回组合,错误,中间,消息
ibm=IBMManager(客户端ID=5001)
公文包,err,errid,errmsg=ibm.get\u account\u update()
如果投资组合:
打印(“,”.join(公文包[0].keys()))
对于投资组合中的p:
打印(“,”.join(映射(str,p.values()))
系统退出(0)#确保ib线程已终止
结果

Server Version: 76
TWS Time at connection:20160113 00:15:29 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>

contract,position,marketPrice,marketValue,averageCost,unrealizedPNL,realizedPNL,accountName
IBM-STK-,10,25.0,250.0,210.0,40.0,0.0,D999999
服务器版本:76
连接时TWS时间:20160113 00:15:29 CET
---------- 
---------- 
---------- 
---------- 
---------- 
---------- 
---------- 
---------- 
---------- 
---------- 
合同、头寸、市场价格、市场价值、平均成本、未实现的DPNL、已实现的PNL、账户名称
IBM-STK-,10,25.0250.0210.0,40.0,0.0,D999999
最后两行可以直接导入(例如)Excel。或者,如果它是一个词典列表(打印出来的内容),则可以在脚本中进一步操作它。

Bes
accvalue = pd.DataFrame(callback.update_AccountValue, columns = ['key', 'value', 'currency', 'accountName']) #[:199]

portfolio = pd.DataFrame(callback.update_Portfolio, columns=['Contract ID','Currency', 'Expiry','Include Expired','Local Symbol','Multiplier','Primary Exchange','Right',
                                'Security Type','Strike','Symbol','Trading         Class','Position','Market Price','Market Value',
                                'Average Cost', 'Unrealised PnL', 'Realised PnL', 'Account Name'])

callback.update_AccountTime
print("AccountValue: \n" + str(accvalue))
print("portfolio: \n" + str(portfolio))
# Position Summary
tws.reqPositions()
time.sleep(2)
dat = pd.DataFrame(callback.update_Position, 
               columns=['Account','Contract ID','Currency','Exchange','Expiry',
                        'Include Expired','Local Symbol','Multiplier','Right',
                        'Security Type','Strike','Symbol','Trading Class',
                        'Position','Average Cost'])

dat[dat["Account"] == accountName]
print("Position Summary: \n" + str(dat))
# Interactive Brokers functions to import data

def read_positions(): #read all accounts positions and return DataFrame with information

    from ibapi.client import EClient 
    from ibapi.wrapper import EWrapper
    from ibapi.common import TickerId
    import pandas as pd

    class ib_class(EWrapper, EClient): 
        def __init__(self): 
            EClient.__init__(self, self)
            self.all_positions = pd.DataFrame([], columns = ['Account','Symbol', 'Quantity', 'Average Cost'])

        def position(self, account, contract, pos, avgCost):
            index = str(account)+str(contract.symbol)
            self.all_positions.loc[index]=account,contract.symbol,pos,avgCost

        def error(self, reqId:TickerId, errorCode:int, errorString:str):
            if reqId > -1:
                print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)

        def positionEnd(self):
            super().positionEnd()
            self.disconnect()

    ib_api = ib_class() 
    ib_api.connect("127.0.0.1", 7496, 0) 
    ib_api.reqPositions()
    current_positions = ib_api.all_positions
    ib_api.run()

    return(current_positions)


def read_navs(): #read all accounts NAVs

    from ibapi.client import EClient 
    from ibapi.wrapper import EWrapper
    from ibapi.common import TickerId
    import pandas as pd

    class ib_class(EWrapper, EClient): 
        def __init__(self): 
            EClient.__init__(self, self)
            self.all_accounts = pd.DataFrame([], columns = ['reqId','Account', 'Tag', 'Value' , 'Currency'])

        def accountSummary(self, reqId, account, tag, value, currency):
            if tag == 'NetLiquidationByCurrency':
                index = str(account)
                self.all_accounts.loc[index]=reqId, account, tag, value, currency

        def error(self, reqId:TickerId, errorCode:int, errorString:str):
            if reqId > -1:
                print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)

        def accountSummaryEnd(self, reqId:int):
                super().accountSummaryEnd(reqId)
                self.disconnect()

    ib_api = ib_class() 
    ib_api.connect("127.0.0.1", 7496, 0) 
    ib_api.reqAccountSummary(9001,"All","$LEDGER")
    current_nav = ib_api.all_accounts
    ib_api.run()

    return(current_nav)
import IB_API

print("Testing IB's API as an imported library:")

all_positions = IB_API.read_positions()
all_navs = IB_API.read_navs()

print("Test ended")