vnpy海龟交易策略实现
本策略主要实行海龟交易的运行与回测
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 策略统计指标计算完成