使用手册
功能在哪 · 是什么 · 怎么调出来一、vn.py 是什么
vn.py(现名 VeighNa)是国内最流行的开源量化交易框架:
- Python 编写,开源免费(MIT 协议)
- 模块化架构:核心引擎 + 按需安装的应用模块(CTA 策略、价差交易、算法交易等)
- 覆盖全流程:行情网关 → 事件引擎 → 策略引擎 → 回测 → 实盘
- 国内期货 CTP 实盘的事实标准之一
白话注解:如果把量化交易比作开餐厅,vn.py 就是"精装修的厨房"——水电煤气(行情/交易通道)都接好了,你只管炒菜(写策略逻辑)。TqSdk 是"半成品厨房"(更简单),Backtrader 是"只练菜不营业"(只回测)。
二、安装与环境
# 方式一:官方推荐,图形化 VeighNa Station(Windows)自动装好一切
# 到 www.vnpy.com 下载 VeighNa Station
# 方式二:pip 手动安装核心 + CTA 应用
pip install vnpy
pip install vnpy_ctastrategy # CTA 策略模块(本教程主角)
pip install vnpy_ctabacktester # CTA 回测工具(可选)
pip install vnpy_ctp # CTP 期货柜台网关(实盘需要,仅 Windows)
- 建议 Python 3.10 左右版本(个别网关对过新/过旧的 Python 支持滞后)
- Windows 实盘 CTP 最省事;Linux 跑回测/研究很稳
- 验证:
python -c "import vnpy; print(vnpy.__version__)"
vn.py 3.x 之后把功能拆成了独立包(vnpy_ctastrategy、vnpy_ctp…)。只装 pip install vnpy 只有核心引擎,CTA 策略要用必须另装 vnpy_ctastrategy——报 No module named 'vnpy_ctastrategy' 就是这个原因。
操作教程
一步一步 · 跟着做完一件事三、核心架构与 vt_symbol 规则
| 组件 | 作用 |
|---|---|
EventEngine 事件引擎 | 框架心脏:所有行情/成交/委托都是事件,分发给订阅者 |
MainEngine 主引擎 | 总管家:管理网关、应用模块、事件转发 |
Gateway 网关 | 对接一个交易所/柜台(CTP、CTP MINI 等),统一转成 vn.py 数据格式 |
| 应用模块 | vnpy_ctastrategy(CTA)、vnpy_spreadtrading(价差)、vnpy_portfoliostrategy(组合)等 |
vt_symbol 合约代码规则:合约.交易所,注意与 TqSdk 顺序相反:
| 示例 | 含义 |
|---|---|
rb2410.SHFE | 上期所螺纹钢 |
IF2406.CFFEX | 中金所股指 |
TA409.CZCE | 郑商所 PTA |
sc2407.INE | 上期能源原油 |
白话注解:日常写策略时你基本不直接碰 MainEngine/EventEngine——VeighNa Trader 图形界面或回测引擎都替你管了。但理解"一切都是事件"这个模型,能帮你明白为什么策略类里全是 on_xxx 回调。
四、数据对象:TickData / BarData / OrderData / TradeData
策略回调收到的都是 vn.py 统一的数据对象,常用字段:
| 对象 | 常用字段 |
|---|---|
BarData | open_price / high_price / low_price / close_price / volume / datetime / vt_symbol |
TickData | last_price / ask_price_1 / bid_price_1 / ask_volume_1 / bid_volume_1 / volume / limit_up / limit_down / datetime |
OrderData | vt_orderid / direction / offset / price / volume / traded / status |
TradeData | vt_tradeid / vt_orderid / direction / offset / price / volume / datetime |
注意字段命名与 TqSdk 不同:vn.py 是 close_price 不是 close,是 ask_price_1 不是 ask_price1。混用两个框架时最容易写串。
五、生命周期回调全集
CtaTemplate 的全部回调(官方 template.py 源码确认):
| 回调 | 触发时机 | 典型用途 |
|---|---|---|
on_init() | 策略初始化(抽象方法,必须实现) | load_bar 预热指标 |
on_start() | 点"启动"后 | 写日志、恢复状态 |
on_stop() | 点"停止"后 | put_event、记录状态 |
on_tick(tick) | 每笔 tick | 喂给 BarGenerator |
on_bar(bar) | 每根 1 分钟 K 线 | 主策略逻辑(多数策略写在这) |
on_order(order) | 委托状态更新 | 跟踪挂单 |
on_trade(trade) | 成交回报 | 记录开仓价、打日志 |
on_stop_order(stop_order) | 本地停止单状态更新 | 跟踪停止单(见第十六章) |
配套工具方法(同样是源码确认):
| 方法 | 作用 |
|---|---|
self.buy/sell/short/cover(price, volume, stop, lock, net) | 四向下单(见第九章) |
self.cancel_order(vt_orderid) / self.cancel_all() | 撤单 / 撤掉本策略全部挂单 |
self.write_log(msg) | 写日志 |
self.put_event() | 刷新界面显示(on_bar 结尾习惯调一次) |
self.load_bar(days, interval, callback, use_database) | 加载历史数据预热指标 |
self.load_tick(days) | 加载历史 tick 预热 |
self.get_engine_type() | 判断当前是回测还是实盘(BACKTESTING/LIVE) |
self.get_pricetick() / self.get_size() | 合约最小变动价 / 合约乘数 |
self.sync_data() | 把 variables 持久化到磁盘(重启恢复现场) |
self.send_notification(msg)(别名 send_email) | 推送通知(实盘告警) |
CtaTemplate 没有 set_target 和 close_all 方法——网上部分老教程写错了,直接调用会报 AttributeError。想"一键平仓":判断 self.pos 后调用对应的 sell/cover;或者干脆继承 TargetPosTemplate 用 set_target_pos(0)(第十四章)。
六、BarGenerator:K 线合成器
国内期货 CTP 推送的是 tick 和 1 分钟线,BarGenerator 负责把它们合成你要的周期:
from vnpy.trader.utility import BarGenerator
from vnpy.trader.constant import Interval
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
# 1分钟K线 → 合成 15分钟K线,推给 on_15min_bar
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
# 小时线:window 配合 Interval.HOUR
self.bg_hour = BarGenerator(self.on_bar, 2, self.on_2hour_bar, Interval.HOUR)
def on_tick(self, tick: TickData):
self.bg.update_tick(tick) # tick 灌进合成器
def on_bar(self, bar: BarData):
self.bg.update_bar(bar) # 1分钟线再灌进15分钟合成器
def on_15min_bar(self, bar: BarData):
# 你的主逻辑写在这(15分钟级别)
...
BarGenerator(on_bar, window, on_window_bar, interval):默认把 tick 合成 1 分钟线推给on_barwindow=N再把 N 根合成一根推给on_window_bar;小时线要配Interval.HOUR- chain 起来就是:tick → 1分钟 → 15分钟,层层灌
白话注解:注意信号只会在 K 线走完时触发一次(合成器是收满 N 根才切一刀),天然规避了"K线没走完反复交易"的问题——这点 vn.py 帮你处理好了。
七、下单函数:buy / sell / short / cover(含 stop/lock/net)
四个下单函数,源码签名完全一致:
def buy(self, price: float, volume: float, stop: bool = False,
lock: bool = False, net: bool = False) -> list:
"""买入开多"""
# 四个方向
self.buy(price, volume) # 买开(做多)
self.sell(price, volume) # 卖平(平多仓)
self.short(price, volume) # 卖开(做空)
self.cover(price, volume) # 买平(平空仓)
| 参数 | 作用 | 细节 |
|---|---|---|
stop=True | 本地停止单 | 价格触线才转限价单发出,不占交易所挂单(见第十六章) |
lock=True | 锁仓代替平仓 | 上期所平今手续费贵时,反手开仓锁仓、次日再解(见第十七章) |
net=True | 净持仓下单 | 直接指定目标净持仓方向和数量,交易所自动处理开平 |
返回值是 vt_orderid 列表(本地停止单返回 STOP.前缀 的虚拟单号),撤单用:
self.cancel_order(vt_orderid) # 撤指定单
self.cancel_all() # 撤本策略全部挂单(含停止单)
白话注解:新手最容易混 buy/cover 和 sell/short。口诀:开仓看方向(买开 buy、卖开 short),平仓反着来(平多用 sell、平空用 cover)。平仓手数超过实际持仓会被拒单——平之前看一眼 self.pos。
八、TargetPosTemplate:目标持仓模板
vn.py 内置了"目标持仓"式策略模板(继承自 CtaTemplate):你不写买卖方向,只声明目标净持仓,框架自动算差额、自动撤旧单、自动按多空方向下单(实盘自动处理平今平昨的组合):
from vnpy_ctastrategy import TargetPosTemplate, BarData
from vnpy.trader.utility import BarGenerator, ArrayManager
class TargetMaStrategy(TargetPosTemplate):
"""注意:继承 TargetPosTemplate,不是 CtaTemplate"""
fast_window = 10
slow_window = 30
target_pos_size = 1
target_pos = 0 # 模板内置变量:目标净持仓(正=多,负=空,0=空仓)
parameters = ["fast_window", "slow_window", "target_pos_size"]
variables = ["fast_ma0", "slow_ma0"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
self.am = ArrayManager(100)
def on_init(self):
self.load_bar(10)
def on_tick(self, tick):
self.bg.update_tick(tick)
def on_bar(self, bar):
self.bg.update_bar(bar)
def on_15min_bar(self, bar: BarData):
am = self.am
am.update_bar(bar)
if not am.inited:
return
fast = am.sma(self.fast_window, array=True)
slow = am.sma(self.slow_window, array=True)
if fast[-1] > slow[-1]:
self.set_target_pos(self.target_pos_size) # 目标:多头1手
elif fast[-1] < slow[-1]:
self.set_target_pos(-self.target_pos_size) # 目标:空头1手
else:
self.set_target_pos(0) # 目标:空仓
self.put_event()
def on_stop(self):
# 停止前把目标清零,框架会自动平掉所有持仓
self.set_target_pos(0)
self.put_event()
与手写 buy/sell/short/cover 对比:
| 维度 | 手写四函数 | TargetPosTemplate |
|---|---|---|
| 表达方式 | 一笔笔委托 | 只声明目标净持仓 |
| 反手/平今平昨 | 自己拼单 | 模板自动拆单组合 |
| 未成交旧单 | 自己撤 | 自动撤旧单再发新单(check_order_finished/cancel_old_order) |
| 下单价格 | 自己给 | 自动对价 ± tick_add(类属性,默认 1,可改) |
| 适合 | 精细控制 | 趋势/调仓类策略 |
白话注解:set_target_pos(n) 的 n 是手数:正数持多、负数持空、0 平光。它内部逻辑(官方 template.py)就是"目标减现有 = 差额",差额为正 buy/cover、为负 sell/short,且实盘会根据你的持仓方向自动选对平仓函数。和 TqSdk 的 TargetPosTask 一个思想——"声明目标,框架干活"。
旧教程里在 CtaTemplate 上调 self.set_target(...) 是错误写法(不存在该方法)。目标持仓的正确入口是继承 TargetPosTemplate 并调用 self.set_target_pos(...)。
九、停止单(stop)机制
buy/sell/short/cover(price, volume, stop=True) 发出的是本地停止单:
- 不发给交易所,存在 vn.py 引擎里,用
STOP.开头的虚拟单号 - 每个 tick 到来时检查:价格触及触发价 → 自动转成限价单发出
- 触发后走
on_stop_order()回调 cancel_all()会一并撤掉所有本地停止单
# 跌破 stop_price 止损(本地停止单)
self.sell(stop_price, abs(self.pos), stop=True)
def on_stop_order(self, stop_order):
self.write_log(f"停止单更新: {stop_order.status}")
白话注解:本地停止单的好处是不占交易所挂单、不暴露意图;代价是vn.py 程序挂了停止单就失效——断线期间价格穿透止损线,没有任何保护。实盘要么保证程序 7×24 稳定,要么用交易所条件单。
十、锁仓(lock)与净持仓(net)模式
| 参数 | 机制 | 什么时候用 |
|---|---|---|
lock=True | 不直接平仓,反向开仓锁住仓位,之后合适时机再解锁平仓 | 上期所平今手续费贵、想避开平今单的场景 |
net=True | 按净持仓报单:直接报"最终要持有多少",交易所/柜台自动拆成开平 | 支持净持仓模式的柜台,简化策略代码 |
# 上期所:用锁仓代替平今
self.short(price, volume, lock=True) # 不平多单,直接反手开空锁仓
# 净持仓模式(柜台支持时)
self.buy(price, 5, net=True) # 目标净多头5手,自动处理开平
白话注解:这三个参数(stop/lock/net)是 vn.py 实盘的"隐藏考点"。回测里它们都被正确模拟,但行为差异只有实盘才感受得到——特别是上期所的平今手续费,能让一个高频策略从微赚变微亏。
十一、参数优化:穷举与遗传算法
from vnpy_ctastrategy.backtesting import BacktestingEngine, OptimizationSetting
engine = BacktestingEngine()
engine.set_parameters(...) # 同第十一章
setting = OptimizationSetting()
setting.set_target("sharpe_ratio") # 优化目标(统计字段名)
setting.add_parameter("fast_window", 5, 25, 5) # 参数名, 起始, 结束, 步长
setting.add_parameter("slow_window", 20, 60, 10)
# 穷举优化(run_optimization 是它的别名)
result = engine.run_bf_optimization(setting)
# 遗传算法优化(参数多、空间大时更快)
result = engine.run_ga_optimization(setting, pop_size=100, ngen=30)
set_target填第十二章统计字段名(如total_return、sharpe_ratio、return_drawdown_ratio)- 返回结果按目标值排序的参数组合列表
优化结果只挑"最优一组"就是过拟合:那组参数大概率只是刚好贴合历史。正确姿势:看最优附近一组参数是否普遍不错(参数平原),再用样本外数据验证(参见本站 Backtrader 教程的防过拟合章节,原理通用)。
十二、实盘部署:VeighNa Trader + CTP
- 启动 VeighNa Station → 打开 VeighNa Trader(或自己写 run.py 加载应用)
- 登录界面连接 CTP:填期货公司给的服务器地址、账号、密码、产品信息、授权码
- 菜单栏"功能 → CTA 策略":添加策略实例(选策略类、绑定合约、填参数)
- 点"初始化"(on_init 加载历史预热)→ 点"启动"(on_start 开始交易)
- 策略配置自动持久化为 json,重启后恢复实例;
sync_data()同步 variables 现场数据
# 自定义启动脚本 run.py:
# 各版本 MainEngine 初始化与应用注册的写法略有差异。
# 最可靠做法:直接抄本机安装目录自带的 run.py(官方模板),
# 在其中加载 cta_strategy 应用即可,模板本身就是最好的文档。
vn.py 版本迭代较快,MainEngine/应用初始化的具体写法请以本机安装版本自带的 run.py 官方模板为准——模板本身就是最好的文档。CTP 实盘前先连SimNow 模拟环境(上期所官方仿真)验证全流程。
十三、风控与通知
self.send_notification(msg):策略里推送告警(配合 vnpy 的通知渠道配置)- 风控模块:安装 vnpy_riskmanager 后可在交易前做委托流控(单笔上限/总委托上限/活跃委托上限),实盘防手滑
- 策略内风控底线(自己写):单笔手数上限、当日最大亏损熔断(用
on_trade累计盈亏触发self.set_target_pos(0)+on_stop)、风险度监控 - 日志:write_log 输出到 VeighNa Trader 日志界面与文件,实盘务必落盘留痕
白话注解:实盘第一原则——程序会出错,所以要有"双保险":框架层风控(riskmanager)管住量,策略层熔断管住钱。任何一条触发就停,宁可少赚不可爆仓。
十四、VPS 部署注意事项
vn.py 实盘 24 小时跑建议用 VPS:
- 选离期货公司机房近的服务器(比如上海)
- CTP 网关(vnpy_ctp)目前仅 Windows;Linux 上可考虑其他兼容柜台网关
- 用 systemd / 任务计划守护进程;程序崩溃自动拉起后,策略实例和 variables 会从 json 恢复
- 夜盘时段(21:00 起)确保 VPS 不断电不断网
- 本地停止单(stop=True)依赖程序存活——见第十六章的风险提示
白话注解:vn.py 是个 Python 程序,你电脑关了它就停了。VPS 是远程 24 小时不关机的服务器,放在期货公司机房旁边,下单延迟比家里低。
十五、vn.py vs TqSdk vs Backtrader
| 对比项 | vn.py | TqSdk | Backtrader |
|---|---|---|---|
| 入门难度 | 中等(概念多、模块多) | 最简单(pip 装完即用) | 简单 |
| 国内期货实盘 | 支持 CTP(本机直连,需装 vnpy_ctp) | 支持 CTP(云端中继) | 核心定位回测,可经 Store 扩展 |
| 回测 | 内置引擎 + 优化器 | 内置,与实盘同代码 | 内置,分析维度最全 |
| 目标持仓工具 | TargetPosTemplate | TargetPosTask | order_target_\* 族 |
| 图形界面 | 完整 VeighNa Trader 客户端 | web_gui 网页 | matplotlib 静态图 |
| 适合 | 专业期货量化、多市场多模块 | 国内期货入门与中低频 | 回测研究与学习 |
白话注解:国内期货从零起步,TqSdk 上手最快;要完整平台(界面、风控、多模块、多网关)选 vn.py;纯研究回测用 Backtrader。三者不冲突,很多团队回测用 Backtrader、实盘用 vn.py/TqSdk。
十六、本课小结
- vn.py = 核心引擎 + 应用模块;CTA 策略装 vnpy_ctastrategy
- 策略继承 CtaTemplate:parameters/variables + on_init/on_start/on_stop + on_tick/on_bar 回调
- BarGenerator 合成周期 K 线,ArrayManager 管指标(sma/ema/atr/rsi/macd/boll…,dir(am) 查全部)
- 下单四函数 buy/sell/short/cover,关键参数 stop(本地停止单)/lock(锁仓)/net(净持仓)
- 一切持仓状态看 self.pos;平仓前先看它
- 目标持仓用 TargetPosTemplate.set_target_pos(正多/负空/0 清仓),不是 set_target
- 回测 BacktestingEngine:interval 用 Interval 枚举;统计 28 字段无胜率,用 get_all_trades 自算
- 优化有穷举和遗传算法两种,警惕过拟合
- 实盘走 VeighNa Trader + vnpy_ctp,先 SimNow 模拟后实盘,VPS 24 小时运行
- 回测 ≠ 实盘,业绩不代表未来收益
本站固定免责声明:本教程仅讲解软件编程与操作方法,不构成投资建议或策略推荐。回测业绩不代表未来收益,EA自动交易风险大,请谨慎决策。
💬 用户评价 (0)
立即登录