价差交易策略模板
价差交易策略模板提供完整的信号生成和委托管理功能,用户可以基于该模板(位于vnpy.app.spread_trading.template中)自行开发策略。
用户自行开发的策略可以放在用户运行文件夹下的strategies文件夹内。 请注意,策略文件命名采用下划线模式,如basic_spread_strategy.py,而策略类命名采用驼峰式,如BasicSpreadStrategy。
目前,vnpy官方提供两个价差策略,即BasicSpreadStrategy和StatisticalArbitrageStrategy,本文档通过BasicSpreadStrategy策略进行示例。
BasicSpreadStrategy策略逻辑假设价差满足均值回归,即价差围绕某个固定数值波动,并基于预先设置好的阈值来发出委托,具体策略逻辑如下:
在价差合约的价格低位买入开仓(BUY),然后在接近均值时候卖出平仓(SELL);
在合约价格高位卖出开仓(SHORT),然后在价格走低接近均值买入平仓(COVER)。
若价差均值并不是围绕某个固定数值波动,或者能够持续走出趋势,则需要更加复杂的策略,如价差的布林带策略等等。这些个性化策略,用户可以基于SpreadStrategyTemplate策略模板自己实现。
在基于价差交易策略模板编写策略逻辑之前,需要在策略文件的顶部载入需要用到的内部组件,如下方代码所示:
from datetime import datetime
from vnpy.app.spread_trading import (
SpreadStrategyTemplate,
SpreadAlgoTemplate,
SpreadData,
OrderData,
TradeData
)
其中,SpreadStrategyTemplate和SpreadAlgoTemplate是价差交易策略模板和价差算法模板,SpreadData、OrderData和TradeData是储存对应信息的数据容器。
策略参数与变量
在策略类的下方,可以设置策略的作者(author),参数(parameters)以及变量(variables),如下方代码所示:
author = "用Python的交易员"
buy_price = 0.0
sell_price = 0.0
cover_price = 0.0
short_price = 0.0
max_pos = 0.0
payup = 10
interval = 5
start_time = "9:00:00"
end_time = "15:00:00"
spread_pos = 0.0
update_time = None
buy_algoid = ""
sell_algoid = ""
short_algoid = ""
cover_algoid = ""
parameters = [
"buy_price",
"sell_price",
"cover_price",
"short_price",
"max_pos",
"payup",
"interval"
]
variables = [
"spread_pos",
"update_time",
"buy_algoid",
"sell_algoid",
"short_algoid",
"cover_algoid",
]
虽然策略的参数和变量都从属于策略类,但策略参数是固定的(由交易员从外部指定),而策略变量则在交易的过程中随着策略的状态变化,所以策略变量一开始只需要初始化为对应的基础类型。例如:整数设为0,浮点数设为0.0,而字符串则设为””。
如果需要价差交易模块引擎在运行过程中,将策略参数和变量在UI界面显示,并在数据刷新、停止策略时保存其数值,则需把参数和变量的名字以字符串的数据类型添加进parameters和variables列表里。
请注意,该列表只能接受参数和变量以str、int、float和bool四种数据类型传入。如果策略里需要用到其他数据类型的参数与变量,请把该参数或变量的定义放到__init__函数下。
类的初始化
入参:strategy_engine, strategy_name: str, spread: SpreadData, setting: dict
出参:无
__init__函数是策略类的构造函数,需要与继承的SpreadStrategyTemplate保持一致。
在这个继承的策略类里,初始化一般分两步,如下方代码所示:
通过super( )的方法继承SpreadStrategyTemplate,在__init__( )函数中传入策略引擎、策略名称、价差以及参数设置。(以上参数均由策略引擎在使用策略类创建策略实例时自动传入,用户无需进行设置);
传入起止时间,策略仅允许在起止时间段内交易。
def __init__(
self,
strategy_engine,
strategy_name: str,
spread: SpreadData,
setting: dict
):
""""""
super().__init__(
strategy_engine, strategy_name, spread, setting
)
self.start_t = datetime.strptime(self.start_time, "%H:%M:%S").time()
self.end_t = datetime.strptime(self.end_time, "%H:%M:%S").time()
策略的回调函数
SpreadStrategyTemplate中以on开头的函数称为回调函数,在编写策略的过程中能够用来接收价差行情或者接收状态更新。回调函数的作用是当某一个事件发生的时候,策略里的这类函数会被价差交易策略引擎自动调用(无需在策略中主动操作)。回调函数按其功能可分为以下三类:
策略实例状态控制(所有策略都需要)
on_init
入参:无
出参:无
初始化策略时on_init函数会被调用,默认写法是调用write_log函数输出“策略初始化”日志。
on_start
入参:无
出参:无
启动策略时on_start函数会被调用,默认写法是调用write_log函数输出“策略启动”日志。
调用策略的on_start函数启动策略后,策略的trading状态变为【True】,此时策略才能够发出交易信号。
on_stop
入参:无
出参:无
停止策略时on_stop函数会被调用,默认写法是调用write_log函数输出“策略停止”日志,同时还原策略的变量。
订单状态推送
以下函数在策略中可以直接pass,其具体逻辑应用交给价差交易引擎负责。
on_spread_pos
入参:无
出参:无
收到持有仓位更新时on_spread_pos函数会被调用。
on_spread_algo
入参:algo: SpreadAlgoTemplate
出参:无
收到算法状态更新时on_spread_algo函数会被调用。
on_order
入参:order: OrderData
出参:无
收到策略委托回报时on_order函数会被调用。
on_trade
入参:trade: TradeData
出参:无 收到策略成交回报时on_trade函数会被调用。
检测仓位、发出交易信号
on_spread_data
入参:无
出参:无
BasicSpreadStrategy策略逻辑主要在on_spread_data()函数上。执行逻辑是先检测仓位:
若无仓位,分别发出买入开仓和卖出开仓委托,然后检测若存在平仓委托,调用stop_algo()函数撤销;
若持有多头仓位,先发出卖出平仓委托,然后检测若存在买入开仓委托,撤单处理;
若持有空头仓位,先发出买入平仓委托,然后检测若存在卖出开仓委托,撤单处理。
def on_spread_data(self):
"""
Callback when spread price is updated.
"""
self.spread_pos = self.get_spread_pos()
# No position
if not self.spread_pos:
# Start open algos
if not self.buy_algoid:
self.buy_algoid = self.start_long_algo(
self.buy_price, self.max_pos, self.payup, self.interval
)
if not self.short_algoid:
self.short_algoid = self.start_short_algo(
self.short_price, self.max_pos, self.payup, self.interval
)
# Stop close algos
if self.sell_algoid:
self.stop_algo(self.sell_algoid)
if self.cover_algoid:
self.stop_algo(self.cover_algoid)
# Long position
elif self.spread_pos > 0:
# Start sell close algo
if not self.sell_algoid:
self.sell_algoid = self.start_short_algo(
self.sell_price, self.spread_pos, self.payup, self.interval
)
# Stop buy open algo
if self.buy_algoid:
self.stop_algo(self.buy_algoid)
# Short position
elif self.spread_pos < 0:
# Start cover close algo
if not self.cover_algoid:
self.cover_algoid = self.start_long_algo(
self.cover_price, abs(
self.spread_pos), self.payup, self.interval
)
# Stop short open algo
if self.short_algoid:
self.stop_algo(self.short_algoid)
self.put_event()
策略的主动函数
stop_open_algos和stop_close_algos都是策略内部的负责撤单的交易请求类函数。
stop_open_algos
入参:无
出参:无
负责撤销开仓委托。
stop_close_algos
入参:无
出参:无
负责撤销平仓委托。