【TWS API 翻译系列】14、TWS API和IB中的账户和投资组合数据
作者:yunjinqi   类别:    日期:2022-01-03 22:18:21    阅读:1242 次   消耗积分:0 分    

账户和投资组合数据

TWS通过其账户和投资组合窗口提供您的账户和投资组合的全面概述。此信息可以使用 TWS API 通过三种不同类型的请求/操作获得:

Managed Accounts

单个用户名可以处理多个帐户。如"连接"部分所述,一旦建立连接,TWS 将自动发送管理帐户列表。该列表也可以通过IBApi.EClient.reqManagedAccts方法获取:

self.reqManagedAccts()

以上内容将导致通过IBApi.EWrapper.managedAccounts交付的以逗号分隔的帐户ID列表

class TestWrapper(wrapper.EWrapper):# ...
     def managedAccounts(self, accountsList: str):
         super().managedAccounts(accountsList)
         print("Account list:", accountsList)

**重要提示:**每当您的TWS用户名处理多个账户时,您将被迫指定需要分配订单的账户ID。如果不这样做,将导致订单被拒绝,因为TWS无法将订单分配给默认帐户。

Family Codes

从 API v973.02和 TWS v964开始,可以从 API 确定帐户家庭下是否存在帐户,并使用 reqFamilyCodes 函数查找家庭代码。

self.reqFamilyCodes()

如果管理账户是账户家庭的一部分(例如,财务顾问或IBroker下的个人账户),则该家族将返回到 IBApi::EWrapper:familyCodes功能。否则,它将返回一个空字符串。

def familyCodes(self, familyCodes: ListOfFamilyCode):
    super().familyCodes(familyCodes)
    print("Family Codes:")
    for familyCode in familyCodes:
        print("FamilyCode.", familyCode)

例如,如果个人账户 U112233 隶属于账户编号为 F445566 的财务顾问,则为账户 U112233 的用户调用 reqFamilyCodes 函数,则将返回家庭代码"F445566A",表明它属于该账户系列。

Account Updates

请求

IBApi.EClient.reqAccountUpdates功能创建对 TWS 的订阅,通过该订阅传递帐户和投资组合信息。此信息与TWS账户窗口中显示的信息完全相同。请注意,此函数接收特定帐户以及指示是启动还是停止订阅的标志。在单个科目结构中,科目编号不是必需的。与TWS的账户窗口一样,除非有头寸变化,否则此信息将以分钟的固定间隔更新。

self.reqAccountUpdates(True, self.account)

接收

由此产生的账户和投资组合信息将通过 IBApi.EWrapper.updateAccountValueIBApi.EWrapper.updatePortfolioIBApi.EWrapper.updateAccountTime 和IBApi.EWrapper.accountDownloadEnd提供

class TestWrapper(wrapper.EWrapper):#...
     def updateAccountValue(self, key: str, val: str, currency: str,
                            accountName: str):
         super().updateAccountValue(key, val, currency, accountName)
         print("UpdateAccountValue. Key:", key, "Value:", val,
               "Currency:", currency, "AccountName:", accountName)#...
     def updatePortfolio(self, contract: Contract, position: Decimal,
                         marketPrice: float, marketValue: float,
                         averageCost: float, unrealizedPNL: float,
                         realizedPNL: float, accountName: str):
         super().updatePortfolio(contract, position, marketPrice, marketValue,
                                 averageCost, unrealizedPNL, realizedPNL, accountName)
         print("UpdatePortfolio.", "Symbol:", contract.symbol, "SecType:", contract.secType, "Exchange:",
               contract.exchange, "Position:", decimalMaxString(position), "MarketPrice:", marketPrice,
               "MarketValue:", marketValue, "AverageCost:", averageCost,
               "UnrealizedPNL:", unrealizedPNL, "RealizedPNL:", realizedPNL,
               "AccountName:", accountName)#...
     def updateAccountTime(self, timeStamp: str):
         super().updateAccountTime(timeStamp)
         print("UpdateAccountTime. Time:", timeStamp)#...
     def accountDownloadEnd(self, accountName: str):
         super().accountDownloadEnd(accountName)
         print("AccountDownloadEnd. Account:", accountName)

取消

不再需要订阅帐户更新后,可以通过调用IBApi.EClient.reqAccountUpdates方法,同时将 susbcription 标志指定为 False 来取消订阅:

self.reqAccountUpdates(False, self.account)

**注意:**在调用IBApi.EClient.reqAccountUpdates后,在IBApi.EWrapper.updateAccountValue中传回的一个重要密钥是布尔值’accountReady’。如果返回账户Ready值为false,则表示IB服务器此时正在重置过程中,即账户"未准备好"。发生这种情况时,返回到IBApi::EWrapper::updateAccountValue 后续键值当前更新中的值可能已过期或不正确。

