CTA:策略实现

策略是模板类的子类

一个策略就是一个继承自模板类的子类。每个策略放在单独的.py脚本文件中。

策略文件可以放在两个地方:

  • vnpy_ctastrategy -> strategies
  • working_diretory -> strategies

下面以最简单的双均线策略做一个示例。

示例:双均线策略

package

from vnpy_ctastrategy import (
    CtaTemplate,
    StopOrder,
    TickData,
    BarData,
    TradeData,
    OrderData,
    BarGenerator,
    ArrayManager
)
from vnpy.trader.object import Interval

此处导入了两个相当重要的东西:

  • BarGenerator:K线合成器
  • ArrayManager:K线池

他们在vnpy_ctastrategy -> __init__.py中被导入,实际定义在vnpy.trader.utility中。

策略设置

class DoubleMaStrategy(CtaTemplate):
    """双均线策略"""
    author = "ZhuZhihao"

    fast_window = 5
    slow_window = 10
    fixed_size = 1

    fast_ma0 = 0.0
    fast_ma1 = 0.0

    slow_ma0 = 0.0
    slow_ma1 = 0.0

    parameters = ["fast_window", "slow_window", "fixed_size"]
    variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"]

__init__之前,定义了parametersvariables两组变量。它们的区别在于:

  • parameters需要设置,是策略的参数
  • variables是参数运行时的中间重要变量

在本例中

  • parameters = ["fast_window", "slow_window", "fixed_size"]是设置双均线的时间窗口。
  • variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"]则定义了一组变量,来保存双均线的上个和上上个值。这些变量可以在策略运行中被查看。
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
    """"""
    super().__init__(cta_engine, strategy_name, vt_symbol, setting)

    self.bar_generator = BarGenerator(self.on_bar)
    self.array_manager = ArrayManager(2*max(self.fast_window, self.slow_window))

__init__函数中,定义了BarGeneratorArrayManager的实例。

def on_init(self) -> None:
    """
    Callback when strategy is inited.
    """
    self.write_log("策略初始化")
    self.load_bar(2*max(self.fast_window, self.slow_window), use_database=True)

策略初始化后,触发回调函数on_init。它会自动初始化K线池。

load_bar函数追溯如下:vnpy_ctastrategy.template.load_bar() -> vnpy_ctastrategy.backtesting.load_bar()

def load_bar(
    self,
    days: int,
    interval: Interval = Interval.MINUTE,
    callback: Callable = None,
    use_database: bool = False
) -> None:
    """
    Load historical bar data for initializing strategy.
    """
    if not callback:
        callback: Callable = self.on_bar

    bars: List[BarData] = self.cta_engine.load_bar(
        self.vt_symbol,
        days,
        interval,
        callback,
        use_database
    )

    for bar in bars:
        callback(bar)

当中self.cta_engine.load_bar()实际把数据读进来保存在bars中,再对每一根K线调用回调函数callback。若策略以K线为回测频率,则回调函数设为on_bar,见:callback: Callable = self.on_bar

策略逻辑

策略逻辑写在回调函数中。

def on_tick(self, tick: TickData):
    """
    Callback of new tick data update.
    """
    self.bar_generator.update_tick(tick)

on_tick()函数的作用是接收Tick数据,并将Tick数据合成为K线数据。此处可以自定义,灵活实现各种频率上的K线。在K线合成器的update_tick()中,合成K线后,会调用策略类的回调函数on_bar()

def on_bar(self, bar: BarData) -> None:
    """
    Callback of new bar data update.
    """
    array_manager = self.array_manager
    array_manager.update_bar(bar)
    if not array_manager.inited:
        return

承接上文,对每一根K线调用回调函数时,第一步是更新K线池。这样,就维护了一个始终含有最新信息的K线池。

    fast_ma = array_manager.sma(self.fast_window, array=True)
    self.fast_ma0 = fast_ma[-1]
    self.fast_ma1 = fast_ma[-2]

    slow_ma = array_manager.sma(self.slow_window, array=True)
    self.slow_ma0 = slow_ma[-1]
    self.slow_ma1 = slow_ma[-2]
    # 金叉
    cross_over = self.fast_ma0 > self.slow_ma0 and self.fast_ma1 < self.slow_ma1
    # 死叉
    cross_below = self.fast_ma0 < self.slow_ma0 and self.fast_ma1 > self.slow_ma1

ArrayManager内置了技术指标的计算方法,用talib实现。

双均线策略逻辑为:

  • 分别计算双均线前一个、前两个时刻的值
  • 金叉:快均线上穿慢均线,做多
  • 死叉:慢均线上穿快均线,做空

    if cross_over:
        if self.pos == 0:
            self.buy(bar.close_price, self.fixed_size)
        elif self.pos < 0:
            self.cover(bar.close_price, abs(self.pos))
            self.buy(bar.close_price, self.fixed_size)
    elif cross_below:
        if self.pos == 0:
            self.short(bar.close_price, self.fixed_size)
        elif self.pos > 0:
            self.sell(bar.close_price, abs(self.pos))
            self.short(bar.close_price, self.fixed_size)

    self.put_event()
posted @ 2025-02-15 15:49  superzzh  阅读(14)  评论(0编辑  收藏  举报