簡體   English   中英

如何使用 Python API 獲取我在盈透證券的賬戶頭寸?

[英]How do I get my accounts' positions at Interactive Brokers using Python API?

編輯:我找到了有關錯誤消息的解決方案 - 這是 IB 的 API 上的錯誤。 我在下面作為答案顯示的代碼對於那些正在尋找從他們在 IB 的賬戶中讀取頭寸和資產凈值的干凈解決方案的人來說應該很有用。

最初的問題[見下面的解決方案; 在此處留下原始問題以獲取上下文]:我正在嘗試使用公司的 API 獲取我在盈透證券 [IB] 的所有賬戶頭寸。 他們的文檔雖然廣泛,但非常令人困惑。 示例代碼充滿了不必要的命令——我想要一些非常精簡的東西。

我需要幫助:

  1. 如何獲取“每個帳戶”的信息 [已解決]
  2. 如何將變量帶入 DataFrame [已解決]
  3. 如何避免IB的API打印一系列錯誤信息[已解決]

到目前為止的代碼:

from ibapi.client import EClient 
from ibapi.wrapper import EWrapper
from ibapi.common import * #for TickerId type
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):
        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()

當我運行上面的代碼時,我會得到一系列 (i) 帳號、(ii) 合約代碼、(iii) 頭寸和 (iv) 平均成本。 因此,這回答了問題 #1。 您可能想要“打印”這些值以查看 IB 的 API 如何向您發送信息。

我還能夠定義一個 DataFrame 變量all_positions來接收我正在尋找的信息。 看看下面的結果。 請注意,我必須創建一個“索引”變量,它是 DataFrame 每一行的唯一標識符(作為帳號和符號的組合)。 如果沒有這個“索引”,我沒有找到將信息“附加”到 DataFrame 的方法(歡迎任何關於如何做的想法):

在此處輸入圖片說明

至於最后一個問題(錯誤消息):

Brian 對“error”函數的建議(見下文)消除了“-1”錯誤。 但我仍然得到以下信息:

EReader 線程 Traceback 中未處理的異常(最近一次調用最后一次):文件“C:\\Users\\danil\\Anaconda3\\lib\\site-packages\\ibapi-9.76.1-py3.7.egg\\ibapi\\reader.py”,行34、在運行data = self.conn.recvMsg()文件“C:\\Users\\danil\\Anaconda3\\lib\\site-packages\\ibapi-9.76.1-py3.7.egg\\ibapi\\connection.py”,行99、在recvMsg buf = self._recvAllMsg()文件“C:\\Users\\danil\\Anaconda3\\lib\\site-packages\\ibapi-9.76.1-py3.7.egg\\ibapi\\connection.py”,第119行,在 _recvAllMsg buf = self.socket.recv(4096) OSError: [WinError 10038] 嘗試對不是套接字的東西進行操作

經過大量實驗,這是我編寫的最終代碼,我將其放置在名為 AB_API 的“.py”文件中(因此我可以將其“導入”為庫):

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
    from threading import Thread

    import pandas as pd
    import time

    class ib_class(EWrapper, EClient):

        def __init__(self):
            EClient.__init__(self, self)

            self.all_positions = pd.DataFrame([], columns = ['Account','Symbol', 'Quantity', 'Average Cost', 'Sec Type'])

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

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

    def run_loop():
        app.run()
    
    app = ib_class()
    app.connect('127.0.0.1', 7496, 0)
    #Start the socket in a thread
    api_thread = Thread(target=run_loop, daemon=True)
    api_thread.start()
    time.sleep(1) #Sleep interval to allow time for connection to server

    app.reqPositions() # associated callback: position
    print("Waiting for IB's API response for accounts positions requests...\n")
    time.sleep(3)
    current_positions = app.all_positions
    current_positions.set_index('Account',inplace=True,drop=True) #set all_positions DataFrame index to "Account"
    
    app.disconnect()

    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
    from threading import Thread

    import pandas as pd
    import time

    class ib_class(EWrapper, EClient):

        def __init__(self):
            EClient.__init__(self, self)

            self.all_accounts = pd.DataFrame([], columns = ['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 accountSummary(self, reqId, account, tag, value, currency):
            index = str(account)
            self.all_accounts.loc[index]=reqId, account, tag, value, currency

    def run_loop():
        app.run()
    
    app = ib_class()
    app.connect('127.0.0.1', 7496, 0)
    #Start the socket in a thread
    api_thread = Thread(target=run_loop, daemon=True)
    api_thread.start()
    time.sleep(1) #Sleep interval to allow time for connection to server

    app.reqAccountSummary(0,"All","NetLiquidation")  # associated callback: accountSummary / Can use "All" up to 50 accounts; after that might need to use specific group name(s) created on TWS workstation
    print("Waiting for IB's API response for NAVs requests...\n")
    time.sleep(3)
    current_nav = app.all_accounts
    
    app.disconnect()

    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()

如果要運行非常快速的測試(不導入/調用函數),請在 read_positions() 和 read_navs()下方執行以下操作:

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

all_positions = read_positions()
print(all_positions)
print()
all_navs = read_navs()
print(all_navs)

我意識到一些用戶對導入函數的概念感到困惑,因此上面的快速建議。

我希望盈透證券能夠為客戶提供一些簡單的示例,讓用戶可以更輕松地測試一些想法並決定是否要使用他們的 API。

我得到的錯誤是由 IB 的 API 上的一個錯誤產生的(你可以看到我問的關於特定錯誤的另一個問題)。 我添加這個答案是為了提供關於如何降級到舊版本的更清晰的步驟:

1) 從這里下載舊版本: http : //interactivebrokers.github.io/downloads/TWS%20API%20Install%20974.01.msi

IB 不顯示舊版本的鏈接,但他們將文件保存在 Github 上(注意鏈接地址末尾的版本名稱)

2) 卸載當前版本。 在 IB 自己的網站上,執行以下操作:

  • 像往常一樣從 Windows 控制面板中的Add/Remove工具卸載 API
  • 如果仍有任何文件,請刪除C:\\TWS API\\文件夾以防止版本不匹配。
  • 找到文件C:\\Windows\\SysWOW64\\TwsSocketClient.dll 刪除此文件。 [沒有找到這個文件]
  • 在安裝不同的 API 版本之前重新啟動計算機。