**重要提示:**一次只能订阅一个帐户。尝试第二个订阅而不事先取消活动订阅不会产生任何错误消息,尽管它会用新帐户覆盖已订阅的帐户。对于财务咨询(FA)帐户结构,有一种指定帐户代码的另一种方法,以便返回"所有"子帐户的信息 - 这是通过将字母"A"附加到帐号末尾来完成的,即reqAccountUpdates(true,“F123456A”)

标识帐户密钥

通过IBApi.EWrapper.updateAccountValue提供的账户价值可以按以下方式进行分类:

  • 商品:后缀为"-C"

  • 证券:后缀为"-S"

  • 总计:无后缀

欲了解更多信息,请参阅账户窗口。

按模型划分的帐户值更新订阅

IBApi.EClient.reqAccountUpdatesMulti可用于任何账户结构,以从一个或多个账户和/或模型同时创建账户价值订阅。与IBApi.EClient.reqAccountUpdates一样,返回的数据将与TWS帐户窗口中显示的数据相匹配。

self.reqAccountUpdatesMulti(9005, self.account, "", True)

由此产生的账户和投资组合信息将通过IBApi.EWrapper.accountUpdateMultiIBApi.EWrapper.accountUpdateMultiEnd提供。

class TestWrapper(wrapper.EWrapper):# ...
     def accountUpdateMulti(self, reqId: int, account: str, modelCode: str,
                            key: str, value: str, currency: str):
         super().accountUpdateMulti(reqId, account, modelCode, key, value,
                                    currency)
         print("AccountUpdateMulti. RequestId:", reqId, "Account:", account,
               "ModelCode:", modelCode, "Key:", key, "Value:", value,
               "Currency:", currency)# ...
     def accountUpdateMultiEnd(self, reqId: int):
         super().accountUpdateMultiEnd(reqId)
         print("AccountUpdateMultiEnd. RequestId:", reqId)

Account Summary

请求

IBApi.EClient.reqAccountSummary方法为"TWS 帐户摘要"窗口中显示的帐户数据创建订阅。它通常用于多账户结构。介绍经纪人(IBroker)账户拥有超过50个子账户或配置为按需账户查找,不能使用group="All"的reqAccountSummary。如果使用 TWS **v983+,**则可以接受配置文件名称代替组。请参阅组和配置文件的统一

IBApi.EClient.reqAccountUpdates不同,IBApi.EClient.reqAccountSummary不仅可以检索一个或所有管理帐户的汇总信息,还可以仅提取要由客户端应用程序监视的指定值。reqAccountSummary 的初始调用将导致返回所有请求值的列表,然后每隔三分钟将返回那些已更改的值。3分钟的更新频率与TWS账户窗口相同,无法更改。

self.reqAccountSummary(9001, "All", AccountSummaryTags.AllTags)

从TWS Build 956和IB网关956开始,我们添加了使用LEDGER标签分别请求每种货币的账户摘要数据(包括CashBalance 和TotalCashBalance)的功能。请参阅TWS 测试版发行说明

指定"$LEDGER"标签时,账户摘要数据将仅以基础货币返回。

self.reqAccountSummary(9002, "All", "$LEDGER")

指定"$LEDGER:货币"标记时,将仅以指定的货币返回帐户摘要数据。返回的现金平衡和总现金余额仅是您在TWS账户窗口中看到的该特定货币的余额。

例如:“LEDGER:美元"、"LEDGER""LEDGER:欧元”、"$LEDGER:港元"等。

self.reqAccountSummary(9003, "All", "$LEDGER:EUR")

指定"$LEDGER:ALL"标记时,返回的帐户摘要数据将汇总所有帐户和货币的值。

例:

账户 = 全部,货币 = 欧元,现金平衡 = 12345.67

账户 = 全部,货币 = 日元,现金平衡 = 987.54

self.reqAccountSummary(9004, "All", "$LEDGER:ALL")

重要提示:一次只允许个有效的摘要订阅!

接收

摘要信息通过IBApi.EWrapper.accountSummaryIBApi.EWrapper.accountSummaryEnd 提供

class TestWrapper(wrapper.EWrapper):# ...
     def accountSummary(self, reqId: int, account: str, tag: str, value: str,
                        currency: str):
         super().accountSummary(reqId, account, tag, value, currency)
         print("AccountSummary. ReqId:", reqId, "Account:", account,
               "Tag: ", tag, "Value:", value, "Currency:", currency)# ...
     def accountSummaryEnd(self, reqId: int):
         super().accountSummaryEnd(reqId)
         print("AccountSummaryEnd. ReqId:", reqId)

