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 策略统计指标计算完成