本策略主要实行海龟交易的运行与回测

1、止损止盈机制

2、加仓减仓机制

from vnpy.app.cta_strategy.template import CtaTemplate
from typing import Any
from vnpy.trader.object import BarData, Interval, TickData, TradeData, OrderData, Direction, Offset
from vnpy.trader.utility import BarGenerator, ArrayManager
from datetime import datetime
from vnpy.app.cta_strategy.backtesting import BacktestingEngine, OptimizationSetting
from vnpy.app.cta_strategy.base import StopOrder
import talib


class BitquantTurtleStrategy(CtaTemplate):

    entry_window = 30
    exit_window = 13
    atr_window = 14
    risk_loss_money = 10000  # 1% - 2%  4次加仓

    long_entry_price = 0.0  # 多头进场价格
    short_entry_price = 0.0   # 空头进场价格
    long_stop_loss_price = 0.0
    short_stop_loss_price = 0.0
    atr_value = 0.0  # atr值

    trade_highest_price = 0.0
    trade_lowest_price = 0.0
    trade_volume = 0

    parameters = ["entry_window", "exit_window", "atr_window", "risk_loss_money"]
    variables = ["long_entry_price", "short_entry_price", "atr_value", "long_stop_loss_price",
                 "short_stop_loss_price", "trade_highest_price", "trade_lowest_price", "trade_volume"]

    def __init__(
            self,
            cta_engine: Any,
            strategy_name: str,
            vt_symbol: str,
            setting: dict):
        super(BitquantTurtleStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting)

        self.bg = BarGenerator(self.on_bar, window=1, on_window_bar=self.on_hour_bar, interval=Interval.HOUR)
        self.am = ArrayManager(300)

        self.sell_stop_orders = []
        self.cover_stop_orders = []

    def on_init(self):
        print("on init")
        self.load_bar(3)

    def on_start(self):
        """
        Callback when strategy is started.
        """
        print("on_start strategy")

    def on_tick(self, tick: TickData):
        self.bg.update_tick(tick)

    def on_bar(self, bar: BarData):
        self.bg.update_bar(bar)

    def on_hour_bar(self, bar: BarData):

        self.cancel_all()  # 先撤单
        self.sell_stop_orders = []
        self.cover_stop_orders = []

        self.am.update_bar(bar)

        if not self.am.inited:
            return

        entry_up, entry_dn = self.am.donchian(self.entry_window)
        exit_up, exit_dn = self.am.donchian(self.exit_window)

        atr_value = self.am.atr(self.atr_window)

        if self.pos == 0:  # 没有仓位
            self.trade_highest_price = bar.high_price
            self.trade_lowest_price = bar.low_price

            self.atr_value = atr_value
            self.trade_volume = self.risk_loss_money/(self.atr_value * 2)
            self.buy(entry_up, self.trade_volume, stop=True)
            self.sell(entry_dn, self.trade_volume, stop=True)

        elif self.pos > 0:  # 有多头仓位
            self.trade_highest_price = max(self.trade_highest_price, bar.high_price)
            self.trade_lowest_price = min(self.trade_lowest_price, bar.low_price)

            # draw_back_price = self.trade_lowest_price - atr_value * 3
            # sell_price = max(exit_dn, self.long_stop_loss_price, draw_back_price)
            #
            # self.sell_stop_orders = self.sell(sell_price, abs(self.pos), True)

            if bar.close_price > self.long_entry_price:
                draw_back_price = self.trade_highest_price - atr_value * 3
                self.long_stop_loss_price = max(exit_dn, self.long_stop_loss_price, draw_back_price)
                self.sell_stop_orders = self.sell(self.long_stop_loss_price, abs(self.pos), True)
            else:
                sell_price = max(exit_dn, self.long_stop_loss_price)
                self.sell_stop_orders = self.sell(sell_price, abs(self.pos), True)

            # if self.pos / self.trade_volume < 4:
            if self.pos / self.trade_volume < 2:
                self.buy(self.long_entry_price + self.atr_value/2, self.trade_volume, stop=True)

        elif self.pos < 0:   # 有空头仓位
            self.trade_highest_price = max(self.trade_highest_price, bar.high_price)
            self.trade_lowest_price = min(self.trade_lowest_price, bar.low_price)

            # draw_back_price = self.trade_lowest_price + atr_value * 3
            # cover_price = min(exit_up, self.short_stop_loss_price, draw_back_price)
            # self.cover_stop_orders = self.cover(cover_price, abs(self.pos), True)

            if bar.close_price < self.short_entry_price:
                draw_back_price = self.trade_lowest_price + atr_value * 3
                self.short_stop_loss_price = min(exit_up, self.short_stop_loss_price, draw_back_price)
                self.cover_stop_orders = self.cover(self.short_stop_loss_price, abs(self.pos), True)
            else:
                cover_price = min(exit_up, self.short_stop_loss_price)
                self.cover_stop_orders = self.cover(cover_price, abs(self.pos), True)


            # if self.pos / self.trade_volume > -4:
            if self.pos / self.trade_volume > -2:
                self.short(self.short_entry_price - self.atr_value/2, self.trade_volume, stop=True)

    def on_trade(self, trade: TradeData):
        # print(f"on trade {trade}")
        if self.pos != 0:
            if trade.direction == Direction.LONG and trade.offset == Offset.OPEN:
                self.long_entry_price = trade.price
                self.long_stop_loss_price = self.long_entry_price - 2 * self.atr_value

                # for vt_id in self.sell_stop_orders:
                #     self.cancel_order(vt_id)
                self.cancel_all()

                self.sell_stop_orders = self.sell(self.long_stop_loss_price, abs(self.pos), True)

                # if self.pos/self.trade_volume < 4: # 一次进场 3次加仓
                if self.pos / self.trade_volume < 2:  # 一次进场 3次加仓
                    self.buy(self.long_entry_price + self.atr_value/2, self.trade_volume, stop=True)

            elif trade.direction == Direction.SHORT and trade.offset == Offset.OPEN:
                self.short_entry_price = trade.price
                self.short_stop_loss_price = self.short_entry_price + 2 * self.atr_value

                # for vt_id in self.cover_stop_orders:
                #     self.cancel_order(vt_id)
                self.cancel_all()

                self.cover_stop_orders = self.cover(self.short_stop_loss_price, abs(self.pos), True)

                # if self.pos/self.trade_volume > -4:
                # self.cover()
                if self.pos/self.trade_volume > -2:
                    self.short(self.short_entry_price-self.atr_value/2, self.trade_volume, stop=True)

        elif self.pos == 0:
            self.cancel_all()

    def on_order(self, order: OrderData):
        pass
        # print(f"on order {order}")

    def on_stop_order(self, stop_order: StopOrder):
        pass
        # print(f"on stop order {stop_order}")



