2017-04-26 15 views
1

私は新しいPythonのインタラクティブ・ブローカーのAPIをしようとしていますが、私は非常に最初の段階でいくつかの深刻なスピードの問題が発生しています...PythonのインタラクティブブローカーIBのAPIは非常に非常に遅い

次のコード(下記参照)回

0:00:08.832813アプリが完全に切断されるまで、データが

​​を受信して​​完了するまで...

なぜそれがとても遅いのですか? これをスピードアップするにはどうすればよいでしょうか?

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 * 
import datetime 
from datetime import timedelta 


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

    @iswrapper 
    def historicalData(self, reqId: TickerId, date: str, open: float, high: float, 
          low: float, close: float, volume: int, barCount: int, 
          WAP: float, hasGaps: int): 
     super().historicalData(reqId, date, open, high, low, close, volume, 
           barCount, WAP, hasGaps) 
     print("HistoricalData. ", reqId, " Date:", date, "Open:", open, 
       "High:", high, "Low:", low, "Close:", close, "Volume:", volume) 

    @iswrapper 
    def historicalDataEnd(self, reqId: int, start: str, end: str): 
     super().historicalDataEnd(reqId, start, end) 
     print("HistoricalDataEnd ", reqId, "from", start, "to", end) 
     print(datetime.datetime.now()-startime) 
     self.done = True # This ends the messages loop - this was not in the example code... 

    def get_data(self):   
     self.connect("127.0.0.1", 4002, clientId=10) 
     print("serverVersion:%s connectionTime:%s" % (self.serverVersion(), 
               self.twsConnectionTime())) 

     cont = Contract() 
     cont.symbol = "ES" 
     cont.secType = "FUT" 
     cont.currency = "USD" 
     cont.exchange = "GLOBEX" 
     cont.lastTradeDateOrContractMonth = "201706" 
     self.reqHistoricalData(1, cont, datetime.datetime.now().strftime("%Y%m%d %H:%M:%S"), 
           "1800 S", "30 mins", "TRADES", 0, 1, []) 
     self.run()   
     self.disconnect() 
     print(datetime.datetime.now()-startime) 

global starttime 
startime = datetime.datetime.now() 
DA = DataApp() 
DA.get_data() 

は、私はまた、唯一の

def runMe(): 
    app.run() # where run() has be removed from the class definition 

import threading 
thread = threading.Thread(target = runMe) 
thread.start() 

と、その場でリクエストを提出するために、継続的にそれがバックグラウンドで実行しようとした。しかし、それはまた、信じられないほど遅かったです。 任意の提案はapp.done == Falseながら、無限ループですが、app.doneがTrueに設定されている場合、それはすぐに停止しない

答えて

-1

app.run()を高く評価しました。 (どうしてか分かりません)。

私が行ったことは、app.run()の代わりに新しい方法を書くことです。

は、ここに私のソリューションです:

import time 
from ibapi import (decoder, reader, comm) 

とあなたのクライアントクラスにこの機能を置きます。

def getMessage(self, wait=3): 
    # wait 3 secs for response to come in 
    time.sleep(wait) 
    # get everything in app.msg_queue 
    while not self.msg_queue.empty(): 
     text = self.msg_queue.get(block=True, timeout=0.2) 
     fields = comm.read_fields(text) 
     self.decoder.interpret(fields) 

使い方は簡単です。 app.run()の代わりにapp.getMessage()を使用してください

2

ibapiモジュールの接続クラス内の接続ソケットロックを変更することをお勧めします。推薦はギトッブの上のヘシムから来た。私的なインタラクティブブローカーリポジトリへのアクセス権があれば、こちらのディスカッションにアクセスできますhttps://github.com/InteractiveBrokers/tws-api/issues/464

これを実行してパフォーマンスが大幅に向上しました。

Heshimingは、メッセージを送受信するたびに呼び出されるソケットロックオブジェクトのタイムアウトを減らすことをお勧めします。 ソケットロックを変更するには、ibapiのsite-packagesフォルダに移動し、connection.py内のconnect関数を変更して、 "self.socket.settimeout(1)"を "self.socket.settimeout(0.01)"に変更します。これは私が持っているバージョンのconnection.pyの48行目です。

heshimingの投稿が表示されない場合は、この投稿の末尾に追加しました。

代替オプション:別の興味深い解決策は、asyncioを非同期イベントループに利用することです。私はこれをしていないが、それは有望に見える。例エワルドは、一緒にhttps://github.com/erdewit/tws_async

Heshimingコメントを入れてください:

/ibapi/connection.py接続の実装はSENDMSGとrecvmsgの両方で共有ロックを目的としています。接続後、 self.socket.settimeout(1)が呼び出されるため、基礎となる self.socket.recv(4096)は1秒に1回のみタイムアウトします。

このような実装では、パフォーマンスの問題が発生します。ロックは が共有されているため、ソケットは受信中にデータを送信できません。受信メッセージの長さが4KB未満のシナリオ では、recvMsg 関数はロックを解除する前に1秒間待機し、 以降のsendMsgを待機させます。私の実験では、ほとんどのメッセージは、4kバイトより短い であるように見えます。言い換えれば、これは1秒あたり1つの recvMsgの上限を課します。

これを軽減する方法がいくつかあります。 受信バッファを4kよりはるかに少ない数に減らすか、またはソケットを タイムアウトを0.001秒に減らしてブロックを少なくします。

または http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid によれば、ソケット自体は実際にはスレッドセーフです。したがって、ロックは必要ありません です。

私は3つの戦略をすべて試しました。ロックを取り外すことが最も効果的です。 タイムアウトを0.001に減らすのと同様の方法で動作します。

私はlinux/unixプラットフォームのみを保証できますが、私は Windowsで試していません。 これを改善するために実装を変更することを検討しますか?