Pandas DataFrame 和系列 - 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,您可以读取它的 vars 以获得像 {date:..., open:123 这样的 dict...}
等
The callback gives you ibapi.common.BarData which you can read it's vars to get a dict like {date:..., open:123...}
etc.
Pandas 可以从一个字典列表中创建一个数据框,因此将它们存储在一个列表中
Pandas can make a dataframe from a list of dicts so store them in a list
也许您想要日期作为索引,pandas 也可以这样做,令人惊讶的是它可以读取格式.
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 notebook,所以我添加了线程,这样我仍然可以交互.
I use jupyter notebook so I added threading so I can still interact.
这是一些输出.接收和打印的第一个数据来自historyDataEnd.数据帧由带有日期时间索引的变量组成,因此可以按时间添加条形.
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.
历史数据结束.ReqId:1 从 20200707 14:23:19 到 20200708 14:23:19
然后在 300 秒后我打印数据帧.检查 ohlc 是否合乎逻辑,并每分钟注意一个新的柱线.14:28 栏只是我假设的前 19 秒,因为我的五分钟(300 秒)从 14:23: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 DataFrame 和系列 - IB TWS HistoricalData的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!