class MaTrendStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [10, 20, 30, 60, 120] request_order = [] close_order = [] volumn = 0 kdj_record = [] parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] add_pos = False safe_price = None ma_info = pd.DataFrame() closeout_offset = 0.003 trade_mgr: TradeMgr = None def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(MaTrendStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 1, self.on_1min_bar, tz_info=eastern) self.am = ArrayManager(400) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar, tz_info=eastern) self.am5 = ArrayManager(100) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar, tz_info=eastern) self.trade_mgr = TradeMgr(self, setting["capital"], OrderType.MARKET, {}) self.closeout_offset = 0.003 self.clock = ClockManager(datetime.time(hour=9, minute=30), datetime.time(hour=16, minute=0)) self.std_range = IntervalGen(np.std, 5) self.std_range3 = IntervalGen(np.std, 5) self.std_range5 = IntervalGen(np.std, 5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) self.offset = 40 self.init_datacreator() def init_datacreator(self): self.data_center = DataCenter(component={ "array_manager_1": self.am, "clock": self.clock }) self.data_creator = { "ma_info": MaInfoCreator(self.data_center), "trend_info": TrendInfoCreator(self.data_center), "ma_dist": MaDistCreator(self.data_center) } self.ma_info = self.data_creator["ma_info"] self.data_center.connect("trend_info", self.on_new_trend) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(5) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return pattern = self.am3.pattern( [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS]) if len(pattern) > 0: print(pattern) self.pattern_record.add_pattern(pattern) # deg = calc_regress_deg(self.am3.close[-20:]) def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return def closeout_strategy(self, am: ArrayManager, bar: BarData, calc_data): if self.trade_mgr.get_status() == PositionStatus.Short: if bar.close_price > self.closeout_price: calc_data["trade_close"] = "平仓:到达最低价{}".format( self.closeout_price) return self.trade_mgr.cover(bar.close_price) # return self.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET, # extra={"reason": "平仓:到达最低价{}".format(self.closeout_price)}) elif self.trade_mgr.get_status() == PositionStatus.Long: if bar.close_price < self.closeout_price: calc_data["trade_close"] = "平仓:到达最低价{}".format( self.closeout_price) return self.trade_mgr.sell(bar.close_price) # return self.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET, # extra={"reason": "平仓:到达最低价{}".format(self.closeout_price)}) ''' 检测3个ma闭合,空仓状态时如果小于0.01则标记起点,随后检测4个ma的穿越,计算角度,并买入。 根据时间和升幅进行加仓(急速提升的情况下,3ma的闭合间隙会加大), 3个ma如果遭遇再次闭合,则根据情况卖出 ''' def on_new_trend(self, data): self.trend_context = data["trend_info"] def range_score(self, am: ArrayManager, length): r_data = am.range[-length:] def ma_trend_strategy(self, am: ArrayManager, bar: BarData, calc_data): context = self.trend_context if context == None: return deg = context["deg"] data = context["data"] sign = context["sign"] if self.pos == 0: ma120 = self.ma_info.info[120] deg120 = calc_regress_deg(ma120[-5:], False) if deg < 0: calc_data["trade_open"] = "开空,deg={}".format(deg) sign() ratio = 0.2 if deg120 < 0 else 0.1 return self.trade_mgr.short(bar.close_price, ratio, {}) elif deg > 0: calc_data["trade_open"] = "开多,deg={}".format(deg) sign() ratio = 0.2 if deg120 > 0 else 0.1 return self.trade_mgr.buy(bar.close_price, ratio, {}) def trend_reverse_close(self, am: ArrayManager, bar: BarData, calc_data): if self.trade_mgr.get_status() != PositionStatus.Empty: data = self.ma_info.info[-60:] length = len(data) close = (data[10] + data[20] + data[30]) / 3 if length > 10: y_fit = reg_util.regress_y_polynomial(close[-10:], zoom=True) deg = calc_regress_deg(y_fit[:10], False) else: deg = calc_regress_deg(close[-10:], False) calc_data["trade_close_deg"] = deg if self.trade_mgr.get_status() == PositionStatus.Short: if deg > 0.01: calc_data["trade_close"] = "平仓:趋势反转{}".format(deg) return self.trade_mgr.cover(bar.close_price) elif self.trade_mgr.get_status() == PositionStatus.Long: if deg < -0.01: calc_data["trade_close"] = "平仓:趋势反转{}".format(deg) return self.trade_mgr.sell(bar.close_price) def ma_close(self, am: ArrayManager, bar: BarData, calc_data): if self.safe_price is None: return rg = (bar.close_price / self.trade_price) - 1 close_price = None if rg > 0.01 and self.trade_mgr.get_status() == PositionStatus.Long: close_price = am.sma(120) elif rg < -0.01 and self.trade_mgr.get_status( ) == PositionStatus.Short: close_price = am.sma(120) for lvl in self.ma_level[-1:]: # if len(self.order_data) < lvl: close_price = am.sma(lvl) break if close_price is None: lvl = self.ma_level[-1] close_price = am.sma(lvl) if self.trade_mgr.get_status() == PositionStatus.Short: if bar.close_price > close_price: calc_data["trade_close"] = "平仓:到达MA均线价{}".format(close_price) return self.trade_mgr.cover(bar.close_price) # return self.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET, # extra= { "reason":"平仓:到达MA均线价{}".format(close_price)}) elif self.trade_mgr.get_status() == PositionStatus.Long: if bar.close_price < close_price: calc_data["trade_close"] = "平仓:到达MA均线价{}".format(close_price) return self.trade_mgr.sell(bar.close_price) # return self.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET, # extra={"reason": "平仓:到达MA均线价{}".format(close_price)}) # 加仓算法 def add_position(self, am: ArrayManager, bar: BarData, calc_data, setting={}): if self.safe_price is None: return if not (self.trade_mgr.get_status() == PositionStatus.Short and bar.close_price < self.safe_price or \ self.trade_mgr.get_status() == PositionStatus.Long and bar.close_price > self.safe_price): return am = self.am rg = (bar.close_price / self.trade_price) - 1 close_price = None if rg > 0.01 and self.trade_mgr.get_status() == PositionStatus.Long: close_price = am.sma(120) if not self.add_pos: self.add_pos = True # scale = 1 - 0.002 # self.closeout_price = round(bar.close_price * scale, 2) return self.trade_mgr.buy(bar.close_price, 0.1, {}) elif rg < -0.01 and self.trade_mgr.get_status( ) == PositionStatus.Short: close_price = am.sma(120) if not self.add_pos: self.add_pos = True # scale = 1 + 0.002 # self.closeout_price = round(bar.close_price * scale, 2) return self.trade_mgr.short(bar.close_price, 0.1, {}) def generate_data(self, am: ArrayManager, bar: BarData): offset = -self.offset offset_m = int(offset / 2) std_val3 = np.std(np.array(am.range[-30:-10])) kdj_val = am.kdj() has_kdj_recore = False k = kdj_val["k"] d = kdj_val["d"] j = kdj_val["j"] if (k[-1] > 75 and d[-1] > 75 and j[-1] > 75) or \ (k[-1] < 25 and d[-1] < 25 and j[-1] < 75): if (j[-2] < k[-2] or j[-2] < d[-2]) and (j[-1] > k[-1] and j[-1] > d[-1]) \ or \ (j[-2] > k[-2] or j[-2] > d[-2]) and (j[-1] < k[-1] and j[-1] < d[-1]): has_kdj_recore = True t = bar.datetime self.kdj_record.append( (t.strftime("%H:%M:%S"), round(k[-1], 3), round(d[-1], 3), round(j[-1], 3))) deg1 = calc_regress_deg(am.close[offset:offset_m], False) deg2 = calc_regress_deg(am.close[offset_m:], False) deg3 = calc_regress_deg(am.close[-10:], False) deg_full = calc_regress_deg(am.close[offset:], False) macd = am.macd(20, 40, 16) calc_data = (dict( kdj=[ round(kdj_val["k"][-1], 2), round(kdj_val["d"][-1], 2), round(kdj_val["j"][-1], 2) ], cci_20=am.cci(20), rsi=am.rsi(20), adx=am.adx(20), boll=am.boll(20, 3.4), macd=[round(macd[0], 2), round(macd[1], 2), round(macd[2], 2)], deg40_20=round(deg1, 2), deg20_0=round(deg2, 2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False), 2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False), 2), deg15_0=round(calc_regress_deg(am.close[-15:], False), 2), deg_f=round(deg_full, 2), deg30_10=round(calc_regress_deg(am.close[-30:-10], False), 2), deg10_0=round(deg3, 2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3), atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, mean_std=np.mean(self.std_range.data[-5:]), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list( map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), atr_mean=np.mean(am.atr(20, array=True, length=240)[-200:]), )) if self.ma_info.info.index.size >= 31: ma5 = self.ma_info.info[5][-31:] x = AnalyseWave(ma5) calc_data["ma5_info"] = x.optimize ma10 = self.ma_info.info[10][-31:] x = AnalyseWave(ma10) calc_data["ma10_info"] = x.optimize return calc_data def on_strategy(self, am: ArrayManager, bar: BarData, strategy_list, close_strategy_list, calc_data=None): order_id = None for open_strategy in strategy_list: if order_id is not None: break order_id = open_strategy(am, bar, calc_data) if order_id is None and self.pos != 0: for strategy in close_strategy_list: if order_id is not None: break order_id = strategy(am, bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append( (self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20_0"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def on_1min_bar(self, bar: BarData): self.trend_context = None self.am.update_bar(bar) am = self.am max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) self.data_center.push("bar_data", bar) self.data_center.push("array_manager", self.am) if not am.inited or not self.trading: return calc_data = self.generate_data(am, bar) open_strategy = [self.ma_trend_strategy, self.add_position] close_strategy = [ self.ma_trend_strategy2, self.closeout_strategy, self.trend_reverse_close ] self.on_strategy(am, bar, open_strategy, close_strategy, calc_data) # median_val = np.median(calc_nums) self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) self.bg.update_bar(bar) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},笔数为{},交易{},pos={}".format( order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value, order.price, order.volume, order.status.value, self.pos)) self.trade_mgr.on_order(order) if order.vt_orderid in self.request_order: if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.close_order.append(order.vt_orderid) def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.trade_mgr.on_trade(trade) if trade.vt_orderid in self.request_order: # self.positions.on_trade(trade) if self.volumn == 0: self.add_pos = False self.trade_price = trade.price if trade.direction == Direction.LONG: self.safe_price = trade.price * 1.003 scale = 1 - self.closeout_offset self.closeout_price = round(trade.price * scale, 2) elif trade.direction == Direction.SHORT: self.safe_price = trade.price * 0.997 scale = 1 + self.closeout_offset self.closeout_price = round(trade.price * scale, 2) if trade.direction == Direction.LONG: self.volumn += trade.volume elif trade.direction == Direction.SHORT: self.volumn -= trade.volume if trade.vt_orderid in self.close_order: self.request_order.remove(trade.vt_orderid) self.close_order.remove(trade.vt_orderid) self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def ma_trend_strategy2(self, am: ArrayManager, bar: BarData, calc_data): context = self.trend_context if context == None: return deg = context["deg"] data = context["data"] sign = context["sign"] if self.pos > 0 and deg < 0: ma120 = self.ma_info.info[120] calc_data["trade_open"] = "平仓并开空,deg={}".format(deg) sign() self.trade_mgr.sell(bar.close_price) return self.trade_mgr.short(bar.close_price, 0.1, {}) elif self.pos < 0 and deg > 0: calc_data["trade_open"] = "开多,deg={}".format(deg) sign() self.trade_mgr.cover(bar.close_price) return self.trade_mgr.buy(bar.close_price, 0.1, {}) '''
class MaLevelTrackStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [5, 10, 20, 30, 120] ma_tag = [] bd = [] fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 request_order = [] bar_identify = [] parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(MaLevelTrackStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 15, self.on_1min_bar) self.am = ArrayManager(400) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar) self.am5 = ArrayManager(120) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.order_data = None self.positions = Position(self) self.std_range = IntervalGen(np.std, 5) self.std_range3 = IntervalGen(np.std, 5) self.std_range5 = IntervalGen(np.std, 5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) five_min_open_5 = partial(self.reverse_shape_strategy, setting={ "atr": 10, "atr_valve": 0.8, "deg1": (10, 5), "deg2": 5 }) self.open_strategy = { "1": [self.reverse_shape_strategy], "5": [five_min_open_5], } self.offset = 40 self.ma120_track = None self.ma120_track_list = [] def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return pattern = self.am3.pattern( [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS]) if len(pattern) > 0: print(pattern) self.pattern_record.add_pattern(pattern) # deg = calc_regress_deg(self.am3.close[-20:]) def wave(self, data, window=0.0002): if len(data) <= 0: return # r = array[::-1] result = {"value": [], "range": [], "pos": [], "length": []} r = data l = len(data) - 1 now = r[0] # v_list.append(now) # p_list.append(0) pos = 1 vol = 0 u_tag = None d_tag = None end_tag = None start_pos = 0 while pos < l: if math.isnan(now): now = r[pos] pos += 1 continue else: start_pos = pos - 1 break while pos < l: if now < r[pos]: u_tag = pos if d_tag: diff = r[start_pos] - r[d_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 1: end_tag = d_tag elif now > r[pos]: d_tag = pos if u_tag: diff = r[start_pos] - r[u_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 1: end_tag = u_tag if end_tag is not None: result["range"].append(r[end_tag] / r[start_pos] - 1) result["length"].append(end_tag - start_pos) start_pos = end_tag result["value"].append(r[end_tag]) result["pos"].append(end_tag) end_tag = None vol += r[pos] - now now = r[pos] pos += 1 return pd.DataFrame(result) def mode_identify(self, bar: BarData): self.bar_identify = [] hl_scale = round(bar.high_price / bar.low_price - 1, 4) if hl_scale > 0.001: diff = bar.high_price - bar.low_price diff_up = bar.low_price + diff / 2 * 1.20 diff_down = bar.low_price + diff / 2 * 0.80 close = bar.close_price if bar.open_price < diff_up and bar.open_price > diff_down and \ bar.close_price < diff_up and bar.close_price > diff_down: if bar.close_price > bar.open_price: print("绿十字星", bar.datetime, bar.high_price, bar.low_price, diff, diff_up, diff_down, bar.open_price, bar.close_price) else: print("红十字星", bar.datetime, bar.high_price, bar.low_price, diff, diff_up, diff_down, bar.open_price, bar.close_price) def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return self.on_strategy(self.am5, bar, self.open_strategy["5"]) # pattern_list = [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS, KlinePattern.CDLCONCEALBABYSWALL, KlinePattern.CDLEVENINGDOJISTAR] # pattern = self.am5.pattern(list(KlinePattern)) # if len(pattern) > 0: # print(list(map(lambda x: (KLINE_PATTERN_CHINESE[x[0]],x[1]), pattern))) # self.pattern_record.add_pattern(pattern) # deg_full = calc_regress_deg(self.am.close[-40 :], False) # print("deg:",deg_full) # self.pattern_record.update() def open_v3(self, am: ArrayManager, bar: BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 3: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v1(self, am: ArrayManager, bar: BarData): offset = -40 offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) mean_val = np.mean(calc_nums) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) if std_val < 1 and mean_val < 2 and self.ma_tag[-1] >= (mean_val + 2): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif std_val < 1 and mean_val > 3 and self.ma_tag[-1] <= (mean_val - 2): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v2(self, am: ArrayManager, bar: BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 2.5: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2.5: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open2(self, am: ArrayManager, bar: BarData, calc_data): deg = calc_data["deg20"] ma = self.ma_tag[-1] if deg > 0.5 and ma > 3 and self.am5.range[-1] > -0.002: return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif deg < -0.5 and ma < 2 and self.am5.range[-1] < 0.002: return self.short(bar.close_price, 1, type=OrderType.MARKET) def open1(self, am: ArrayManager, bar: BarData, calc_data): mean = calc_data["mean30_10"] mean_val2 = calc_data["mean10"] # if std_val2 < 0.2: if mean_val2 > 3.5 and mean_val2 >= (mean + 2): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 1.5 and mean_val2 <= (mean - 2): return self.short(bar.close_price, 1, type=OrderType.MARKET) # v形反转捕获 def reverse_shape_strategy(self, am: ArrayManager, bar: BarData, calc_data, setting={ "atr": 40, "atr_valve": 0.8, "deg1": (40, 20), "deg2": (20, 0), }): deg1 = calc_data["deg40_20"] deg2 = calc_data["deg20_0"] kdj = calc_data["kdj"] atr = self.am.atr(40) if atr < 0.08: return if deg1 > 0 and deg2 > 0 or \ deg1 < 0 and deg2 < 0: return if not (abs(deg1) > 0.15 and abs(deg2) > 0.1 and (abs(deg1) + abs(deg2)) > 0.3): return close = am.close[-40:] min_val = np.min(close) max_val = np.max(close) mid_val = max_val if deg1 > 0 else min_val mid_pos = np.where(close == mid_val)[0][0] if mid_pos < 10 or mid_pos > 30: return start_val = np.min(close[:mid_pos]) if deg1 > 0 else np.max( close[:mid_pos]) start_pos = np.where(close == start_val)[0][0] l = mid_pos - start_pos # pos2 = np.where(close == min_val)[0][0] x_fit = reg_util.regress_y_polynomial(close[:mid_pos], zoom=True) deg1_remake = calc_regress_deg(x_fit[:abs(mid_pos)], False) y_fit = reg_util.regress_y_polynomial(close[mid_pos:], zoom=True) deg2_remake = calc_regress_deg(y_fit[:abs(mid_pos)], False) print(start_pos, mid_pos, deg1, deg2, deg1_remake, deg2_remake, l, start_val, mid_val) if deg2 < 0: if kdj[0] < 20 and kdj[1] < 10 and kdj[2] < 10: # if kdj[2] < 10: return self.short(bar.close_price, 1, type=OrderType.MARKET) else: if kdj[0] > 80 and kdj[1] > 90 and kdj[2] > 90: # if kdj[2] > 90: return self.buy(bar.close_price, 1, type=OrderType.MARKET) # print("找到大v形:", deg1, deg2 ) def open5(self, am: ArrayManager, bar: BarData, calc_data): ma = self.ma_tag[-1] mean = calc_data["mean30_10"] atr = self.am.atr(10, array=True, length=20) tr = self.am.atr(1, array=True, length=11) # self.ma120_track ma120 = self.am.sma(120) # if std_val2 < 0.2: mean_std = calc_data["mean_std"] if mean_std < 0.8 and tr[-1] > 0.1 and tr[-1] / tr[-10] > 3 and tr[ -1] / atr[-1] >= 1.7 and tr[-10] / atr[-10] < 1: if np.sum(self.am.range[-10:]) > 0 and self.ma120_track > 0: return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.ma120_track < 0: return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_kline1(self, am: ArrayManager, bar: BarData, calc_data): if KlinePattern.CDLEVENINGSTAR not in self.pattern_record: return # if std_val2 < 0.2: deg = calc_regress_deg(self.am.close[-5:], False) print("kline_strategy", deg) if deg < -0.1: return self.short(bar.close_price, 1, type=OrderType.MARKET) def generate_data(self, bar: BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(self.am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = self.am.kdj() deg1 = calc_regress_deg(self.am.close[offset:offset_m], False) deg2 = calc_regress_deg(self.am.close[offset_m:], False) deg3 = calc_regress_deg(self.am.close[-10:], False) deg_full = calc_regress_deg(self.am.close[offset:], False) wave = self.wave(self.am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd = self.am.macd(20, 40, 16) calc_data = (dict( kdj=[ round(kdj_val["k"][-1], 2), round(kdj_val["d"][-1], 2), round(kdj_val["j"][-1], 2) ], cci_20=self.am.cci(20), rsi=self.am.rsi(20), adx=self.am.adx(20), boll=self.am.boll(20, 3.4), macd=[round(macd[0], 2), round(macd[1], 2), round(macd[2], 2)], deg40_20=round(deg1, 2), deg20_0=round(deg2, 2), deg20_10=round(calc_regress_deg(self.am.close[-20:-10], False), 2), deg10_0=round(deg3, 2), deg30_15=round(calc_regress_deg(self.am.close[-30:-15], False), 2), deg15_0=round(calc_regress_deg(self.am.close[-15:], False), 2), deg_f=round(deg_full, 2), atr=round(self.am.atr(10, length=15), 3), tr=round(self.am.atr(1, length=2), 3), atr_40=round(self.am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2), mean40=round(mean_val, 2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2, 2), mean30_10=round(mean_val4, 2), mean10=round(mean_val2, 2), vol=self.am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=self.am.range[-1:-5:-1].tolist(), range_sum=np.sum(self.am.range[-5:]), pattern=list( map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(self.am.atr(20, array=True, length=240)[-200:]))) return calc_data def on_strategy(self, am: ArrayManager, bar: BarData, strategy_list): calc_data = self.generate_data(bar) order_id = None if self.pos == 0: for open_strategy in strategy_list: if order_id is not None: break order_id = open_strategy(am, bar, calc_data) else: order_id = self.positions.on_strategy(bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append( (self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20_0"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def on_1min_bar(self, bar: BarData): self.am.update_bar(bar) am = self.am max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] ma_lvl = [] for i in self.ma_level: ma = self.am.sma(i, True)[-1] ma_lvl.append(ma) l = len(ma_lvl) ma_lvl_tag = [] now = bar.close_price direction = 1 if now > ma_lvl[0] else 0 ma_lvl_tag.append(direction) for i in range(l - 1): val = 1 if ma_lvl[i] > ma_lvl[i + 1] else 0 ma_lvl_tag.append(val) bincount_val = np.bincount(np.array(ma_lvl_tag)) tag_val = 0 if len(bincount_val) == 2: tag_val = bincount_val[1] if len(self.ma_tag) < 200: self.ma_tag.append(tag_val) else: self.ma_tag[:-1] = self.ma_tag[1:] self.ma_tag[-1] = tag_val if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) ma120 = self.am.sma(120) if bar.close_price >= ma120: if self.ma120_track is None: self.ma120_track = 1 elif self.ma120_track > 0: self.ma120_track += 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = 1 elif bar.close_price < ma120: if self.ma120_track is None: self.ma120_track = -1 elif self.ma120_track < 0: self.ma120_track -= 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = -1 if not am.inited or not self.trading: return self.on_strategy(am, bar, self.open_strategy["1"]) # median_val = np.median(calc_nums) self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) self.bg.update_bar(bar) # def init_order_data(self): # self.order_data = np.array([]) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},笔数为{},交易{},pos={}".format( order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value, order.price, order.volume, order.status.value, self.pos)) if order.vt_orderid in self.request_order: self.positions.on_order(order) if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.request_order.remove(order.vt_orderid) # if order.status == Status.ALLTRADED or order.status == Status.PARTTRADED: # if order.direction == Direction.LONG: # if self.positions.volumn == 0: # self.positions.close_price = round(order.price * 0.995) # self.positions.volumn += order.volume # elif order.direction == Direction.SHORT: # self.positions.volumn -= order.volume # elif order.direction == Direction.NET: # self.positions.volumn = order.volume def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class PatternScoreStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [10, 20, 30, 60, 120] ma_tag = [] bd = [] fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 request_order = [] bar_identify = [] score = Score() count = 0 interval = 6 parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(PatternScoreStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager(400) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar) self.am5 = ArrayManager(120) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.order_data = None self.positions = Position(self) self.std_range = IntervalGen(np.std, 5) self.std_range3 = IntervalGen(np.std, 5) self.std_range5 = IntervalGen(np.std, 5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) self.open_strategy = [self.open_kline1] self.offset = 40 self.min = 0 self.max = 0 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return # deg = calc_regress_deg(self.am3.close[-20:]) def calc_score(self): score = 0 score += self.score.base for item in self.pattern_record.values(): score += item["value"] return score def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return diff_time = bar.datetime - self.am.time_array[-1] if diff_time.total_seconds() > 3600 or self.count > self.interval: self.count = 0 self.score.base = calc_regress_deg(self.am.close[-self.interval:], False) * 1000 print("score:", self.score.base, self.min, self.max) else: self.count += 1 # pattern_list = [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS, KlinePattern.CDLCONCEALBABYSWALL, KlinePattern.CDLEVENINGDOJISTAR] pattern = self.am5.pattern(list(KlinePattern)) if len(pattern) > 0: print( list( map(lambda x: (KLINE_PATTERN_CHINESE[x[0]], x[1]), pattern))) self.pattern_record.add_pattern(pattern) deg_full = calc_regress_deg(self.am.close[-40:], False) print("deg:", deg_full) self.pattern_record.update() def open_kline1(self, bar: BarData, calc_data): score = self.calc_score() if score < self.min: self.min = score if score > self.max: self.max = score if abs(calc_data["range_sum"]) < 0.001 or abs(score) < 300: return # if std_val2 < 0.2: if score > 0 and calc_data["range_sum"] > 0: return self.buy(bar.close_price, 1, type=OrderType.MARKET, extra={ "reason": "开多,score={}, rang_sum={}".format( score, calc_data["range_sum"]) }) if score < 0 and calc_data["range_sum"] < 0: return self.short(bar.close_price, 1, type=OrderType.MARKET, extra={ "reason": "开多,score={}, rang_sum={}".format( score, calc_data["range_sum"]) }) def generate_data(self, bar: BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(self.am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = self.am.kdj() deg1 = calc_regress_deg(self.am.close[offset:offset_m], False) deg2 = calc_regress_deg(self.am.close[offset_m:], False) deg3 = calc_regress_deg(self.am.close[-10:], False) deg_full = calc_regress_deg(self.am.close[offset:], False) calc_data = (dict(kdj=[ round(kdj_val["k"][-1], 2), round(kdj_val["d"][-1], 2), round(kdj_val["j"][-1], 2) ], deg40_20=round(deg1, 2), deg20=round(deg2, 2), deg10=round(deg3, 2), deg_f=round(deg_full, 2), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2), mean40=round(mean_val, 2), std_10=round(std_val2, 2), mean30_10=round(mean_val4, 2), mean10=round(mean_val2, 2), vol=self.am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=self.am.range[-1:-5:-1].tolist(), range_sum=np.sum(self.am.range[-5:]), atr=self.am.atr(10), tr=self.am.atr(1, length=2), pattern=list( map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())))) return calc_data def on_strategy(self, bar: BarData): calc_data = self.generate_data(bar) order_id = None if self.pos == 0: for open_strategy in self.open_strategy: if order_id is not None: break order_id = open_strategy(bar, calc_data) else: order_id = self.positions.on_strategy(bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append( (self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) am = self.am self.am.update_bar(bar) max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] ma_lvl = [] for i in self.ma_level: ma = self.am.sma(i, True)[-1] ma_lvl.append(ma) l = len(ma_lvl) ma_lvl_tag = [] now = bar.close_price direction = 1 if now > ma_lvl[0] else 0 ma_lvl_tag.append(direction) for i in range(l - 1): val = 1 if ma_lvl[i] > ma_lvl[i + 1] else 0 ma_lvl_tag.append(val) bincount_val = np.bincount(np.array(ma_lvl_tag)) tag_val = 0 if len(bincount_val) == 2: tag_val = bincount_val[1] if len(self.ma_tag) < 200: self.ma_tag.append(tag_val) else: self.ma_tag[:-1] = self.ma_tag[1:] self.ma_tag[-1] = tag_val if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) if not self.am.inited or not self.trading: return self.on_strategy(bar) # median_val = np.median(calc_nums) self.put_event() # def init_order_data(self): # self.order_data = np.array([]) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},交易{},".format( order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value, order.price, order.status.value)) if order.vt_orderid in self.request_order: self.positions.on_order(order) if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.request_order.remove(order.vt_orderid) # if order.status == Status.ALLTRADED or order.status == Status.PARTTRADED: # if order.direction == Direction.LONG: # if self.positions.volumn == 0: # self.positions.close_price = round(order.price * 0.995) # self.positions.volumn += order.volume # elif order.direction == Direction.SHORT: # self.positions.volumn -= order.volume # elif order.direction == Direction.NET: # self.positions.volumn = order.volume def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class ReverseCatchStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [5, 10, 20, 30, 120] ma_tag = [] bd = [] fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 request_order = [] bar_identify = [] volumn = 0 kdj_record = [] parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] add_pos = False safe_price = None trend_record = MaTrendRecord def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(ReverseCatchStrategy, self).__init__( cta_engine, strategy_name, vt_symbol, setting ) self.bg = BarGenerator(self.on_bar, 1, self.on_1min_bar) self.am = ArrayManager(200) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar) self.am5 = ArrayManager(120) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.order_data = None self.positions = CloseoutPosition(self, {"closeout_offset": 0.003}) self.std_range = IntervalGen(np.std,5) self.std_range3 = IntervalGen(np.std,5) self.std_range5 = IntervalGen(np.std,5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) self.ma_info = [] five_min_open_5 = partial(self.reverse_shape_strategy, setting={"len":20, "atr":10, "atr_valve":0.8, "mid_sign":(7,14)}) self.open_strategy = { "1":[five_min_open_5], } self.offset = 40 self.ma120_track = None self.ma120_track_list = [] def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(5) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return pattern = self.am3.pattern([KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS]) if len(pattern) > 0: print(pattern) self.pattern_record.add_pattern(pattern) # deg = calc_regress_deg(self.am3.close[-20:]) def wave(self, data, window = 0.0002): if len(data) <= 0: return # r = array[::-1] result = { "value":[], "range":[], "pos":[], "length":[]} r = data l = len(data) - 1 now = r[0] # v_list.append(now) # p_list.append(0) pos = 1 vol = 0 u_tag = None d_tag = None end_tag = None start_pos = 0 while pos < l: if math.isnan(now): now = r[pos] pos += 1 continue else: start_pos = pos - 1 break while pos < l: if now < r[pos]: u_tag = pos if d_tag: diff = r[start_pos] - r[d_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 4: end_tag = d_tag elif now > r[pos]: d_tag = pos if u_tag: diff = r[start_pos] - r[u_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 4: end_tag = u_tag if end_tag is not None: result["range"].append(r[end_tag] / r[start_pos] - 1) result["length"].append(end_tag - start_pos) start_pos = end_tag result["value"].append(r[end_tag]) result["pos"].append(end_tag) end_tag = None vol += r[pos] - now now = r[pos] pos += 1 return pd.DataFrame(result) def mode_identify(self, bar: BarData): self.bar_identify = [] hl_scale = round(bar.high_price / bar.low_price - 1, 4) if hl_scale > 0.001: diff = bar.high_price - bar.low_price diff_up = bar.low_price + diff / 2 * 1.20 diff_down = bar.low_price + diff / 2 * 0.80 close = bar.close_price if bar.open_price < diff_up and bar.open_price > diff_down and \ bar.close_price < diff_up and bar.close_price > diff_down: if bar.close_price > bar.open_price: print("绿十字星",bar.datetime, bar.high_price,bar.low_price,diff,diff_up,diff_down, bar.open_price, bar.close_price) else: print("红十字星",bar.datetime, bar.high_price,bar.low_price,diff,diff_up,diff_down, bar.open_price, bar.close_price) def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return # self.on_strategy(self.am5, bar, self.open_strategy["5"]) # pattern_list = [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS, KlinePattern.CDLCONCEALBABYSWALL, KlinePattern.CDLEVENINGDOJISTAR] # pattern = self.am5.pattern(list(KlinePattern)) # if len(pattern) > 0: # print(list(map(lambda x: (KLINE_PATTERN_CHINESE[x[0]],x[1]), pattern))) # self.pattern_record.add_pattern(pattern) # deg_full = calc_regress_deg(self.am.close[-40 :], False) # print("deg:",deg_full) # self.pattern_record.update() def open_v3(self, am:ArrayManager, bar:BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 3: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v1(self, am:ArrayManager, bar:BarData): offset = -40 offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) mean_val = np.mean(calc_nums) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) if std_val < 1 and mean_val < 2 and self.ma_tag[-1] >= (mean_val + 2): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif std_val < 1 and mean_val > 3 and self.ma_tag[-1] <= (mean_val - 2): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v2(self, am:ArrayManager, bar:BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 2.5: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2.5: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def ma_trend_strategy(self, am:ArrayManager, bar:BarData, calc_data, setting={"len":40, "atr":40, "atr_valve":0.09, "mid_sign":(10,30)}): # 60个bar后取消 if self.trend_record.std_val is not None: if len(self.trend_record.close) >= 60: self.trend_record.close = [] self.trend_record.std_val = None else: self.trend_record.close.append(bar.close_price) # 如果有新的bar,则覆盖 ma5_std = self.ma_info[-1]["ma5"] if ma5_std <= 0.16: self.trend_record.close = [] self.trend_record.std_val = ma5_std return if self.trend_record.std_val is not None and \ ma5_std > 0.8: y_fit = reg_util.regress_y_polynomial(self.trend_record.close, zoom=True) deg = calc_regress_deg(y_fit[:10], False) if deg < 0: # if k < 20 and d < 10 and j < 10: # if kdj[2] < 10: if self.pos == 0: calc_data["trade_open"] = "开空,deg={}".format(deg) return self.short(bar.close_price, 1, type=OrderType.MARKET) else: # if k > 80 and d > 90 and j > 90: # if kdj[2] > 90: if self.pos == 0: calc_data["trade_open"] = "开多,deg={}".format(deg) return self.buy(bar.close_price, 1, type=OrderType.MARKET) # v形反转捕获 def reverse_shape_strategy(self, am:ArrayManager, bar:BarData, calc_data, setting={"len":40, "atr":40, "atr_valve":0.09, "mid_sign":(10,30)}): length = setting["len"] offset1 = int(-length) offset2 = int(-(length / 2)) close = am.close deg1 = calc_regress_deg(close[offset1:offset2], False) deg2 = calc_regress_deg(close[offset2:], False) atr = self.am.atr(setting["atr"]) atr_valve = setting["atr_valve"] if atr < atr_valve: return if deg1 > 0 and deg2 > 0 or \ deg1 < 0 and deg2 < 0: return if not (abs(deg1) > 0.15 and abs(deg2) > 0.1 and (abs(deg1) + abs(deg2)) > 0.3) : return close = am.close[-length:] min_val = np.min(close) max_val = np.max(close) mid_val = max_val if deg1 > 0 else min_val mid_pos = np.where(close == mid_val)[0][0] if mid_pos < setting["mid_sign"][0] or mid_pos > setting["mid_sign"][1]: return start_val = np.min(close[:mid_pos]) if deg1 > 0 else np.max(close[:mid_pos]) start_pos = np.where(close == start_val)[0][0] l = mid_pos - start_pos # pos2 = np.where(close == min_val)[0][0] kdj = am.kdj() k = kdj["k"][-1] d = kdj["d"][-1] j = kdj["j"][-1] x_fit = reg_util.regress_y_polynomial(close[:mid_pos], zoom=True) deg1_remake = calc_regress_deg(x_fit[:abs(mid_pos)], False) y_fit = reg_util.regress_y_polynomial(close[mid_pos:], zoom=True) deg2_remake = calc_regress_deg(y_fit[:abs(mid_pos)], False) # print(start_pos, mid_pos, deg1, deg2, deg1_remake, deg2_remake, l, start_val, mid_val) cci = am.cci(20) ma60 = am.sma(60) if deg2 < 0: # if k < 20 and d < 10 and j < 10: # if kdj[2] < 10: if cci < -100 and bar.close_price < ma60: if self.pos == 0: calc_data["trade_open"] = "开空,deg={},cci={}".format(deg2, cci) return self.short(bar.close_price, 1, type=OrderType.MARKET) elif self.pos > 0: order_id_cover = self.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.short(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) else: # if k > 80 and d > 90 and j > 90: # if kdj[2] > 90: if cci > 100 and bar.close_price > ma60: if self.pos == 0: calc_data["trade_open"] = "开多,deg={},cci={}".format(deg2, cci) return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.pos < 0: order_id_cover = self.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.buy(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) # print("找到大v形:", deg1, deg2 ) def ma120_close(self, am:ArrayManager, bar:BarData, calc_data): if self.safe_price is None: return rg = (bar.close_price / self.buy_price) - 1 close_price = None if rg > 0.01 and self.volumn > 0: close_price = am.sma(120) elif rg < -0.01 and self.volumn < 0: close_price = am.sma(120) for lvl in self.ma_lvl[-1:]: # if len(self.order_data) < lvl: close_price = am.sma(lvl) break if close_price is None: lvl = self.ma_level[-1] close_price = am.sma(lvl) if self.volumn < 0: if bar.close_price > close_price: calc_data["trade_close"] = "平仓:到达MA均线价{}".format(close_price) return self.strategy.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET, extra= { "reason":"平仓:到达MA均线价{}".format(close_price)}) elif self.volumn > 0: if bar.close_price < close_price: calc_data["trade_close"] = "平仓:到达MA均线价{}".format(close_price) return self.strategy.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET, extra={"reason": "平仓:到达MA均线价{}".format(close_price)}) def add_position(self, am:ArrayManager, bar:BarData, calc_data, setting={}): if self.safe_price is None: return if not (self.volumn < 0 and bar.close_price < self.safe_price or \ self.volumn > 0 and bar.close_price > self.safe_price): return am = self.am rg = (bar.close_price / self.trade_price) - 1 close_price = None if rg > 0.01 and self.volumn > 0: close_price = am.sma(120) if not self.add_pos: self.add_pos = True return self.strategy.buy(bar.close_price, 50, type=OrderType.MARKET) elif rg < -0.01 and self.volumn < 0: close_price = am.sma(120) if not self.add_pos: self.add_pos = True return self.strategy.short(bar.close_price, 50, type=OrderType.MARKET) def reverse2_strategy(self, am:ArrayManager, bar:BarData, calc_data, setting={"len":40, "atr":40, "atr_valve":0.09, "mid_sign":(10,30)}): length = 30 offset1 = -30 offset2 = int(-10) close = am.close deg1 = calc_regress_deg(close[-30:-8], False) deg2 = calc_regress_deg(close[-8:], False) if deg1 > 0 and deg2 > 0 or \ deg1 < 0 and deg2 < 0: return if not (abs(deg1) > 0.15 and abs(deg2) > 0.15 and (abs(deg1) + abs(deg2)) > 0.35) : return close = am.close[-length:] min_val = np.min(close) max_val = np.max(close) mid_val = max_val if deg1 > 0 else min_val mid_pos = np.where(close == mid_val)[0][0] if mid_pos < setting["mid_sign"][0] or mid_pos > setting["mid_sign"][1]: return start_val = np.min(close[:mid_pos]) if deg1 > 0 else np.max(close[:mid_pos]) start_pos = np.where(close == start_val)[0][0] l = mid_pos - start_pos # pos2 = np.where(close == min_val)[0][0] kdj = am.kdj() k = kdj["k"][-1] d = kdj["d"][-1] j = kdj["j"][-1] x_fit = reg_util.regress_y_polynomial(close[:mid_pos], zoom=True) deg1_remake = calc_regress_deg(x_fit[:abs(mid_pos)], False) y_fit = reg_util.regress_y_polynomial(close[mid_pos:], zoom=True) deg2_remake = calc_regress_deg(y_fit[:abs(mid_pos)], False) # print(start_pos, mid_pos, deg1, deg2, deg1_remake, deg2_remake, l, start_val, mid_val) cci = am.cci(20) ma60 = am.sma(60) if deg2 < 0: # if k < 20 and d < 10 and j < 10: # if kdj[2] < 10: if cci < -100 and bar.close_price < ma60: if self.pos == 0: calc_data["trade_open"] = "开空,deg={},cci={}".format(deg2, cci) return self.short(bar.close_price, 1, type=OrderType.MARKET) elif self.pos > 0: calc_data["trade_close"] = "平多后做空仓,deg={},cci={}".format(deg2, cci) order_id_cover = self.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.short(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) else: # if k > 80 and d > 90 and j > 90: # if kdj[2] > 90: if cci > 100 and bar.close_price > ma60: if self.pos == 0: calc_data["trade_open"] = "开多,deg={},cci={}".format(deg2, cci) return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.pos < 0: calc_data["trade_close"] = "平空后多仓,deg={},cci={}".format(deg2, cci) order_id_cover = self.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.buy(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) def open5(self, am:ArrayManager, bar:BarData, calc_data): ma = self.ma_tag[-1] mean = calc_data["mean30_10"] atr = self.am.atr(10, array=True, length=20) tr = self.am.atr(1, array=True, length=11) # self.ma120_track ma120 = self.am.sma(120) # if std_val2 < 0.2: mean_std = calc_data["mean_std"] if mean_std < 0.8 and tr[-1] > 0.1 and tr[-1] / tr[-10] > 3 and tr[-1] / atr[-1] >= 1.7 and tr[-10] / atr[-10] < 1: if np.sum(self.am.range[-10:]) > 0 and self.ma120_track > 0: return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.ma120_track < 0: return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_kline1(self, am:ArrayManager, bar:BarData, calc_data): if KlinePattern.CDLEVENINGSTAR not in self.pattern_record: return # if std_val2 < 0.2: deg = calc_regress_deg(self.am.close[-5:], False) print("kline_strategy",deg) if deg < -0.1: return self.short(bar.close_price, 1, type=OrderType.MARKET) def generate_data(self, am:ArrayManager, bar:BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = am.kdj() has_kdj_recore = False k = kdj_val["k"] d = kdj_val["d"] j = kdj_val["j"] if (k[-1] > 75 and d[-1] > 75 and j[-1] > 75) or \ (k[-1] < 25 and d[-1] < 25 and j[-1] < 75): if (j[-2] < k[-2] or j[-2] < d[-2]) and (j[-1] > k[-1] and j[-1] > d[-1]) \ or \ (j[-2] > k[-2] or j[-2] > d[-2]) and (j[-1] < k[-1] and j[-1] < d[-1]): has_kdj_recore = True t = local_to_eastern(bar.datetime.timestamp()) self.kdj_record.append((t.strftime("%H:%M:%S"), round(k[-1], 3), round(d[-1], 3), round(j[-1], 3))) deg1 = calc_regress_deg(am.close[offset : offset_m], False) deg2 = calc_regress_deg(am.close[offset_m :], False) deg3 = calc_regress_deg(am.close[-10 :], False) deg_full = calc_regress_deg(am.close[offset :], False) wave = self.wave(am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd=am.macd(20,40, 16) calc_data = (dict( ma_info=self.ma_info[-1:], kdj=[round(kdj_val["k"][-1],2),round(kdj_val["d"][-1],2),round(kdj_val["j"][-1],2)], cci_20=am.cci(20),rsi=am.rsi(20),adx=am.adx(20),boll=am.boll(20, 3.4), macd=[round(macd[0],2),round(macd[1],2),round(macd[2],2)], deg40_20=round(deg1,2), deg20_0=round(deg2,2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False),2), deg30_10=round(calc_regress_deg(am.close[-30:-10], False),2),deg10_0=round(deg3,2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False),2), deg15_0=round(calc_regress_deg(am.close[-15:], False),2),deg_f=round(deg_full,2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3),atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2),mean40=round(mean_val,2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2,2), mean30_10=round(mean_val4,2), mean10=round(mean_val2,2), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list(map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(am.atr(20, array=True,length=240)[-200:]), kdj_record=self.kdj_record[-10:], )) if self.ma_info[-1]["ma5"] <= 0.16: calc_data["kdj_key"] = True return calc_data def generate_3mindata(self, am:ArrayManager, bar:BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = am.kdj() deg1 = calc_regress_deg(am.close[offset : offset_m], False) deg2 = calc_regress_deg(am.close[offset_m :], False) deg3 = calc_regress_deg(am.close[-10 :], False) deg_full = calc_regress_deg(am.close[offset :], False) wave = self.wave(am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd=am.macd(20,40, 16) calc_data = (dict( kdj=[round(kdj_val["k"][-1],2),round(kdj_val["d"][-1],2),round(kdj_val["j"][-1],2)], cci_20=am.cci(20),rsi=am.rsi(20),adx=am.adx(20),boll=am.boll(20, 3.4), macd=[round(macd[0],2),round(macd[1],2),round(macd[2],2)], deg40_20=round(deg1,2), deg20_0=round(deg2,2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False),2), deg10_0=round(deg3,2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False),2), deg15_0=round(calc_regress_deg(am.close[-15:], False),2),deg_f=round(deg_full,2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3),atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2),mean40=round(mean_val,2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2,2), mean30_10=round(mean_val4,2), mean10=round(mean_val2,2), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list(map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma_info=list(map(lambda x:x["std"], self.ma_info[-1:])), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(am.atr(20, array=True,length=240)[-200:]) )) return calc_data def on_strategy(self, am:ArrayManager, bar: BarData, strategy_list, close_strategy_list, calc_data=None): order_id = None for open_strategy in strategy_list: if order_id is not None: break order_id = open_strategy(am, bar, calc_data) if order_id is None and self.pos != 0: for strategy in close_strategy_list: if order_id is not None: break order_id = strategy(am, bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append(( self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20_0"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def ma_info_update(self, am:ArrayManager): ma_info = {} ma_data = [] for i in self.ma_level: ma = am.sma(i) ma_info[i] = round(ma,2) ma_data.append(ma) data = [] diff = ma_data[-1] for v in ma_data: data.append(round(v / diff, 6)) ma_info["ma5"] = round(np.var(data)*1000000, 8) data = [] diff = ma_data[-3] for v in ma_data[:-2]: data.append(round(v / diff, 6)) ma_info["ma3"] = round(np.var(data)*1000000, 8) if len(self.ma_info) < 500: self.ma_info.append(ma_info) else: self.ma_info[:-1] = self.ma_info[1:] self.ma_info[-1] = ma_info def on_1min_bar(self, bar: BarData): self.am.update_bar(bar) am = self.am max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] ma_lvl = [] for i in self.ma_level: ma = self.am.sma(i, True)[-1] ma_lvl.append(ma) l = len(ma_lvl) ma_lvl_tag = [] now = bar.close_price direction = 1 if now > ma_lvl[0] else 0 ma_lvl_tag.append(direction) for i in range(l-1): val = 1 if ma_lvl[i] > ma_lvl[i+1] else 0 ma_lvl_tag.append(val) bincount_val = np.bincount(np.array(ma_lvl_tag)) tag_val = 0 if len(bincount_val) == 2: tag_val = bincount_val[1] if len(self.ma_tag) < 200: self.ma_tag.append(tag_val) else: self.ma_tag[:-1] = self.ma_tag[1:] self.ma_tag[-1] = tag_val if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) ma120 = self.am.sma(120) if bar.close_price >= ma120: if self.ma120_track is None: self.ma120_track = 1 elif self.ma120_track > 0: self.ma120_track += 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = 1 elif bar.close_price < ma120: if self.ma120_track is None: self.ma120_track = -1 elif self.ma120_track < 0: self.ma120_track -= 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = -1 if not am.inited or not self.trading: return self.ma_info_update(am) calc_data = self.generate_data(am, bar) five_min_open_5 = partial(self.reverse_shape_strategy, setting={"len":20, "atr":10, "atr_valve":0.8, "mid_sign":(7,14)}) open_strategy = [self.reverse_shape_strategy, self.add_position] close_strategy = [self.positions.on_bar, self.ma120_close] self.on_strategy(am, bar, open_strategy, close_strategy, calc_data) # median_val = np.median(calc_nums) self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) self.bg.update_bar(bar) # def init_order_data(self): # self.order_data = np.array([]) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},笔数为{},交易{},pos={}".format(order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value,order.price, order.volume, order.status.value, self.pos)) if order.vt_orderid in self.request_order: if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.request_order.remove(order.vt_orderid) def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.vt_orderid in self.request_order: self.positions.on_trade(trade) if self.volumn == 0: self.add_pos = False if trade.direction == Direction.LONG: self.safe_price = trade.price * 1.003 self.volumn += trade.volume elif trade.direction == Direction.SHORT: self.safe_price = trade.price * 0.997 self.volumn -= trade.volume self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass