3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 QMT(Quantitative Trading Platform)的 Python 策略开发中,ContextInfo 是最核心、最重要的对象。它贯穿于策略运行的整个生命周期,充当着环境容器、API 接口入口以及全局状态载体的角色。
以下是对 ContextInfo 对象的详细解释,以及如何使用它来管理自定义变量。
ContextInfo 是 QMT 平台在运行策略时自动创建并传递给策略函数的一个 Python 对象。它的主要作用体现在以下三个方面:
QMT 提供的绝大多数功能函数都是作为 ContextInfo 的成员方法存在的。
ContextInfo.get_market_data_ex()(获取行情)、ContextInfo.get_financial_data()(获取财务数据)。passorder 是独立函数,但在回测模式下,资金账号、费率设置等都依赖 ContextInfo 的属性(如 ContextInfo.capital)。ContextInfo.barpos)、当前策略运行的周期(ContextInfo.period)等。在 Python 策略中,init() 只运行一次,而 handlebar() 会随着 K 线或 Tick 的更新被多次调用。普通的局部变量在函数调用结束后会被销毁。ContextInfo 对象在策略启动时被创建,并一直存活到策略停止。因此,它是存储跨函数、跨周期数据的最佳场所。
它记录了策略运行时的所有状态信息,包括回测的起止时间、股票池设定、基准设定等。
由于 ContextInfo 是一个标准的 Python 对象,且在 init 和 handlebar 函数中都作为参数传入,利用 Python 的动态特性,我们可以直接向其添加自定义属性来存储变量。
init(ContextInfo) 中定义并初始化变量。这是为了确保变量在使用前已经存在,避免 AttributeError。handlebar(ContextInfo) 中读取、修改这些变量。由于 ContextInfo 在多次调用中是同一个实例,修改后的值会保留到下一次调用。假设我们需要实现一个简单的逻辑:记录策略运行以来,收盘价上涨的天数。我们需要一个变量来累加计数,这个变量必须在不同的 K 线之间保持记忆。
# -*- coding: gbk -*-
def init(ContextInfo):
"""
初始化函数:策略启动时调用一次
"""
# 1. 在 ContextInfo 上绑定自定义变量
# 建议使用 distinctive 的命名,避免与系统内置属性冲突
ContextInfo.up_days_count = 0
ContextInfo.last_entry_price = None
ContextInfo.my_custom_flag = False
print("策略初始化完成,自定义变量已设置。")
def handlebar(ContextInfo):
"""
行情事件函数:每根 K 线调用一次
"""
# 获取当前 K 线索引
index = ContextInfo.barpos
# 获取收盘价数据 (取当前根和前一根)
# 注意:get_market_data_ex 返回的是字典,需要解析
# 这里为了演示简单,使用伪代码逻辑获取收盘价
# 实际开发建议使用 get_market_data_ex
close_data = ContextInfo.get_market_data(['close'])
# 确保有足够的数据进行比较
if len(close_data) < 2:
return
# 2. 读取并更新 ContextInfo 中的自定义变量
current_close = close_data[-1]
prev_close = close_data[-2]
if current_close > prev_close:
# 修改变量值,这个值会被保存到下一次 handlebar 调用
ContextInfo.up_days_count += 1
print(f"K线 {index}: 收盘价上涨。累计上涨天数: {ContextInfo.up_days_count}")
# 3. 传递逻辑示例
# 如果累计上涨超过 5 天且未标记,则设置标记
if ContextInfo.up_days_count > 5 and not ContextInfo.my_custom_flag:
ContextInfo.my_custom_flag = True
print("触发条件:累计上涨超过5天!")
init(ContextInfo)。ContextInfo.up_days_count 被设为 0。handlebar(ContextInfo)。代码读取 up_days_count (0),逻辑判断后可能将其加 1。handlebar(ContextInfo)。此时读取到的 up_days_count 是 Bar 0 运行结束后的值(0 或 1),而不是初始值 0。在使用 ContextInfo 传递自定义变量时,请注意以下几点:
命名冲突风险:
barpos, period, stockcode, capital, benchmark, universe 等。ContextInfo.g_count 或 ContextInfo.user_status。必须在 init 中初始化:
init 中对所有需要用到的全局变量赋初值(如 None, 0, [])。如果在 handlebar 中直接读取一个未定义的属性,会导致程序报错崩溃。对象引用问题:
ContextInfo 传递的是对象的引用。这意味着你在函数内部对 ContextInfo 属性的修改,会直接影响到该对象本身,从而影响后续的执行。回测与实盘的区别:
ContextInfo 承载的数据流是连续的历史时间序列。init 会重新运行,ContextInfo 中的自定义变量会被重置为初始值(除非你使用了外部文件或数据库来持久化存储数据)。Q: 为什么不直接使用 Python 的 global 关键字来定义全局变量?
A: 虽然可以使用 global 关键字,但在量化框架中,使用 ContextInfo 是更规范的做法。
ContextInfo 将策略的所有状态封装在一个对象中,便于管理和调试。ContextInfo 传递状态,这样可以避免全局命名空间污染,且在某些多线程或特殊运行模式下更安全。Q: ContextInfo 可以存储哪些类型的数据?
A: 它可以存储任何 Python 支持的数据类型,包括:
int, float, bool, strlist, dict, set, tuplepandas.DataFrame, numpy.array,甚至是你自定义的类的实例。Q: 如何查看 ContextInfo 中有哪些内置属性?
A: 你可以在 init 或 handlebar 中使用 dir(ContextInfo) 命令打印该对象的所有属性和方法列表,从而了解其内部结构。