diff --git a/bitmart/交易.py b/bitmart/交易.py index d229948..ee12626 100644 --- a/bitmart/交易.py +++ b/bitmart/交易.py @@ -67,7 +67,7 @@ class BitmartFuturesTransaction: self.current_open = None # 当前K线开盘价 # 策略优化参数 - self.min_prev_entity_pct = 0.1 # 上一根K线实体涨幅(%),仅当实体涨幅 > 此值才用作“上一根” + self.min_prev_entity_pct = 0.1 # 上一根K线实体涨幅(%),仅当实体涨幅 >= 此值才用作“上一根” # 自动止盈:基于当前K线振幅四等分(多仓用 open~high,空仓用 open~low) self.take_profit_close_quartile = 3 # 达到极值后,回到 3/4 位置平仓 @@ -108,7 +108,7 @@ class BitmartFuturesTransaction: }) formatted.sort(key=lambda x: x['id']) - # 返回最近多根K线列表,供主循环按「实体涨幅>0.1%」向前选取上一根 + # 返回最近多根K线列表,供主循环按「实体涨幅>=min_prev_entity_pct」向前选取上一根 if len(formatted) >= 2: return formatted return None @@ -411,85 +411,46 @@ class BitmartFuturesTransaction: 检查交易信号 返回: ('long', trigger_price) / ('short', trigger_price) / None """ - # 计算上一根K线实体(主循环已保证所选 prev 实体涨幅 > 0.1%) + # 计算上一根K线实体(主循环已保证所选 prev 实体涨幅 >= min_prev_entity_pct) prev_entity = self.calculate_entity(prev_kline) - # 获取上一根K线的实体上下边 - prev_entity_edge = self.get_entity_edge(prev_kline) - prev_entity_upper = prev_entity_edge['upper'] # 实体上边 - prev_entity_lower = prev_entity_edge['lower'] # 实体下边 + # 基础规则:始终以当前K线开盘价为基准 + # 开仓与反手阈值统一为「当前开盘价 ± 上一根实体/3」 + base_open = current_kline['open'] + long_trigger = base_open + prev_entity / 3 + short_trigger = base_open - prev_entity / 3 + long_breakout = long_trigger + short_breakout = short_trigger - # 优化:以下两种情况以当前这根的开盘价作为计算基准 - # 1) 上一根阳线 且 当前开盘价 > 上一根收盘价(跳空高开) - # 2) 上一根阴线 且 当前开盘价 < 上一根收盘价(跳空低开) - prev_is_bullish_for_calc = prev_kline['close'] > prev_kline['open'] - prev_is_bearish_for_calc = prev_kline['close'] < prev_kline['open'] - current_open_above_prev_close = current_kline['open'] > prev_kline['close'] - current_open_below_prev_close = current_kline['open'] < prev_kline['close'] - use_current_open_as_base = (prev_is_bullish_for_calc and current_open_above_prev_close) or (prev_is_bearish_for_calc and current_open_below_prev_close) - - if use_current_open_as_base: - # 以当前K线开盘价为基准计算(跳空时用当前开盘价参与计算) - calc_lower = current_kline['open'] - calc_upper = current_kline['open'] # 同一基准,上下三分之一对称 - long_trigger = calc_lower + prev_entity / 3 - short_trigger = calc_upper - prev_entity / 3 - long_breakout = calc_upper + prev_entity / 3 - short_breakout = calc_lower - prev_entity / 3 - else: - # 原有计算方式 - long_trigger = prev_entity_lower + prev_entity / 3 # 做多触发价 = 实体下边 + 实体/3(下三分之一处) - short_trigger = prev_entity_upper - prev_entity / 3 # 做空触发价 = 实体上边 - 实体/3(上三分之一处) - long_breakout = prev_entity_upper + prev_entity / 3 # 做多突破价 = 实体上边 + 实体/3 - short_breakout = prev_entity_lower - prev_entity / 3 # 做空突破价 = 实体下边 - 实体/3 - - # 上一根阴线 + 当前阳线:做多形态,不按上一根K线上三分之一做空 - prev_is_bearish = prev_kline['close'] < prev_kline['open'] - current_is_bullish = current_kline['close'] > current_kline['open'] - skip_short_by_upper_third = prev_is_bearish and current_is_bullish - # 上一根阳线 + 当前阴线:做空形态,不按上一根K线下三分之一做多 - prev_is_bullish = prev_kline['close'] > prev_kline['open'] - current_is_bearish = current_kline['close'] < current_kline['open'] - skip_long_by_lower_third = prev_is_bullish and current_is_bearish - - if use_current_open_as_base: - if prev_is_bullish_for_calc and current_open_above_prev_close: - logger.info(f"上一根阳线且当前开盘价({current_kline['open']:.2f})>上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") - else: - logger.info(f"上一根阴线且当前开盘价({current_kline['open']:.2f})<上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") logger.info(f"当前价格: {current_price:.2f}, 上一根实体: {prev_entity:.4f}") - logger.info(f"上一根实体上边: {prev_entity_upper:.2f}, 下边: {prev_entity_lower:.2f}") - logger.info(f"做多触发价(下1/3): {long_trigger:.2f}, 做空触发价(上1/3): {short_trigger:.2f}") - logger.info(f"突破做多价(上1/3外): {long_breakout:.2f}, 突破做空价(下1/3外): {short_breakout:.2f}") - if skip_short_by_upper_third: - logger.info("上一根阴线+当前阳线(做多形态),不按上三分之一做空") - if skip_long_by_lower_third: - logger.info("上一根阳线+当前阴线(做空形态),不按下三分之一做多") + logger.info(f"当前K线开盘价: {base_open:.2f}") + logger.info(f"做多触发价(开盘+实体1/3): {long_trigger:.2f}, 做空触发价(开盘-实体1/3): {short_trigger:.2f}") + logger.info(f"开仓做多价: {long_breakout:.2f}, 开仓做空价: {short_breakout:.2f}") # 无持仓时检查开仓信号 if self.start == 0: - if current_price >= long_breakout and not skip_long_by_lower_third: + if current_price >= long_breakout: logger.info( - f"触发做多信号!价格 {current_price:.2f} >= 突破价(上1/3外) {long_breakout:.2f}" + f"触发做多信号!价格 {current_price:.2f} >= 开仓做多价(开盘+实体1/3) {long_breakout:.2f}" ) return ('long', long_breakout) - elif current_price <= short_breakout and not skip_short_by_upper_third: + elif current_price <= short_breakout: logger.info( - f"触发做空信号!价格 {current_price:.2f} <= 突破价(下1/3外) {short_breakout:.2f}" + f"触发做空信号!价格 {current_price:.2f} <= 开仓做空价(开盘-实体1/3) {short_breakout:.2f}" ) return ('short', short_breakout) # 持仓时检查反手信号 elif self.start == 1: # 持多仓 - # 反手条件: 价格跌到上一根K线的上三分之一处(做空触发价);上一根阴线+当前阳线做多时跳过 - if current_price <= short_trigger and not skip_short_by_upper_third: - logger.info(f"持多反手做空!价格 {current_price:.2f} <= 触发价(上1/3) {short_trigger:.2f}") + # 反手条件: 价格跌到 当前开盘价-上一根实体/3(做空触发价) + if current_price <= short_trigger: + logger.info(f"持多反手做空!价格 {current_price:.2f} <= 触发价(开盘-实体1/3) {short_trigger:.2f}") return ('reverse_short', short_trigger) elif self.start == -1: # 持空仓 - # 反手条件: 价格涨到上一根K线的下三分之一处(做多触发价);上一根阳线+当前阴线做空时跳过 - if current_price >= long_trigger and not skip_long_by_lower_third: - logger.info(f"持空反手做多!价格 {current_price:.2f} >= 触发价(下1/3) {long_trigger:.2f}") + # 反手条件: 价格涨到 当前开盘价+上一根实体/3(做多触发价) + if current_price >= long_trigger: + logger.info(f"持空反手做多!价格 {current_price:.2f} >= 触发价(开盘+实体1/3) {long_trigger:.2f}") return ('reverse_long', long_trigger) return None @@ -703,7 +664,7 @@ class BitmartFuturesTransaction: page_start = False try: - # 1. 获取K线数据,当前K线=最后一根;上一根=从后往前第一根实体涨幅>0.1%的K线 + # 1. 获取K线数据,当前K线=最后一根;上一根=从后往前第一根实体涨幅>=min_prev_entity_pct 的K线 formatted = self.get_klines() if not formatted or len(formatted) < 2: logger.warning("获取K线失败,等待重试...") @@ -716,11 +677,11 @@ class BitmartFuturesTransaction: k = formatted[i] entity = abs(k['close'] - k['open']) entity_pct = entity / k['open'] * 100 if k['open'] else 0 - if entity_pct > self.min_prev_entity_pct: + if entity_pct >= self.min_prev_entity_pct: prev_kline = k break if prev_kline is None: - logger.info(f"没有实体涨幅>{self.min_prev_entity_pct:.3f}%的上一根K线,跳过信号检测") + logger.info(f"没有实体涨幅>={self.min_prev_entity_pct:.3f}%的上一根K线,跳过信号检测") time.sleep(0.1) continue @@ -892,13 +853,13 @@ class BitmartFuturesTransaction: sig_type, trigger_price = signal op_name = {"long": "开多", "short": "开空", "reverse_long": "反手做多", "reverse_short": "反手做空"}.get(sig_type, sig_type) if sig_type == "long": - open_reason = f"三分之一策略:当前价{current_price:.2f}>=突破做多价{trigger_price:.2f}(实体上边+1/3)" + open_reason = f"三分之一策略:当前价{current_price:.2f}>=开仓做多价{trigger_price:.2f}(当前开盘+上一根实体1/3)" elif sig_type == "short": - open_reason = f"三分之一策略:当前价{current_price:.2f}<=突破做空价{trigger_price:.2f}(实体下边-1/3)" + open_reason = f"三分之一策略:当前价{current_price:.2f}<=开仓做空价{trigger_price:.2f}(当前开盘-上一根实体1/3)" elif sig_type == "reverse_long": - open_reason = f"持空反手做多:当前价{current_price:.2f}>=做多触发价{trigger_price:.2f}(下1/3)" + open_reason = f"持空反手做多:当前价{current_price:.2f}>=做多触发价{trigger_price:.2f}(当前开盘+上一根实体1/3)" else: - open_reason = f"持多反手做空:当前价{current_price:.2f}<=做空触发价{trigger_price:.2f}(上1/3)" + open_reason = f"持多反手做空:当前价{current_price:.2f}<=做空触发价{trigger_price:.2f}(当前开盘-上一根实体1/3)" self._write_open_log(op_name, open_reason, current_kline, prev_kline) logger.success(f"交易执行完成: {signal[0]}, 当前持仓状态: {self.start}") page_start = True