3) 使用 .msi 文件安裝 API

4) 運行 Anaconda 提示符並導航到dir C:\\TWS API\\source\\pythonclient

5)運行: python setup.py install

6)安裝python setup.py后,重啟Spyder(如果它已經打開;我在上面的步驟#5之前關閉了我的)

我安裝這個舊版本后,錯誤消失了! 現在我的控制台上的輸出又干凈了!

你的代碼沒問題。 如果您想忽略錯誤,只需覆蓋錯誤回調即可。

from ibapi.common import * #for TickerId type

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

錯誤 > -1 用於需要 ID 的操作。

如果您正在獲取數據或下訂單,我仍然會跟蹤連接狀態。

您初始化 ddf 兩次。 您還調用 super ,它只記錄我認為的數據。

斷開連接時的套接字錯誤是一個錯誤,或者只是它們在 IB 上的處理方式。 它應該已經修復,但它可能需要一段時間才能發布。 也許嘗試更新,我在 4 月 26 日看到了修復它的拉取請求。

編輯:我找到了有關錯誤消息的解決方案-這是IB API上的錯誤。 我在下面作為答案給出的代碼對於那些希望使用干凈的解決方案以從其在IB賬戶中讀取頭寸以及資產凈值的人員來說應該是有用的。

原始問題[請參見下面的解決方案;請參見下面的“解決方案”。 在此離開原始問題]:我正在嘗試使用該公司的API來獲取我在盈透證券[IB]的所有賬戶頭寸。 他們的文檔盡管內容廣泛,卻極為混亂。 示例代碼中充滿了不必要的命令-我想要一些非常精簡的東西。

我需要以下方面的幫助:

  1. 如何獲取“每個帳戶”信息[已解決]
  2. 如何將變量帶到DataFrame [已解決]
  3. 如何避免IB的API打印一系列錯誤消息[已解決]

到目前為止的代碼:

from ibapi.client import EClient 
from ibapi.wrapper import EWrapper
from ibapi.common import * #for TickerId type
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):
        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()

當我運行上面的代碼時,我得到一系列的(i)帳號,(ii)合約符號,(iii)頭寸和(iv)平均成本。 因此,這回答了問題1。 您可能需要“打印”這些值,以查看IB的API如何向您發送信息。

我還能夠定義一個DataFrame變量all_positions來接收我正在尋找的信息。 請參閱下面的結果。 請注意,我必須創建一個“索引”變量,該變量是DataFrame每行的唯一標識符(作為帳號和符號的組合)。 沒有這種“索引”,我找不到將信息“附加”到DataFrame的方法(歡迎任何有關如何做的想法):

在此處輸入圖片說明

至於最后一個問題(錯誤消息):

Brian關於“錯誤”功能的建議(見下文)擺脫了“ -1”錯誤。 但是我仍然得到以下信息:

EReader線程回溯中未處理的異常(最近一次調用為最新):文件“ C:\\ Users \\ danil \\ Anaconda3 \\ lib \\ site-packages \\ ibapi-9.76.1-py3.7.egg \\ ibapi \\ reader.py”,行34,在運行數據中= self.conn.recvMsg()文件“ C:\\ Users \\ danil \\ Anaconda3 \\ lib \\ site-packages \\ ibapi-9.76.1-py3.7.egg \\ ibapi \\ connection.py”,行99,在recvMsg buf = self._recvAllMsg()文件“ C:\\ Users \\ danil \\ Anaconda3 \\ lib \\ site-packages \\ ibapi-9.76.1-py3.7.egg \\ ibapi \\ connection.py”中,第119行,在_recvAllMsg中buf = self.socket.recv(4096)OSError:[WinError 10038]嘗試對非套接字的對象進行操作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM