This commit is contained in:
ddrwode
2026-01-30 01:01:07 +08:00
parent edb07c01d3
commit dbf76fe385

View File

@@ -14,7 +14,7 @@ BitMart 三分之一回归策略交易(双向触发版)
3. 执行逻辑:
- 做多时遇到做空信号 -> 平多并反手开空
- 做空时遇到做多信号 -> 平空并反手开多
- 同一根K线内只交易一次,防止频繁反手
- 同一根K线内:若先开空后价格回调到「做多触发价」(开仓价+上一根实体/3则平空开多反之先开多后跌到做空触发价则平多开空。同一根K线内仅允许一次反手防止频繁来回开仓。
示例1阳线
前一根K线开盘3000收盘3100阳线实体=100
@@ -554,21 +554,27 @@ class BitmartOneThirdStrategy:
if direction:
curr_kline_id = curr_kline['id']
# 检查是否在同一K线内已经交易过防止频繁反手)
if self.last_trade_kline_id == curr_kline_id:
logger.debug(f"同一K线内已交易跳过本次{direction}信号")
# 更新触发记录,避免重复日志
self.last_trigger_kline_id = curr_kline_id
self.last_trigger_direction = direction
time.sleep(self.check_interval)
continue
# 获取持仓状态
# 获取持仓状态先获取用于判断是否允许同一K线内反手)
if not self.get_position_status():
logger.warning("获取仓位信息失败")
time.sleep(self.check_interval)
continue
# 检查是否在同一K线内已经交易过防止频繁反手
# 例外同一根K线内仅允许一次反手
# - 先开空 -> 价格回调到做多触发价 -> 允许平空开多
# - 先开多 -> 价格跌到做空触发价 -> 允许平多开空
if self.last_trade_kline_id == curr_kline_id:
allow_reverse = (self.start == -1 and direction == "long") or (self.start == 1 and direction == "short")
if not allow_reverse:
logger.debug(f"同一K线内已交易且非反手场景跳过本次{direction}信号")
self.last_trigger_kline_id = curr_kline_id
self.last_trigger_direction = direction
time.sleep(self.check_interval)
continue
action_desc = "平空开多" if (self.start == -1 and direction == "long") else "平多开空"
logger.info(f"同一K线内回调/反弹触发反手:当前持仓{'' if self.start == -1 else ''},信号{direction} -> {action_desc}")
prev_time = datetime.datetime.fromtimestamp(valid_prev['id']).strftime('%H:%M')
prev_type = "阳线" if self.is_bullish(valid_prev) else "阴线"
prev_body = self.get_body_size(valid_prev)
@@ -581,6 +587,18 @@ class BitmartOneThirdStrategy:
time.sleep(self.check_interval)
continue
# 开仓原因(用于日志:多久、为什么开仓)
is_same_kline_reverse = (self.last_trade_kline_id == curr_kline_id)
if is_same_kline_reverse and direction == "long":
open_reason = f"同一根K线内价格回调到做多触发价 {trigger_price:.2f}(前一根[{prev_time}]{prev_type} 实体={prev_body:.2f}),平空反手开多"
elif is_same_kline_reverse and direction == "short":
open_reason = f"同一根K线内价格跌到做空触发价 {trigger_price:.2f}(前一根[{prev_time}]{prev_type} 实体={prev_body:.2f}),平多反手开空"
elif direction == "long":
open_reason = f"当前K线最高价触达做多触发价 {trigger_price:.2f}(前一根[{prev_time}]{prev_type} 实体={prev_body:.2f} 收盘={valid_prev['close']:.2f}"
else:
open_reason = f"当前K线最低价触达做空触发价 {trigger_price:.2f}(前一根[{prev_time}]{prev_type} 实体={prev_body:.2f} 收盘={valid_prev['close']:.2f}"
open_time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
logger.info(f"{'=' * 50}")
logger.info(f"🚨 检测到{direction}信号!触发价格: {trigger_price:.2f}")
logger.info(
@@ -588,6 +606,8 @@ class BitmartOneThirdStrategy:
logger.info(
f" 当前K线: H={curr_kline['high']:.2f} L={curr_kline['low']:.2f} C={curr_kline['close']:.2f}")
logger.info(f" 当前持仓: {self.start} (1=多, -1=空, 0=无)")
logger.info(f" 开仓时间: {open_time_str}")
logger.info(f" 开仓原因: {open_reason}")
# ========== 执行交易逻辑 ==========
balance = self.get_available_balance()
@@ -598,25 +618,25 @@ class BitmartOneThirdStrategy:
executed = False
if direction == "long":
if self.start == -1: # 当前空仓,平空开多
logger.info("📈 平空仓,反手开多")
logger.info(f"📈 平空仓,反手开多 | {open_time_str} | {open_reason}")
self.平仓()
time.sleep(1)
self.开单(marketPriceLongOrder=1, size=trade_size)
executed = True
elif self.start == 0: # 当前无仓,直接开多
logger.info("📈 无仓位,开多")
logger.info(f"📈 无仓位,开多 | {open_time_str} | {open_reason}")
self.开单(marketPriceLongOrder=1, size=trade_size)
executed = True
elif direction == "short":
if self.start == 1: # 当前多仓,平多开空
logger.info("📉 平多仓,反手开空")
logger.info(f"📉 平多仓,反手开空 | {open_time_str} | {open_reason}")
self.平仓()
time.sleep(1)
self.开单(marketPriceLongOrder=-1, size=trade_size)
executed = True
elif self.start == 0: # 当前无仓,直接开空
logger.info("📉 无仓位,开空")
logger.info(f"📉 无仓位,开空 | {open_time_str} | {open_reason}")
self.开单(marketPriceLongOrder=-1, size=trade_size)
executed = True
@@ -627,6 +647,8 @@ class BitmartOneThirdStrategy:
if executed:
# 记录交易K线防止同一K线内频繁反手
self.last_trade_kline_id = curr_kline_id
# 发送开仓时间与原因到钉钉
self.ding(msg=f"开仓时间: {open_time_str}\n开仓原因: {open_reason}")
# 交易后立即发送持仓信息
self.get_position_status()
self._send_position_message(curr_kline)