创新技术阁:基于CryptoTrader的策略开发指南

147 阅读4分钟

如之前文章《创新技术阁:量化交易系统CryptoTrader使用说明》所说,用户可以根据策略模板,自己开发策略,只需要把开发的策略放到可执行文件的统计目录strategies中,即可在CryptoTrader里面使用。本文就详细介绍如何开发自己的策略。

1. 注意事项

1.1 命名规范

  • 策略文件名采用下划线模式,例如:turtle_strategy.py
  • 策略类名采用驼峰式,例如:TurtleStrategy

1.2 类名冲突

自建策略的类名不得重复,如果发生重名,图形界面只会显示一个策略类名。

2. 策略开发的步骤

2.1 载入内部组件

在编写策略逻辑前,需在策略文件顶部导入所需的内部组件。

from core.trader.utility import round_to, get_decimal_places_via_decimal_lib
from app.app_novastrategy import (
    StrategyTemplate,
    BarDataTickData,
    TradeDataOrderData,
    ArrayManagerBarGenerator,
    Interval, datetime
)

组件说明

  • StrategyTemplate: CTA策略模板基类
  • TickData, BarData, TradeData, OrderData: 数据容器,分别存储Tick、K线、成交和委托信息
  • BarGenerator: K线生成模块,用于合成K线数据
  • ArrayManager: K线时间序列管理模块,支持技术指标计算

2.2 定义策略参数与变量

在策略类中,可定义策略的作者(author)、参数(parameters)和变量(variables)。

class TurtleStrategy(StrategyTemplate):
    """经典海龟交易策略"""
    
    author = "创新技术阁"
    
    # 策略参数
    entry_window = 90    # 入场窗口
    exit_window = 60     # 离场窗口
    atr_window = 12      # ATR计算窗口
    risk_level = 5000.0  # 风险水平
    
    # 策略变量
    trading_size = 0.0   # 交易手数
    trading_target = 0.0 # 目标仓位
    trading_pos = 0.0    # 当前仓位
    entry_up = 0.0       # 入场上限
    entry_down = 0.0     # 入场下限
    exit_up = 0.0        # 离场上限
    exit_down = 0.0      # 离场下限
    atr_value = 0.0      # ATR值
    long_entry = 0.0     # 多头入场价
    short_entry = 0.0    # 空头入场价
    long_stop = 0.0      # 多头止损价
    short_stop = 0.0     # 空头止损价
    
    # 参数与变量列表
    parameters = ["entry_window""exit_window""atr_window""risk_level"]
    variables = [
        "trading_size""trading_target""trading_pos",
        "entry_up""entry_down""exit_up""exit_down""atr_value"
    ]

2.2.1 参数与变量的区别

  • 策略参数: 由交易员外部指定,固定不变
  • 策略变量: 随交易过程动态变化,初始化为默认值(如0或0.0)

2.2.2 显示与保存

若需在CTA引擎UI界面显示参数和变量,并在数据刷新或停止策略时保存数值,需将其名称以字符串形式添加到parameters和variables列表中。
注意: 列表仅支持str、int、float和bool类型,其他类型需在__init__函数中定义。

2.3 类的初始化

2.3.1 函数名称__init__

  • 入参: cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict
  • 出参: 无
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
    super().__init__(cta_engine, strategy_name, vt_symbol, setting)
    
    # 初始化K线生成器
    self.bg = BarGenerator(
        on_bar=lambda bar: None,
        window=1,
        on_window_bar=self.on_window_bar,
        interval=Interval.HOUR
    )
    
    # 初始化K线序列管理器
    self.am = ArrayManager()
    
    # 加载历史数据
    self.load_bars(5, Interval.MINUTE)

策略类的构造函数__init__,需与StrategyTemplate保持一致。初始化分三步:

  1. 继承模板: 通过super()传入CTA引擎、策略名称、vt_symbol和参数设置(支持实盘与回测引擎)
  2. K线生成: 使用BarGenerator将Tick数据合成为1小时K线
  3. 序列管理: 使用ArrayManager将K线数据转化为时间序列,支持技术指标计算

2.4 回调函数

StrategyTemplate中的on_开头的函数为回调函数,由CTA引擎在特定事件触发时自动调用。按功能分为三类:

2.4.1 策略状态控制

on_init

  • 功能: 初始化策略
  • 示例:
