tick数据合成k线的完整过程(含源代码)
- 写在前面
- tick 数据的选择
- 行情结构体字段
- tick 行情示例
- 批量合成1分钟k线方式
- 增量合成1分钟k线方式
- k线分钟级别扩展
- 源码获取方式
写在前面
码上君量化互助社群已建立,所有源码免费对社群成员开放,如有需要请查看社群介绍文章,里面有加入社群的方式。
社群介绍:码上君量化互助社群介绍
公众号-码上助君(可跳转)
感兴趣的关注下公众号,优先发布,接收后续的更新内容会更及时奥
本文主要分享 tick 数据合成 k线 的完整过程,这样我们的策略就可以在此 k 线的基础上,计算各种技术指标(如ema、atr、kdj、macd等等)。
tick 数据的选择
国内股票行情是3秒一个切片,期货是1秒推送两个切片,由于期货行情是免费且无需登录验证,方便获取,所以选择期货行情数据进行k线合成。
在前面的文章中分享过期货行情订阅的代码,主要是以下回调函数:
相关链接:CTP-API开发系列之九:行情登录及订阅代码
行情结构体字段
行情结构体里面的字段比较多,大部分是没有用的,在行情回调函数中我们仅保存部分需要用到的字段,最主要的就是合约代码InstrumentID、更新时间UpdateTime、最新价LastPrice、累计成交量Volume、累计成交额Turnover
def OnRtnDepthMarketData(self, pDepthMarketData: 'CThostFtdcDepthMarketDataField') -> "void":
# Volume 成交量
if pDepthMarketData.Volume == 0:
return
md = f"{pDepthMarketData.TradingDay},{pDepthMarketData.UpdateTime},{pDepthMarketData.UpdateMillisec},{pDepthMarketData.InstrumentID}," \
f"{pDepthMarketData.LastPrice},{pDepthMarketData.BidPrice1},{pDepthMarketData.BidVolume1},{pDepthMarketData.AskPrice1}," \
f"{pDepthMarketData.AskVolume1},{pDepthMarketData.Volume},{pDepthMarketData.Turnover}"
log_md.info(md)
tick 行情示例
先以读取文件的方式,将所有的tick数据保存到 DataFrame 中
f = open('./logs/md_20240925085557.csv')
titles = ['date', 'time', 'mill', 'id', 'last_price', 'bid_price1', 'bid_volume1', 'ask_price1', 'ask_volume1', 'volume', 'turnover']
datas = []
for one in f.readlines():
d = one.replace(' ', '').split('INFO:')[1].split('[')[0].split(',')
datas.append(d)
result = dict(zip(titles, d))
df = pd.DataFrame(datas, columns=titles)
print(df)
这里面有部分数据是非交易时间的,期货的交易日是从夜盘开始的,所以也会看到部分夜盘的最后一笔行情,需要在合成的时候进行特殊处理。
这里订阅的期货全是市场的主力合约,为了展示方便,后面仅以螺纹钢rb2501合约为例进行合成:
data = df.loc[df['id'] == 'rb2501']
print(data)
批量合成1分钟k线方式
time的格式 HH:MM:SS,合成1分钟k线,我们先按照time字段取 HH:MM,将相同时分内的数据,第一条记录的last_price记为open,最后一条记录的last_price记为close,最大一条记录的last_price记为high,最小一条记录的last_price记为low
每一条记录的成交量增量、成交额增量都是减去上一条记录对应的数值,相同时分内的增量进行累加记为volume、turnover
data['last_price'] = data['last_price'].astype(float)
data['volume'] = data['volume'].astype(float)
data['turnover'] = data['turnover'].astype(float)
data['volume_change'] = data['volume'] - data['volume'].shift(1)
data['turnover_change'] = data['turnover'] - data['turnover'].shift(1)
data['minute'] = data['time'].str[0:5]
minute_grouped = data.groupby('minute')
df = pd.DataFrame()
df['open'] = minute_grouped.first()['last_price']
df['high'] = minute_grouped.max()['last_price']
df['low'] = minute_grouped.min()['last_price']
df['close'] = minute_grouped.last()['last_price']
df['volume'] = minute_grouped.agg({'volume_change': 'sum'})
df['turnover'] = minute_grouped.agg({'turnover_change': 'sum'})
print(df)
下图是某商业软件的截图,我们取09:02的k线进行对比,可以发现与我们合成的数据09:01这条数据是一致的,也就是说09:01这一分钟内的数据,最终形成的k线时间是下一分钟的时间
df['tmp_minute'] = df.index.tolist()
df['new_minute'] = df['tmp_minute'].shift(-1)
df = df.drop('tmp_minute', axis=1)
df.dropna(inplace=True)
df.rename(columns={'new_minute': 'minute'}, inplace=True)
df.set_index('minute', inplace=True)
df = df[1:-1]
print(df)
我们继续优化后,可以发现跟上图是一致的
增量合成1分钟k线方式
上面的合成k线的方式,是批量处理的,在实际的策略中,我们更需要的是一种增量合成的方式
来一条tick数据,进行一次合成,当1根k线完全合成后(HH:MM发生改变),再将合成的k线推送给相应的策略使用。
我们用一个函数实现该功能:
同时,我们还可以非常方便的进行各类指标的计算
在 添加到1min线队列的末尾 的位置的时候,就代表一根新的k线已经合成,此时可以推送需要的策略模块。
k线分钟级别扩展
以 rb2501 数据为例,我们从 27002 条tick数据,最终合成了 227 条1分钟级别的数据。
1分钟级别的数据对于绝大多数策略已经足够使用了,有了1分钟数据作为基础,在进行5分钟、10分钟、30分钟、1小时等级别的数据就更简单了,大家可以自行扩展。
源码获取方式
码上君量化互助社群已建立,所有源码免费对社群成员开放,包括文章的示例tick数据文件,如有需要请查看社群介绍文章,里面有加入社群的方式。
社群介绍:码上君量化互助社群介绍
公众号-码上助君(可跳转)
感兴趣的关注下公众号,优先发布,接收后续的更新内容会更及时奥