一个用portfolio_strategy模块,写的 多标的 双均线策略,有2个标的,策略的数据源是 mongodb,不同的标的使用,不同的表
(1)请大家看看,有什么地方可以修改,优化,简洁一些 ?
我指的优化,不是指策略本身,意思指,在使用 portfolio_strategy模块方面,有什么改善的地方?
(2)如果建立股票池,股票池的 标的和数量 ,过一段时间就会改变,使用portfolio_strategy模块,策略怎么样写?
谢谢大家
from vnpy.app.cta_strategy.backtesting import BacktestingEngine
from datetime import datetime
from importlib import reload
import vnpy.app.portfolio_strategy
reload(vnpy.app.portfolio_strategy)
from vnpy.app.portfolio_strategy import BacktestingEngine
import vnpy.app.portfolio_strategy.strategies.pair_trading_strategy as stg
reload(stg)
from vnpy.trader.constant import Interval, Direction, Offset
from typing import List, Dict
from vnpy.trader.object import BarData, TickData, OrderData, TradeData
from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine
from vnpy.trader.utility import BarGenerator, ArrayManager
from vnpy.trader.object import TickData, BarData
engine = BacktestingEngine()
engine.set_parameters(
vt_symbols=["000001.SZSE","601518.SSE"],
interval=Interval.MINUTE,
start=datetime(2017, 7, 1),
end=datetime(2020, 9, 21),
rates={"000001.SZSE": 0/10000,"601518.SSE": 0/10000},
slippages={"000001.SZSE": 00,"601518.SSE": 0},
sizes={"000001.SZSE": 10,"601518.SSE": 10},
priceticks={"000001.SZSE": 1,"601518.SSE": 1},
capital=1_000_000,
collection_names={"000001.SZSE":'000001_bar',"601518.SSE":'601518_bar'}
)
class DemoStrategy2(StrategyTemplate):
""""""
author = "zhp168"
fast_window_1 = 10
slow_window_1 = 20
fast_ma0_1 = 0.0
fast_ma1_1 = 0.0
slow_ma0_1 = 0.0
slow_ma1_1 = 0.0
fast_window_2 = 10
slow_window_2 = 20
fast_ma0_2 = 0.0
fast_ma1_2 = 0.0
slow_ma0_2 = 0.0
slow_ma1_2 = 0.0
parameters = ["fast_window","slow_window"]
variables = ["fast_ma0","fast_ma1","slow_ma0","slow_ma1"]
def __init__(
self,
strategy_engine: StrategyEngine,
strategy_name: str,
vt_symbols: List[str],
setting: dict
):
""""""
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
self.bg = BarGenerator(self.on_bar)
self.am_1 = ArrayManager()
self.am_2 = ArrayManager()
self.vt_symbol_1 = vt_symbols[0]
self.vt_symbol_2 = vt_symbols[1]
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bars(20)
def on_start(self):
"""
Callback when strategy is started.
"""
self.write_log("策略启动")
def on_stop(self):
"""
Callback when strategy is stopped.
"""
self.write_log("策略停止")
def on_tick(self, tick: TickData):
"""
Callback of new tick data update.
"""
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
bars = {bar.vt_symbol: bar}
self.on_bars(bars)
def on_bars(self, bars: Dict[str, BarData]):
""""""
self.cancel_all()
bar_1 = bars[self.vt_symbol_1]
am_1 = self.am_1
am_1.update_bar(bar_1)
if not am_1.inited:
return
bar_2 = bars[self.vt_symbol_2]
am_2 = self.am_2
am_2.update_bar(bar_2)
if not am_2.inited:
return
# 第一个标的,计算快速均线
fast_ma_1 = am_1.sma(self.fast_window_1, array=True)
self.fast_ma0_1 = fast_ma_1[-1] # T时刻数值
self.fast_ma1_1 = fast_ma_1[-2] # T-1时刻数值
# 第二个标的,计算快速均线
fast_ma_2 = am_2.sma(self.fast_window_2, array=True)
self.fast_ma0_2 = fast_ma_2[-1] # T时刻数值
self.fast_ma1_2 = fast_ma_2[-2] # T-1时刻数值
# 第一个标的,计算慢速均线
slow_ma_1 = am_1.sma(self.slow_window_1, array=True)
self.slow_ma0_1 = slow_ma_1[-1]
self.slow_ma1_1 = slow_ma_1[-2]
# 第二个标的,计算慢速均线
slow_ma_2 = am_2.sma(self.slow_window_2, array=True)
self.slow_ma0_2 = slow_ma_2[-1]
self.slow_ma1_2 = slow_ma_2[-2]
# 获取仓位
pos_1 = self.get_pos(self.vt_symbol_1)
pos_2 = self.get_pos(self.vt_symbol_2)
# 判断是否金叉
cross_over_1 = (self.fast_ma0_1 > self.slow_ma0_1 and
self.fast_ma1_1 < self.slow_ma1_1)
cross_over_2 = (self.fast_ma0_2 > self.slow_ma0_2 and
self.fast_ma1_2 < self.slow_ma1_2)
# 判断是否死叉
cross_below_1 = (self.fast_ma0_1 < self.slow_ma0_1 and
self.fast_ma1_1 > self.slow_ma1_1)
cross_below_2 = (self.fast_ma0_2 < self.slow_ma0_2 and
self.fast_ma1_2 > self.slow_ma1_2)
# 如果发生了金叉
if cross_over_1:
# 为了保证成交,在K线收盘价上加5发出限价单
price = bar_1.close_price + 5
# 当前无仓位,则直接开多
if pos_1 == 0:
self.buy(self.vt_symbol_1,price, 1)
# 当前持有空头仓位,则先平空,再开多
elif pos_1 < 0:
self.cover(self.vt_symbol_1,price, 1)
self.buy(self.vt_symbol_1,price, 1)
# 如果发生了死叉
elif cross_below_1:
price = bar_1.close_price - 5
# 当前无仓位,则直接开空
if pos_1 == 0:
self.short(self.vt_symbol_1,price, 1)
# 当前持有空头仓位,则先平多,再开空
elif pos_1 > 0:
self.sell(self.vt_symbol_1,price, 1)
self.short(self.vt_symbol_1,price, 1)
---------------------------------------------------------------------------------------------
# 如果发生了金叉
if cross_over_2:
# 为了保证成交,在K线收盘价上加5发出限价单
price = bar_2.close_price + 5
# 当前无仓位,则直接开多
if pos_2 == 0:
self.buy(self.vt_symbol_2, price, 1)
# 当前持有空头仓位,则先平空,再开多
elif pos_2 < 0:
self.cover(self.vt_symbol_2, price, 1)
self.buy(self.vt_symbol_2, price, 1)
# 如果发生了死叉
elif cross_below_2:
price = bar_2.close_price - 5
# 当前无仓位,则直接开空
if pos_2 == 0:
self.short(self.vt_symbol_2, price, 1)
# 当前持有空头仓位,则先平多,再开空
elif pos_2 > 0:
self.sell(self.vt_symbol_2, price, 1)
self.short(self.vt_symbol_2, price, 1)
self.put_event()
def update_trade(self, trade: TradeData):
print("股票编号:", trade.symbol, "成交时间:", trade.datetime, "成交价格:", trade.price)
print("方向:", trade.direction, trade.direction.value, "offset:", trade.offset, "成交量:", trade.volume)
engine.add_strategy(DemoStrategy2,{})
engine.load_data()
engine.run_backtesting()
df = engine.calculate_result()
engine.calculate_statistics()
engine.show_chart()