簡體   English   中英

不使用Ibpy的IB API Python示例

[英]IB API Python sample not using Ibpy

有人可以通過使用IB API Python套接字幫助我弄清楚如何做基本請求嗎? (我使用最新的IB API,它似乎支持Python,所以不應該使用人們過去使用的Ibpy)

像這樣的代碼可以簡單地工作並使其連接到TWS。 問題是:我不知道如何“看到”從IB發回的消息。

from ibapi import wrapper
from ibapi.client import EClient
from ibapi.contract import *


w = wrapper.EWrapper()
myTWS = EClient(w)
myTWS.connect(host='localhost', port=7496, clientId=100)

print("serverVersion:%s connectionTime:%s" % (myTWS.serverVersion(),
                                          myTWS.twsConnectionTime()))
myTWS.startApi()


c = Contract()
c.m_symbol = "AAPL"
c.m_secType = "STK"
c.m_exchange = "ISLAND"
c.m_currency = "USD"


myTWS.reqRealTimeBars(999, c, 5, "MIDPOINT", True, [])

我知道它之前就像是IBPy之類的Register()。 我只是不知道如何在當前的IB原始python API中做到這一點。 給我一個簡單的例子可以幫助別人嗎? 提前致謝。

有一個新項目簡化了Python TWS Api的工作。

它被稱為IB-insync,它允許同步和異步處理。 對於TWS API中的新手來說,這看起來非常棒。 鏈接到項目頁面

使用IB-insync請求歷史數據的示例:

from ib_insync import *

ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1)

contract = Forex('EURUSD')
bars = ib.reqHistoricalData(contract, endDateTime='', durationStr='30 D',
    barSizeSetting='1 hour', whatToShow='MIDPOINT', useRTH=True)

# convert to pandas dataframe:
df = util.df(bars)
print(df[['date', 'open', 'high', 'low', 'close']])

您必須子類化/覆蓋/實現wrapper.EWrapper。 這就是你告訴EClient發送從TWS收到的數據的地方。

我從示例程序中刪除了幾乎所有內容,然后運行。

from ibapi import wrapper
from ibapi.client import EClient
from ibapi.utils import iswrapper #just for decorator
from ibapi.common import *
from ibapi.contract import *
from ibapi.ticktype import *

class TestApp(wrapper.EWrapper, EClient):
    def __init__(self):
        wrapper.EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)

    @iswrapper
    def nextValidId(self, orderId:int):
        print("setting nextValidOrderId: %d", orderId)
        self.nextValidOrderId = orderId
        #here is where you start using api
        contract = Contract()
        contract.symbol = "AAPL"
        contract.secType = "STK"
        contract.currency = "USD"
        contract.exchange = "SMART"
        self.reqMktData(1101, contract, "", False, None)

    @iswrapper
    def error(self, reqId:TickerId, errorCode:int, errorString:str):
        print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)

    @iswrapper
    def tickPrice(self, reqId: TickerId , tickType: TickType, price: float,
                  attrib:TickAttrib):
        print("Tick Price. Ticker Id:", reqId, "tickType:", tickType, "Price:", price)
        #this will disconnect and end this program because loop finishes
        self.done = True

def main():
    app = TestApp()
    app.connect("127.0.0.1", 7496, clientId=123)
    print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
                                                app.twsConnectionTime()))
    app.run()

if __name__ == "__main__":
    main()

一旦你調用app.run() ,程序就會啟動一個幾乎無限循環讀取消息,所以你需要一些其他方法來構建程序,因為必須啟動循環。

我已經找到了如何處理app對象之外的請求序列的方法。

這是我對Brian的代碼的一點修改(感謝Brian介紹如何使用它),它獲得了兩個合同細節,首先是它請求MSFT的合同細節,然后是IBM。

  • app.run()在收到所有contractDetails消息后通過在contractDetailsEnd()方法中設置app.done = True來完成
  • 當app.done設置為True時,客戶端將在EClient.run()方法中斷開連接。 我沒有想出如何在不斷開連接的情況下退出EClient.run()方法,所以我在client.py EClient.run()方法的源代碼中更改了退出:

     finally: #self.disconnect() # Myk prevent disconnect return #Myk instead of disconnect return 
  • 之后app.run()完成而沒有斷開連接並且可以再次調用,但是你必須首先將app.done設置為False,否則run()方法退出
  • 你必須自己斷開連接
  • disconnect()方法拋出錯誤,但有人說它似乎你可以忽略它,特別是如果你在代碼的末尾斷開連接

如果有人在不更改API源代碼的情況下知道更好的方法,如果您給我一個建議我會很高興。

這是代碼:

from ibapi import wrapper
from ibapi.client import EClient
from ibapi.utils import iswrapper #just for decorator
from ibapi.common import *
from ibapi.contract import *
from ibapi.ticktype import *

