3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 ptrade 中进行多因子选股或全市场回测时,获取历史行情数据(如 get_history 或 get_price)往往是策略运行的性能瓶颈。默认情况下,这些接口返回的是 pandas.DataFrame 或 pandas.Panel 对象。虽然 Pandas 对象便于数据分析,但在处理数百只甚至数千只股票的大数据量时,Pandas 对象的构建和转换会消耗大量的 CPU 时间和内存。
为了解决这一痛点,ptrade 提供了 is_dict=True 参数。通过启用该参数,API 将直接返回原生 Python 字典(OrderedDict)和 numpy.ndarray,从而绕过 Pandas 的封装开销,实现极速数据读取。
is_dict=True 能大幅提升速度?is_dict=True 直接返回底层的 NumPy 数组,省去了这些繁重的转换步骤。get_history 开启 is_dict=True 后的数据结构当设置 is_dict=True 时,get_history 返回一个 OrderedDict,其结构如下:
OrderedDict([
('股票代码', array([(时间戳, 开盘价, 最高价, 最低价, 收盘价, 成交量, 成交额, 最新价)],
dtype={'names': ['datetime', 'open', 'high', 'low', 'close', 'volume', 'money', 'price'],
'formats': ['i8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8']}))
])
OrderedDict([
('000001.SZ', array([(202309220931, 11.03, 11.08, 11.03, 11.07, 2289400.0, 25302018.0, 11.07)],
dtype=[('datetime', '<i8'), ('open', '<f8'), ('close', '<f8'), ...]))
])
以下是一个完整的 ptrade 策略示例,展示了如何使用 is_dict=True 获取全市场(或大批量)股票的历史收盘价,并计算 5 日均线。
def initialize(context):
# 设置测试股票池(例如沪深300成分股)
g.security_list = get_index_stocks('000300.XBHS')
set_universe(g.security_list)
def handle_data(context, data):
# 1. 开启 is_dict=True 获取过去5天的日线数据
# 此时返回的是 OrderedDict,速度极快
history_dict = get_history(
count=5,
frequency='1d',
field=['close'],
security_list=g.security_list,
is_dict=True
)
if history_dict is None:
log.error("获取行情数据失败")
return
# 2. 极速遍历并计算均值
for security in g.security_list:
if security in history_dict:
# 获取该股票的 numpy array
stock_data = history_dict[security]
# 提取 close 字段的所有值
close_prices = stock_data['close']
# 计算5日均价
if len(close_prices) >= 5:
ma5 = close_prices[-5:].mean()
# 打印部分日志展示结果
if security == g.security_list[0]:
log.info(f"{security} 的 5日均价为: {ma5:.2f}")
除了 get_history 之外,ptrade 的其他高频/大数据量接口也支持 is_dict 参数,建议在编写高频或 Tick 级策略时统一开启:
L2 逐笔委托与成交:
get_individual_entrust(..., is_dict=True)get_individual_transaction(..., is_dict=True)is_dict=True,否则返回的 DataFrame 可能会因为转换超时而返回 None。避免多线程冲突:
get_history 与 get_price 接口不支持多线程同时调用。请避免在 run_daily 或 run_interval 等定时任务中,与 handle_data 框架模块在同一时刻并发调用这两个接口,否则可能会偶现获取数据为空的现象。