2017-03-17 11 views
6

IB API Python 소켓을 사용하여 기본 요청을 수행하는 방법을 알아낼 수 있습니까? (최신 IB API를 사용하고 있으며 Python을 지원하는 것처럼 보이기 때문에 사람들이 사용하던 Ibpy가 필요하지 않습니다.)IB API IBpy를 사용하지 않는 Python 샘플

내 코드는 간단히 작동하여 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 원래 파이썬 API에서 그것을 어떻게 해야할지 모르겠다. 누군가가 간단한 예를 들어 도와 줄 수 있습니까? 미리 감사드립니다.

답변

3

래퍼를 서브 클래 싱/오버라이드/구현해야합니다. 래퍼. 그것은 TWS로부터받은 데이터를 EClient에게 보내고있는 곳입니다.

샘플 프로그램에서 거의 모든 것을 제거했으며이 프로그램이 실행됩니다. 당신이 app.run()를 호출하면

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

이 프로그램은 루프를 시작해야하기 때문에 프로그램을 구성하는 다른 방법이 필요합니다 있도록 메시지를 읽고 거의 무한 루프를 시작합니다.

+0

는 귀하의 의견 주셔서 너무 감사합니다. 나는 그것을 시도하고 싶어하지만 어떤 이유로 나는 "server error"msg를 얻고 있으며이 순간 TWS에 로그인 할 수 없다. 일단 내가 연결하고 코드를 시험해 볼 수있게되면 이것을 대답으로 표시 할 것입니다. 감사. –

+0

edemo/demouser를 사용하여 로그인하여 테스트 할 수 있습니다. 그게 내가 한 짓이야. 나는 실제 계정이나 데모 계정을 암시하는 7496을 사용하고 있음을 알고 있습니다. 데모 또는 페이퍼 어카운트를 가지고 테스트 해보는 것이 좋습니다 (일반적으로 용지는 포트 7497 임). 코드가있는 – brian

+0

: self.done = True, Run run breaks. 및 오류 발생 : thread-1 : 예외, _recvAllMsg의 줄 113, buf = self.socket.recv (4096) AttributeError : 'NoneType'개체에 'recv'특성이 없습니다. 나는 그것이 .disconnection으로 인한 것이라고 생각했다. 같은 문제가 보이십니까? 어떤 방법으로 안전하게 연결을 끊고 프로그램을 종료 할 수 있습니까? 감사. –

3

앱 개체 외부에서 요청 순서를 처리하는 방법을 찾았습니다.

이것은 Brian의 코드를 약간 수정 한 것입니다. Brian의 코드를 약간 수정 한 것입니다. Brian은 두 가지 계약 세부 정보를 얻습니다. 처음에는 MSFT와 IBM에 대한 contractdetails를 요청합니다.

  • app.run()는 app.done True로 설정() 메소드
  • contractDetailsEnd 참된 app.done = 설정함으로써 모든 contractDetails 메시지를 수신 한 후에 완료된다 EClient.run의 클라이언트 단절() 메소드를 호출합니다. 나는 분리없이 EClient.run() 메소드를 종료하는 방법을 생각하지 않았다, 그래서 나는 EClient.run() 메소드 client.py의 소스 코드에 종료 변경 :

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

감사합니다. Myk - 이것은 받아 들여진 대답이어야합니다. –

+0

Myk, nextValidId() 메소드에서 원하는만큼 많은 요청을 넣을 수 있습니다. 50ms/초 제한을 초과하지 마십시오. – brian

+0

안녕 마이 크, 왜 ibapi 모듈을 찾을 수없는 모든 아이디어. 아나콘다와 일하고 있니? Visual Studio Code로 작업하고 있습니까? – pashute

2

이 멀티 스레딩을 사용하여 API 메시지를 처리하는 방법을 예입니다 : 여기

는 코드입니다. app.run()은 별도의 스레드로 시작되며 TWS API 응답을 수신합니다. 주 프로그램은 ContractDetails에 대한 5 개의 요청을 보낸 다음 주 프로그램은 응답을 기다리는 10 초입니다. 응답이 처리 될 준비가되면 TWS 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 * 
#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() 
+0

이봐, 나는 그걸보고 싶다.하지만이 오류가있다. "ImportError : 'OrderSamples'라는 모듈이 없다. – Jeremy

+0

OrderSamples는 데모 폴더에 있지만,이 예제에서는 neccesssary가 아니므로 주석 처리했다. – Myk

1

파이썬 TWS API로 작업을 간소화하는 새로운 프로젝트가 있습니다.

IB- 비동기라고하며 동기화 및 비동기 처리를 모두 허용합니다. TWS API의 초보자에게는 매우 유용합니다. IB-은 insync를 사용하여 기록 데이터를 요청하는 Link to Project Page

예 :

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']])