价差交易策略模板

价差交易策略模板提供完整的信号生成和委托管理功能,用户可以基于该模板(位于vnpy.app.spread_trading.template中)自行开发策略。

用户自行开发的策略可以放在用户运行文件夹下的strategies文件夹内。 请注意,策略文件命名采用下划线模式,如basic_spread_strategy.py,而策略类命名采用驼峰式,如BasicSpreadStrategy。

目前,vnpy官方提供两个价差策略,即BasicSpreadStrategy和StatisticalArbitrageStrategy,本文档通过BasicSpreadStrategy策略进行示例。

BasicSpreadStrategy策略逻辑假设价差满足均值回归,即价差围绕某个固定数值波动,并基于预先设置好的阈值来发出委托,具体策略逻辑如下:

  • 在价差合约的价格低位买入开仓(BUY),然后在接近均值时候卖出平仓(SELL);

  • 在合约价格高位卖出开仓(SHORT),然后在价格走低接近均值买入平仓(COVER)。

若价差均值并不是围绕某个固定数值波动,或者能够持续走出趋势,则需要更加复杂的策略,如价差的布林带策略等等。这些个性化策略,用户可以基于SpreadStrategyTemplate策略模板自己实现。

在基于价差交易策略模板编写策略逻辑之前,需要在策略文件的顶部载入需要用到的内部组件,如下方代码所示:

  1. from datetime import datetime
  2. from vnpy.app.spread_trading import (
  3. SpreadStrategyTemplate,
  4. SpreadAlgoTemplate,
  5. SpreadData,
  6. OrderData,
  7. TradeData
  8. )

其中,SpreadStrategyTemplate和SpreadAlgoTemplate是价差交易策略模板和价差算法模板,SpreadData、OrderData和TradeData是储存对应信息的数据容器。

策略参数与变量

在策略类的下方,可以设置策略的作者(author),参数(parameters)以及变量(variables),如下方代码所示:

  1. author = "用Python的交易员"
  2. buy_price = 0.0
  3. sell_price = 0.0
  4. cover_price = 0.0
  5. short_price = 0.0
  6. max_pos = 0.0
  7. payup = 10
  8. interval = 5
  9. start_time = "9:00:00"
  10. end_time = "15:00:00"
  11. spread_pos = 0.0
  12. update_time = None
  13. buy_algoid = ""
  14. sell_algoid = ""
  15. short_algoid = ""
  16. cover_algoid = ""
  17. parameters = [
  18. "buy_price",
  19. "sell_price",
  20. "cover_price",
  21. "short_price",
  22. "max_pos",
  23. "payup",
  24. "interval"
  25. ]
  26. variables = [
  27. "spread_pos",
  28. "update_time",
  29. "buy_algoid",
  30. "sell_algoid",
  31. "short_algoid",
  32. "cover_algoid",
  33. ]

虽然策略的参数和变量都从属于策略类,但策略参数是固定的(由交易员从外部指定),而策略变量则在交易的过程中随着策略的状态变化,所以策略变量一开始只需要初始化为对应的基础类型。例如:整数设为0,浮点数设为0.0,而字符串则设为””。

如果需要价差交易模块引擎在运行过程中,将策略参数和变量在UI界面显示,并在数据刷新、停止策略时保存其数值,则需把参数和变量的名字以字符串的数据类型添加进parameters和variables列表里。

请注意,该列表只能接受参数和变量以str、int、float和bool四种数据类型传入。如果策略里需要用到其他数据类型的参数与变量,请把该参数或变量的定义放到__init__函数下。

类的初始化

入参:strategy_engine, strategy_name: str, spread: SpreadData, setting: dict

出参:无

__init__函数是策略类的构造函数,需要与继承的SpreadStrategyTemplate保持一致。

在这个继承的策略类里,初始化一般分两步,如下方代码所示:

  1. 通过super( )的方法继承SpreadStrategyTemplate,在__init__( )函数中传入策略引擎、策略名称、价差以及参数设置。(以上参数均由策略引擎在使用策略类创建策略实例时自动传入,用户无需进行设置);

  2. 传入起止时间,策略仅允许在起止时间段内交易。

  1. def __init__(
  2. self,
  3. strategy_engine,
  4. strategy_name: str,
  5. spread: SpreadData,
  6. setting: dict
  7. ):
  8. """"""
  9. super().__init__(
  10. strategy_engine, strategy_name, spread, setting
  11. )
  12. self.start_t = datetime.strptime(self.start_time, "%H:%M:%S").time()
  13. 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()函数撤销;

  • 若持有多头仓位,先发出卖出平仓委托,然后检测若存在买入开仓委托,撤单处理;

  • 若持有空头仓位,先发出买入平仓委托,然后检测若存在卖出开仓委托,撤单处理。

  1. def on_spread_data(self):
  2. """
  3. Callback when spread price is updated.
  4. """
  5. self.spread_pos = self.get_spread_pos()
  6. # No position
  7. if not self.spread_pos:
  8. # Start open algos
  9. if not self.buy_algoid:
  10. self.buy_algoid = self.start_long_algo(
  11. self.buy_price, self.max_pos, self.payup, self.interval
  12. )
  13. if not self.short_algoid:
  14. self.short_algoid = self.start_short_algo(
  15. self.short_price, self.max_pos, self.payup, self.interval
  16. )
  17. # Stop close algos
  18. if self.sell_algoid:
  19. self.stop_algo(self.sell_algoid)
  20. if self.cover_algoid:
  21. self.stop_algo(self.cover_algoid)
  22. # Long position
  23. elif self.spread_pos > 0:
  24. # Start sell close algo
  25. if not self.sell_algoid:
  26. self.sell_algoid = self.start_short_algo(
  27. self.sell_price, self.spread_pos, self.payup, self.interval
  28. )
  29. # Stop buy open algo
  30. if self.buy_algoid:
  31. self.stop_algo(self.buy_algoid)
  32. # Short position
  33. elif self.spread_pos < 0:
  34. # Start cover close algo
  35. if not self.cover_algoid:
  36. self.cover_algoid = self.start_long_algo(
  37. self.cover_price, abs(
  38. self.spread_pos), self.payup, self.interval
  39. )
  40. # Stop short open algo
  41. if self.short_algoid:
  42. self.stop_algo(self.short_algoid)
  43. self.put_event()

策略的主动函数

stop_open_algos和stop_close_algos都是策略内部的负责撤单的交易请求类函数。

stop_open_algos

入参:无

出参:无

负责撤销开仓委托。

stop_close_algos

入参:无

出参:无

负责撤销平仓委托。