问题描述
解决方案
在 PTrade 中,原生 API (get_history 或 get_price) 支持的标准频率通常包括 1分钟、5分钟、15分钟、30分钟、60分钟和日线等。如果需要 10分钟 或 45分钟 这样非标准的 K 线数据,我们需要获取 1分钟 的基础数据,然后利用 Python 的 pandas 库进行重采样(Resampling)合成。
以下是具体的实现逻辑和代码示例。
核心逻辑
合成 K 线遵循以下聚合规则(OHLCV):
- Open (开盘价):取该时间段内第一根 1 分钟 K 线的开盘价。
- High (最高价):取该时间段内所有 1 分钟 K 线最高价的最大值。
- Low (最低价):取该时间段内所有 1 分钟 K 线最低价的最小值。
- Close (收盘价):取该时间段内最后一根 1 分钟 K 线的收盘价。
- Volume (成交量):取该时间段内所有 1 分钟 K 线成交量的总和。
- Money (成交额):取该时间段内所有 1 分钟 K 线成交额的总和。
策略代码实现
你可以将以下代码直接复制到 PTrade 的策略编辑器中运行。代码包含了一个通用的合成函数 get_custom_period_data。
import pandas as pd
import numpy as np
def initialize(context):
# 设置股票池,以恒生电子为例
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
# 示例1:获取过去 5 根 10分钟 K线
# 需要获取足够的1分钟数据,5 * 10 = 50,为了保险起见取 60
df_10m = get_custom_period_data(g.security, count=60, period='10T')
if df_10m is not None and len(df_10m) > 0:
log.info("=== 10分钟 K线数据 (最后5行) ===")
log.info(df_10m.tail(5))
# 示例2:获取过去 5 根 45分钟 K线
# 5 * 45 = 225,取 240 根1分钟数据
df_45m = get_custom_period_data(g.security, count=240, period='45T')
if df_45m is not None and len(df_45m) > 0:
log.info("=== 45分钟 K线数据 (最后5行) ===")
log.info(df_45m.tail(5))
def get_custom_period_data(security, count, period):
"""
利用1分钟数据合成自定义周期K线
:param security: 股票代码
:param count: 获取1分钟K线的数量 (建议为 period倍数 * N)
:param period: 目标周期,格式参考 pandas resample,如 '10T', '45T'
:return: 合成后的 DataFrame
"""
# 1. 获取 1分钟 历史数据
# 注意:include=True 包含当前这一分钟,这样合成出来的最后一根K线是实时的
df = get_history(count, frequency='1m', field=['open', 'high', 'low', 'close', 'volume', 'money'],
security_list=security, include=True)
if df is None or len(df) == 0:
return None
# 2. 确保索引是 datetime 类型 (PTrade get_history 返回的索引通常已经是 datetime)
# 如果不是,需要转换: df.index = pd.to_datetime(df.index)
# 3. 定义聚合规则
agg_dict = {
'open': 'first',
'high': 'max',
'low': 'min',
'close': 'last',
'volume': 'sum',
'money': 'sum'
}
# 4. 使用 pandas resample 进行重采样
# closed='right', label='right' 表示时间标签取区间的结束时间,且包含结束时间点的数据
# 例如 09:31-09:40 的数据合成一根,标签为 09:40
resampled_df = df.resample(period, closed='right', label='right').agg(agg_dict)
# 5. 去除无效数据
# 重采样可能会产生非交易时间段的空行(例如中午休市期间),需要去除成交量为0或NaN的行
resampled_df = resampled_df.dropna()
resampled_df = resampled_df[resampled_df['volume'] > 0]
return resampled_df
代码关键点解析
-
get_history的count参数:- PTrade 没有直接“获取过去 N 个 10分钟”的接口。
- 你需要估算所需的 1 分钟数据量。例如,如果你需要计算 10 分钟级别的 MA5(5周期均线),你需要至少 5 根 10分钟 K线,也就是 50 根 1分钟 K线。建议适当多取一些(如 60 或 100),以防重采样时的边界损耗。
-
resample参数:period='10T':表示 10 分钟(T 代表 Minute)。同理'45T'代表 45 分钟。closed='right', label='right':这是金融时间序列的标准处理方式。意味着 09:30:01 到 09:40:00 的数据会被归纳为 09:40:00 这根 K 线。
-
处理 45 分钟 K 线的特殊性:
- A股交易时间为每天 240 分钟(上午 120 分钟,下午 120 分钟)。
- 10分钟:240 / 10 = 24,可以完美整除,K 线结构非常规整。
- 45分钟:240 / 45 = 5.33,无法整除。
- 使用
pandas直接重采样 45 分钟数据时,可能会出现跨越中午休市(11:30 - 13:00)的情况,或者在收盘时产生一个不足 45 分钟的短 K 线。上述代码会自动处理这些情况,但你需要知晓这种非整除周期的天然特性。
-
Python 版本兼容性:
- 代码使用了基础的
pandas语法,兼容 Python 3.5 及以上版本(PTrade 环境通常支持)。
- 代码使用了基础的
常见问题 Q&A
Q: 为什么合成的数据中间有断档?
A: pandas.resample 是基于连续时间轴的。A股中午 11:30 到 13:00 休市,重采样会生成这段时间的空数据行。代码中的 resampled_df.dropna() 和 resampled_df[resampled_df['volume'] > 0] 就是用来过滤掉这些非交易时间的无效数据的。
Q: 如何计算合成 K 线的均线(MA)?
A: 合成完 DataFrame 后,直接对 close 列进行计算即可。例如:
df_10m['MA5'] = df_10m['close'].rolling(window=5).mean()
current_ma5 = df_10m['MA5'].iloc[-1]
Q: include=True 是必须的吗?
A: 在盘中实盘或回测时,如果你希望获取包含“当前正在走的这一分钟”的数据来合成最新的 K 线,必须设为 True。否则 get_history 默认只返回上一分钟结束的数据,导致你的 10 分钟 K 线会有滞后。