def on_init(self):
    self.trading_symbol = self.vt_symbols[0]
    self.bar_dt = None
    self.bg = BarGenerator(
        on_bar=lambda bar: None,
        window=1,
        on_window_bar=self.on_window_bar,
        interval=Interval.HOUR
    )
    self.am = ArrayManager()
    self.load_bars(5, Interval.MINUTE)
    self.write_log("策略初始化完成")
  • 说明: 调用后inited状态变为True,此时仅计算指标,不发交易信号。基于Tick回测需调用load_tick。

on_start

  • 功能: 启动策略
  • 示例:
def on_start(self):
    self.write_log("策略启动")
  • 说明: 调用后trading状态变为True,可发交易信号。

on_stop

  • 功能: 停止策略
  • 示例:
def on_stop(self):
    self.write_log("策略停止")
  • 说明: 调用后trading状态变为False,停止交易信号。

2.4.2 数据接收与交易信号

on_tick

  • 功能: 处理Tick数据更新
  • 示例:
def on_tick(selftick: TickData):
    self.bg.update_tick(tick)
    if not tick.extra or not tick.extra.get("bar"):
        return
    bar = tick.extra["bar"]
    bar_dt = bar.datetime
    if self.bar_dt and bar_dt == self.bar_dt:
        return
    self.bar_dt = bar_dt
    bars = {bar.vt_symbol: bar}
    self.on_bars(bars)
  • 说明: 将Tick数据推进BarGenerator合成K线。

on_bars

  • 功能: 处理K线数据更新并生成交易信号
  • 示例:
def on_bars(self, bars: dict[str, BarData]):
    self.cancel_all()
    bar = bars[self.trading_symbol]
    self.bg.update_bar(bar)
    if not self.am.inited:
        return
    min_volume = self.get_min_volume(self.trading_symbol)
    decimal_num = get_decimal_places_via_decimal_lib(min_volume)
    if not self.trading_target:  # 无仓位
        self.atr_value = self.am.atr(self.atr_window)
        self.trading_size = round(self.risk_level / self.atr_value, decimal_num)
        if bar.high_price >= self.entry_up:
            self.trading_target = self.trading_size
        elif bar.low_price <= self.entry_down:
            self.trading_target = -self.trading_size
    elif self.trading_target > 0:  # 多头
        if bar.low_price <= self.exit_down:
            self.trading_target = 0
    elif self.trading_target < 0:  # 空头
        if bar.high_price >= self.exit_up:
            self.trading_target = 0
    pricetick = self.get_pricetick(self.trading_symbol)
    trading_volume = round_to(self.trading_target - self.trading_pos, min_volume)
    if trading_volume > 0:
        buy_price = round_to(bar.close_price * 1.01, pricetick)
        self.buy(self.trading_symbol, buy_price, abs(trading_volume))
    elif trading_volume < 0:
        short_price = round_to(bar.close_price * 0.99, pricetick)
        self.short(self.trading_symbol, short_price, abs(trading_volume))
    self.put_event()
  • 说明: 基于1分钟K线数据进行交易决策。

on_window_bar

  • 功能: 处理窗口K线更新
  • 示例:
def on_window_bar(self, bar: BarData):
    self.am.update_bar(bar)
    if not self.am.inited:
        return
    self.entry_up, self.entry_down = self.am.donchian(self.entry_window)
    self.exit_up, self.exit_down = self.am.donchian(self.exit_window)
    self.put_event()
  • 说明: 基于1小时K线计算入场和离场点。

2.4.3 委托状态更新

on_trade

  • 功能: 处理成交回报
  • 示例:
def on_trade(selftrade: TradeData):
    trade.strategy = self.strategy_name
    self.trading_pos = self.get_pos(self.trading_symbol)
    self.put_event()

on_order

  • 功能: 处理委托回报
  • 示例:
def on_order(self, order: OrderData):
    pass

2.5 交易函数

  • buy: 买入开仓
  • sell: 卖出平仓
  • short: 卖出开仓
  • cover: 买入平仓
  • 入参: price: float, volume: float, stop: bool = False, lock: bool = False, net: bool = False
  • 出参: vt_orderids: List[str] 或 无

2.6 委托与撤单

  • send_order: 发送委托(由引擎调用)
  • cancel_order: 撤销指定委托
  • cancel_all: 撤销所有委托

注意: 仅在trading状态为True时可发送或撤销委托。