取消

一旦不再需要订阅帐户摘要,可以通过 IBApi::EClient::cancelAccountSummary方法取消订阅:

self.cancelAccountSummary(9001)self.cancelAccountSummary(9002)self.cancelAccountSummary(9003)self.cancelAccountSummary(9004)

Positions

请求

IBApi.EClient.reqAccountUpdates函数的一个限制是,它一次只能与单个帐户一起使用。要从多个账户创建仓位更新订阅,可以使用IBApi.EClient.reqPositions函数。

注意:要求仓位功能在介绍经纪人或财务顾问主账户中不可用,这些账户拥有大量子账户(>50个)来优化TWS / IB网关v973 +的性能。相反,函数 reqPositionsMulti 可用于订阅来自各个子帐户的更新。对于配置为按需帐户查找的 IBroker 帐户,也不可用。

在最初调用 reqPositions 后,将返回有关所有关联账户中所有仓位的信息,然后返回IBApi::EWrapper::positionEnd 回调。此后,当仓位发生更改时,更新将返回到IBApi::EWrapper::position 函数。要取消 reqPositions 订阅,请调用 IBApi::EClient::cancelPositions.

self.reqPositions()

接收

调用上述内容后,将通过IBApi.EWrapper.position回调接收仓位。在所有仓位的初始回调(仅)之后,将触发IBApi.EWrapper.positionEnd函数。

  • 对于期货,交易所字段不会填充在头寸回调中,因为某些期货在多个交易所进行交易

class TestWrapper(wrapper.EWrapper):# ...
     def position(self, account: str, contract: Contract, position: Decimal,
                  avgCost: float):
         super().position(account, contract, position, avgCost)
         print("Position.", "Account:", account, "Symbol:", contract.symbol, "SecType:",
               contract.secType, "Currency:", contract.currency,
               "Position:", decimalMaxString(position), "Avg cost:", avgCost)# ...
     def positionEnd(self):
         super().positionEnd()
         print("PositionEnd")

取消

要取消 reqPosition 订阅,请调用 IBApi::EClient::cancelPositions:

self.cancelPositions()

Position Update Subscription by Model

IBApi.EClient.reqPositionsMulti函数可与任何账户结构一起使用,以订阅多个账户和/或模型的头寸更新。如果没有多个科目或模型可用,则科目和模型参数是可选的。对特定账户子集使用此功能比使用IBApi.EClient.reqPositions更有效。如果使用TWS v983+,则可以接受配置文件名称代替科目参数中的组。请参阅组和配置文件的统一

self.reqPositionsMulti(9006, self.account, "")

调用IBApi.EClient.reqPositions 后,多个数据将返回到IBApi.EWrapper.positionMulti函数。在对与提供的条件匹配的所有仓位进行初始回调后,将触发IBApi.EWrapper.positionMultiEnd函数。此后,只有在发生更改时才会向 positionMulti 发送消息。要取消 positionMulti 订阅,函数IBApi.EClient.cancelPositionsMulti将使用用于创建订阅的相同请求 ID 进行调用。

class TestWrapper(wrapper.EWrapper):#...
     def positionMulti(self, reqId: int, account: str, modelCode: str,
                       contract: Contract, pos: Decimal, avgCost: float):
         super().positionMulti(reqId, account, modelCode, contract, pos, avgCost)
         print("PositionMulti. RequestId:", reqId, "Account:", account,
               "ModelCode:", modelCode, "Symbol:", contract.symbol, "SecType:",
               contract.secType, "Currency:", contract.currency, ",Position:",
               decimalMaxString(pos), "AvgCost:", avgCost)#...
     def positionMultiEnd(self, reqId: int):
         super().positionMultiEnd(reqId)
         print("PositionMultiEnd. RequestId:", reqId)

Profit And Loss (P&L)

账户窗口中的损益数据

未实现和已实现的损益在使用IBApi.EClient.reqAccountUpdates发出订阅请求后,将发送到API函数IBApi.EWrapper.updateAccountValue函数。此信息与TWS账户窗口中的数据相对应,并且与TWS投资组合窗口中的PnL数据和相关API函数(见下文)具有不同的信息来源,不同的更新频率和不同的重置计划。特别是,TWS账户窗口中显示的未实现损益信息(发送给updentPortfolioValue)将**(1)当该特定工具的交易发生时或(2)**每3分钟更新一次。TWS账户窗口中已实现的损益数据每天重置为 0 次。

  • 重要的是要记住,账户窗口和投资组合窗口中显示的损益数据有时会有所不同,因为有不同的信息来源和不同的重置时间表。

