from typing import List, Dict from datetime import datetime from operator import itemgetter from vnpy.app.portfolio_strategy import StrategyTemplate, StrategyEngine from vnpy.trader.utility import BarGenerator, ArrayManager from vnpy.trader.object import TickData, BarData from vnpy.trader.constant import Interval class Macd10Strategy(StrategyTemplate): """""" author = "KeKe" price_add_percent = 0.05 # 超价5%下单 fixed_pos_value = 100000 # 每个合约做100万 trade_day = 0 targets_pos = {} macd_data = {} target_cs = {} target_total = {} parameters = [ "price_add_percent", "fixed_size", ] variables = [ ] 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.bgs: Dict[str, BarGenerator] = {} self.ams: Dict[str, ArrayManager] = {} self.last_tick_time: datetime = None # Obtain contract info for vt_symbol in self.vt_symbols: def on_bar(bar: BarData): """""" pass self.bgs[vt_symbol] = BarGenerator(on_bar) self.ams[vt_symbol] = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bars(10, interval=Interval.DAILY) 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. """ if ( self.last_tick_time and self.last_tick_time.minute != tick.datetime.minute ): bars = {} for vt_symbol, bg in self.bgs.items(): bars[vt_symbol] = bg.generate() self.on_bars(bars) bg: BarGenerator = self.bgs[tick.vt_symbol] bg.update_tick(tick) self.last_tick_time = tick.datetime def on_bars(self, bars: Dict[str, BarData]): """""" # MACD指标计算 for vt_symbol, bar in bars.items(): am: ArrayManager = self.ams[vt_symbol] am.update_bar(bar) x, y, macd = am.macd(10, 20, 5) self.macd_data[vt_symbol] = macd # 按照MACD从小到大排序 sorted_l = sorted(self.macd_data.items(), key=itemgetter(1)) len_symbol = len(sorted_l) # 10 choose = int(0.25 * len_symbol) # int(2.5) =2 short_part = dict(sorted_l[:choose]) long_part = dict(sorted_l[-choose:]) not_trade_part = dict(sorted_l[choose: -choose]) for k in short_part: self.target_cs[k] = -1 for k in long_part: self.target_cs[k] = 1 for k in not_trade_part: self.target_cs[k] = 0 # 信号汇总 for vt_symbol, bar in bars.items(): self.target_total[vt_symbol] = self.target_cs[vt_symbol] self.targets_pos[vt_symbol] = int( self.fixed_pos_value / bar.close_price ) * self.target_total[vt_symbol] # 交易执行 if self.trade_day == 0 or not (self.trade_day + 0) % 10: for vt_symbol in self.vt_symbols: bar = bars.get(vt_symbol) if not bar: continue target_pos = self.targets_pos[vt_symbol] current_pos = self.get_pos(vt_symbol) pos_diff = target_pos - current_pos if pos_diff > 0: price = bar.close_price * (1 + self.price_add_percent) if current_pos < 0: self.cover(vt_symbol, price, pos_diff) else: self.buy(vt_symbol, price, pos_diff) elif pos_diff < 0: price = bar.close_price * (1 - self.price_add_percent) if current_pos > 0: self.sell(vt_symbol, price, - pos_diff) else: self.short(vt_symbol, price, - pos_diff) self.trade_day += 1 self.put_event()