if __name__ == '__main__':
    # 回测引擎初始化
    engine = BacktestingEngine()

    # 设置交易对产品的参数
    engine.set_parameters(
        vt_symbol="XBTUSD.BITMEX",  # 交易的标的
        interval=Interval.MINUTE,
        start=datetime(2018, 1, 1),  # 开始时间
        rate=7.5 / 10000,  # 手续费
        slippage=0.5,  # 交易滑点
        size=1,  # 合约乘数
        pricetick=0.5,  # 8500.5 8500.01
        capital=1000000,  # 初始资金
        # end=datetime(2018, 6, 1)  # 结束时间
    )

    # 添加策略
    engine.add_strategy(BitquantTurtleStrategy, {})

    # 加载
    engine.load_data()

    # # 运行回测
    engine.run_backtesting()

    # 统计结果
    engine.calculate_result()

    # 计算策略的统计指标 Sharp ratio, drawdown
    engine.calculate_statistics()

    # 绘制图表
    engine.show_chart()
    """
    "total_return": total_return,
    "annual_return": annual_return,
    "daily_return": daily_return,
    "return_std": return_std,
    "sharpe_ratio": sharpe_ratio,
    "return_drawdown_ratio": return_drawdown_ratio,
    """
    # setting = OptimizationSetting()
    # setting.set_target("sharpe_ratio")
    # setting.add_parameter("entry_window", 10, 300, 1)
    # setting.add_parameter("exit_window", 5, 50, 1)
    # setting.add_parameter("atr_window", 10, 50, 1)
    # engine.run_ga_optimization(setting)  # 遗传算法优化.

    # engine.run_optimization()  # 多线程优化.

最终的执行结果为

2020-11-19 15:14:57.137545	开始计算策略统计指标
2020-11-19 15:14:57.145523	------------------------------
2020-11-19 15:14:57.145523	首个交易日:	2018-01-03
2020-11-19 15:14:57.145523	最后交易日:	2019-10-30
2020-11-19 15:14:57.145523	总交易日:	666
2020-11-19 15:14:57.145523	盈利交易日:	218
2020-11-19 15:14:57.146520	亏损交易日:	363
2020-11-19 15:14:57.146520	起始资金:	1,000,000.00
2020-11-19 15:14:57.146520	结束资金:	2,756,262.91
2020-11-19 15:14:57.146520	总收益率:	175.63%
2020-11-19 15:14:57.146520	年化收益:	63.29%
2020-11-19 15:14:57.146520	最大回撤: 	-249,118.24
2020-11-19 15:14:57.146520	百分比最大回撤: -17.48%
2020-11-19 15:14:57.146520	最长回撤天数: 	44
2020-11-19 15:14:57.146520	总盈亏:	1,756,262.91
2020-11-19 15:14:57.146520	总手续费:	1,426,578.95
2020-11-19 15:14:57.146520	总滑点:	161,731.36
2020-11-19 15:14:57.146520	总成交金额:	1,902,105,263.13
2020-11-19 15:14:57.146520	总成交笔数:	2039
2020-11-19 15:14:57.146520	日均盈亏:	2,637.03
2020-11-19 15:14:57.146520	日均手续费:	2,142.01
2020-11-19 15:14:57.146520	日均滑点:	242.84
2020-11-19 15:14:57.146520	日均成交金额:	2,856,013.91
2020-11-19 15:14:57.146520	日均成交笔数:	3.0615615615615615
2020-11-19 15:14:57.146520	日均收益率:	0.15%
2020-11-19 15:14:57.146520	收益标准差:	2.34%
2020-11-19 15:14:57.146520	Sharpe Ratio:	1.01
2020-11-19 15:14:57.146520	收益回撤比:	10.05
2020-11-19 15:14:57.146520	策略统计指标计算完成