pandas 数据框和系列-IB TWS HistoricalData [英] Pandas DataFrame and Series - IB TWS HistoricalData
问题描述
我正在尝试将pandas模块应用于我的代码,以便重新组织从IB TWS服务器收到的消息.
I am trying to apply the pandas module to my code in order to re-organize the messages received back from IB TWS server.
代码是
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
class MyWrapper(EWrapper):
def nextValidId(self, orderId:int):
print("Setting nextValidOrderId: %d", orderId)
self.nextValidOrderId = orderId
self.start()
def historicalData(self, reqId, bar):
print("HistoricalData. ", reqId, "Date:", bar.date, "Open:", bar.open, "High:", bar.high, "Low:", bar.low, "Close:", bar.close, "Volume:", bar.volume, "Average:", bar.average, "Count:", bar.barCount)
def historicalDataUpdate(self, reqId, bar):
print("HistoricalDataUpdate. ", reqId, "Date:", bar.date, "Open:", bar.open, "High:", bar.high, "Low:", bar.low, "Close:", bar.close, "Volume:", bar.volume, "Average:", bar.average, "Count:", bar.barCount)
def error(self, reqId, errorCode, errorString):
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def start(self):
queryTime = ""
contract = Contract()
contract.secType = "STK"
contract.symbol = "NIO"
contract.currency = "USD"
contract.exchange = "SMART"
app.reqHistoricalData(1, contract, queryTime, "1 D", "5 secs", "TRADES", 0, 1, True, [])
app = EClient(MyWrapper())
app.connect("127.0.0.1", 7496, clientId=123)
app.run()
此代码检索给定股票的历史数据,然后返回最新更新.
This code retrives historical data for a given stock, then returns the most current updates.
我面临的问题是返回的消息是按这样的方式组织的
The problem that I am facing is that the messages returned are organized as such
HistoricalDataUpdate. 1 Date: 20200708 08:31:00 Open: 14.17 High: 14.17 Low: 14.17 Close: 14.17 Volume: -1 Average: 14.15 Count: -1
虽然我试图以重组的方式检索数据,例如
While I am trying to retrieve the data in a re-organized manner such as
HistoricalDataUpdate. 1 Date: Open: High: Low: Close: Volume: Average: Count:
20200708 08:31:00 14.17 14.17 14.17 14.17 -1 14.15 -1
我们将不胜感激.
推荐答案
该回调为您提供了ibapi.common.BarData,您可以将其读取为var,以获取诸如{date:..., open:123...}
等的字典.
The callback gives you ibapi.common.BarData which you can read it's vars to get a dict like {date:..., open:123...}
etc.
熊猫可以从字典列表中制作一个数据框,因此可以将它们存储在列表中
Pandas can make a dataframe from a list of dicts so store them in a list
也许您希望日期作为索引,熊猫也可以这样做,令人惊讶的是它可以读取格式.
Maybe you want date as an index, pandas can do that as well, surprisingly it can read the format.
完成后,您可以将数据保存到csv文件中.
You can save the data when you are done in a csv file.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
class MyWrapper(EWrapper):
def __init__(self):
self.data = []
self.df=None
def nextValidId(self, orderId:int):
print("Setting nextValidOrderId: %d", orderId)
self.nextValidOrderId = orderId
self.start()
def historicalData(self, reqId, bar):
self.data.append(vars(bar));
def historicalDataUpdate(self, reqId, bar):
line = vars(bar)
# pop date and make it the index, add rest to df
# will overwrite last bar at that same time
self.df.loc[pd.to_datetime(line.pop('date'))] = line
def historicalDataEnd(self, reqId: int, start: str, end: str):
print("HistoricalDataEnd. ReqId:", reqId, "from", start, "to", end)
self.df = pd.DataFrame(self.data)
self.df['date'] = pd.to_datetime(self.df['date'])
self.df.set_index('date', inplace=True)
def error(self, reqId, errorCode, errorString):
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def start(self):
queryTime = ""
# so everyone can get data use fx
fx = Contract()
fx.secType = "CASH"
fx.symbol = "USD"
fx.currency = "JPY"
fx.exchange = "IDEALPRO"
# setting update to 1 minute still sends an update every tick? but timestamps are 1 min
# I don't think keepUpToDate sends a realtimeBar every 5 secs, just updates the last bar.
app.reqHistoricalData(1, fx, queryTime, "1 D", "1 min", "MIDPOINT", 0, 1, True, [])
wrap = MyWrapper()
app = EClient(wrap)
app.connect("127.0.0.1", 7497, clientId=123)
#I just use this in jupyter so I can interact with df
import threading
threading.Thread(target = app.run).start()
#this isn't needed in jupyter, just run another cell
import time
time.sleep(300) # in 5 minutes check the df and close
print(wrap.df)
wrap.df.to_csv("myfile.csv")#save in file
app.disconnect()
#in jupyter to show plot
%matplotlib inline
wrap.df.close.plot()
我使用jupyter笔记本,因此添加了线程,因此我仍然可以进行交互.
I use jupyter notebook so I added threading so I can still interact.
这是一些输出.接收和打印的第一个数据来自historyDataEnd.一个dataFrame由带有日期时间索引的变量组成,因此可以按时间添加条形图.
Here is some output. The first data received and printed comes from historicalDataEnd. A dataFrame gets made from the variables with a datetime index so bars can be added by time.
HistoricalDataEnd. ReqId: 1 from 20200707 14:23:19 to 20200708 14:23:19
然后在300秒之后,我打印数据框.检查ohlc是否合乎逻辑,并每分钟注意一个新栏.自从我的五分钟(300秒)从14:23:19开始以来,我假定的14:28小节仅仅是前19秒.这正是您希望并期望保持图表最新的行为.
Then later after 300 secs I print the dataframe. Check that ohlc is logical and notice a new bar every minute. The 14:28 bar is only the first 19 seconds I assume since my five minutes (300 secs) started at 14:23:19. This is exactly the behaviour you would want and expect for keeping a chart up to date.
2020-07-08 14:24:00 107.231 107.236 107.231 107.233 -1 -1
2020-07-08 14:25:00 107.233 107.234 107.23 107.232 -1 -1
2020-07-08 14:26:00 107.232 107.232 107.225 107.232 -1 -1
2020-07-08 14:27:00 107.232 107.239 107.231 107.239 -1 -1
2020-07-08 14:28:00 107.239 107.239 107.236 107.236 -1 -1
您可以看到它获得了所有条形图(仅在图形中关闭)并保持最新状态.
You can see that it gets all the bars (close only in graph) and keeps it up to date.
这篇关于 pandas 数据框和系列-IB TWS HistoricalData的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!