class TestApp(wrapper.EWrapper, EClient):
    def __init__(self):
        wrapper.EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)
        self.reqIsFinished = True
        self.started = False
        self.nextValidOrderId = 0

    @iswrapper
    def nextValidId(self, orderId:int):
        print("setting nextValidOrderId: %d", orderId)
        self.nextValidOrderId = orderId
        # we can start now

    @iswrapper
    def error(self, reqId:TickerId, errorCode:int, errorString:str):
        print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " ,     errorString)

    @iswrapper
    # ! [contractdetails]
    def contractDetails(self, reqId: int, contractDetails: ContractDetails):
        super().contractDetails(reqId, contractDetails)
        print("ContractDetails. ReqId:", reqId, contractDetails.summary.symbol,
              contractDetails.summary.secType, "ConId:", contractDetails.summary.conId,
          "@", contractDetails.summary.exchange)
        # ! [contractdetails]

    @iswrapper
    # ! [contractdetailsend]
    def contractDetailsEnd(self, reqId: int):
        super().contractDetailsEnd(reqId)
        print("ContractDetailsEnd. ", reqId, "\n")
        self.done = True  # This ends the messages loop
        # ! [contractdetailsend]

def main():
    app = TestApp()
    app.connect("127.0.0.1", 4001, clientId=123)
    print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
                                            app.twsConnectionTime()))

    print('MSFT contract details:')
    contract = Contract()
    contract.symbol = "MSFT"
    contract.secType = "STK"
    contract.currency = "USD"
    contract.exchange = ""
    app.reqContractDetails(210, contract)
    app.run()

    print('IBM contract details:')
    contract.symbol = "IBM"
    app.done = False # must be set before next run
    app.reqContractDetails(210, contract)
    app.run()

    app.disconnect() 

if __name__ == "__main__":
    main()

這是如何使用多線程處理API消息的示例。 app.run()作為單獨的線程啟動,它正在偵聽TWS API響應。 然后主程序發送5個ContractDetails請求,然后主程序等待響應10秒。 當響應准備好處理時,TWS API消息存儲在app實例和簡單信號量信號中。

這是我的第一個多線程程序,歡迎任何評論。

from ibapi import wrapper
from ibapi.client import EClient
from ibapi.utils import iswrapper #just for decorator
from ibapi.common import *
from ibapi.contract import *
from ibapi.ticktype import *
#from OrderSamples import OrderSamples
import threading
import time

class myThread (threading.Thread):
   def __init__(self, app, threadID, name):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.app = app

   def run(self):
      print ("Starting application in separate thread:", self.name,     "threadID:", self.threadID  )
      self.app.run()
      print ("Exiting " + self.name)

class TestApp(wrapper.EWrapper, EClient):
    def __init__(self):
        wrapper.EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)
        self.started = False
        self.nextValidOrderId = 0
        self.reqData = {}       # store data returned by requests
        self.reqStatus = {}     # semaphore of requests - status End will indicate request is finished


@iswrapper
def nextValidId(self, orderId:int):
    print("setting nextValidOrderId: %d", orderId)
    self.nextValidOrderId = orderId


@iswrapper
def error(self, reqId:TickerId, errorCode:int, errorString:str):
    print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)

@iswrapper
# ! [contractdetails]
def contractDetails(self, reqId: int, contractDetails: ContractDetails):
    super().contractDetails(reqId, contractDetails)
    # store response in reqData dict, for each request several objects are appended into list
    if not reqId in self.reqData:
        self.reqData[reqId] = []
    self.reqData[reqId].append(contractDetails) # put returned data into data storage dict
    # ! [contractdetails]

@iswrapper
# ! [contractdetailsend]
def contractDetailsEnd(self, reqId: int):
    super().contractDetailsEnd(reqId)
    print("ContractDetailsEnd. ", reqId, "\n")  # just info
    self.reqStatus[reqId] = 'End'               # indicates the response is ready for further processing
    # ! [contractdetailsend]



def main():

    app = TestApp()
    app.connect("127.0.0.1", 4001, clientId=123)
    print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
                                            app.twsConnectionTime()))

    thread1App = myThread(app, 1, "Thread-1")  # define thread for sunning app
    thread1App.start()                         # start app.run(] as infitnite loop in separate thread

    print('Requesting MSFT contract details:')
    contract = Contract()
    contract.symbol = "MSFT"
    contract.secType = "STK"
    contract.currency = "USD"
    contract.exchange = ""
    app.reqStatus[210] = 'Sent'   # set request status to "sent to TWS"
    app.reqContractDetails(210, contract)

    print('Requesting IBM contract details:')
    contract.symbol = "IBM"
    app.reqStatus[211] = 'Sent'          
    app.reqContractDetails(211, contract)

    print('Requesting IBM contract details:')
    contract.symbol = "GE"
    app.reqStatus[212] = 'Sent'
    app.reqContractDetails(212, contract)

    print('Requesting IBM contract details:')
    contract.symbol = "GM"
    app.reqStatus[213] = 'Sent'
    app.reqContractDetails(213, contract)

    print('Requesting IBM contract details:')
    contract.symbol = "BAC"
    app.reqStatus[214] = 'Sent'
    app.reqContractDetails(214, contract)

    i = 0
    while i < 100:         # exit loop after 10 sec (100 x time.sleep(0.1)
        i = i+1
        for reqId in app.reqStatus:
            if app.reqStatus[reqId] == 'End':
                for contractDetails in app.reqData[reqId]:
                    print("ContractDetails. ReqId:", reqId, contractDetails.summary.symbol,
                  contractDetails.summary.secType, "ConId:", contractDetails.summary.conId,
                  "@", contractDetails.summary.exchange)
                app.reqStatus[reqId] = 'Processed'
        time.sleep(0.1)
    app.done = True             # this stops app.run() loop

if __name__ == "__main__":
    main()

暫無
暫無

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

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