投资组合窗口中的损益数据

从 API v973.03 开始,可以发出请求以接收有关帐户或单个头寸的每日损益和未实现损益的实时更新。财务顾问还可以请求"所有"子账户或投资组合模型的损益数据。在 API v973.05+/TWS v968+ 中,这进一步扩展为包括帐户或个人职位级别的已实现损益信息。

下面演示的这些较新的损益 API 函数返回当前版本的 TWS (v963+) 中在 TWS投资组合窗口中显示的数据。因此,P&L 值是根据 TWS 全局配置中指定的重置计划(默认情况下是特定于仪器的重置计划)计算的,此设置也会影响发送到关联 API 函数的值。同样在TWS中,当且仅当账户窗口的虚拟Fx部分展开时,来自虚拟外汇头寸的损益数据将包含在账户损益表中。

  • 注意:Python API 中的 P&L 函数从 API v973.06+ 开始可用。

单个position的损益订阅请求

使用IBApi::EClient::reqPnLSingle函数进行订阅 不能与配置为按需查找且帐户 = ‘全部’ 的 IBroker 帐户一起使用

self.reqPnLSingle(17002, "DU111519", "", 8314);

目前,更新大约每秒返回一次到IBApi.EWrapper.pnlSingle。*将来可能会有变化

def pnlSingle(self, reqId: int, pos: Decimal, dailyPnL: float,
                   unrealizedPnL: float, realizedPnL: float, value: float):
    super().pnlSingle(reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value)
    print("Daily PnL Single. ReqId:", reqId, "Position:", decimalMaxString(pos),
               "DailyPnL:", dailyPnL, "UnrealizedPnL:", unrealizedPnL,
               "RealizedPnL:", realizedPnL, "Value:", value)
  • 如果针对不在帐户中的无效 conId 或合同发出损益订阅请求,则不会有响应。

  • 与 API 中的其他位置一样,最大双精度值将指示"未设置"值。这对应于TWS中的空单元格。

  • 没有大量子账户(<50)的介绍经纪人账户可以通过将账户指定为"全部"来接收汇总数据。

  • *不能与配置为按需查找且帐户 = ‘全部’ 的 IBroker 帐户一起使用

使用IBApi::EClient::cancelPnLSingle函数取消订阅:

self.cancelPnLSingle(17002);

帐户的损益订阅请求

使用 IBApi::EClient::reqPnL函数进行订阅:

self.reqPnL(17001, "DU111519", "")

  • 少于50个子账户的介绍经纪人账户可以通过指定"全部"作为账户代码来接收所有子账户的聚合PnL。

  • 对于具有许多子帐户和/或头寸的顾问帐户的请求,可能需要几秒钟才能计算和返回汇总的损益。

  • 对于账户损益数据,必须选中TWS设置"下载头寸时准备投资组合PnL数据"。

更新将发送到IBApi.EWrapper.pnl

def pnl(self, reqId: int, dailyPnL: float,
         unrealizedPnL: float, realizedPnL: float):
    super().pnl(reqId, dailyPnL, unrealizedPnL, realizedPnL)
    print("Daily PnL. ReqId:", reqId, "DailyPnL:", dailyPnL,
            "UnrealizedPnL:", unrealizedPnL, "RealizedPnL:", realizedPnL)

使用 IBApi::EClient::cancelPnL函数取消不必要的订阅:

self.cancelPnL(17001)

TWS API相关的教程

【TWS API使用教程1】—如何在自己创建的client和TWS之间创建一个连接,并请求当前的时间
【TWS API使用教程2】—如何使用 TWS API在ubuntu和windows上分别设置contract、获取contract详细信息、设置order、下单、获取持仓信息、获取账户信息
【TWS API使用教程3】—如何使用TWS API从盈透证券中设置contract及获取contract的信息?
【TWS API使用教程4】—如何使用TWS API在盈透证券中设置order?
【TWS API使用教程5】—如何使用TWS API在盈透证券中下单(place order)、获取订单信息、获取持仓、获取账户汇总信息?
【TWS API使用教程6】—如何使用TWS API在盈透证券中获取数据?
【TWS API 使用教程7】如何使用TWS API 从盈透证券中筛选满足一定条件的contract?
【TWS API 使用教程8】一个基于TWS API的简单的程序化策略


版权所有,转载本站文章请注明出处:云子量化, http://www.woniunote.com/article/80
上一篇:【TWS API 翻译系列】13、TWS API和IB中的历史数据
下一篇:【TWS API 翻译系列】15、TWS API和IB中的期权相关的操作