日志展示优化

This commit is contained in:
ddrwode
2026-02-06 17:59:16 +08:00
parent ae4d48603f
commit 6dd9b4031e

View File

@@ -74,8 +74,10 @@ def make_metrics_panel(state: dict) -> Panel:
t.add_row("突破做多", f"{state.get('long_breakout', 0):.2f}")
t.add_row("突破做空", f"{state.get('short_breakout', 0):.2f}")
ema10 = state.get("ema10")
ema20 = state.get("ema20")
atr14 = state.get("atr14")
t.add_row("EMA10", f"{ema10:.2f}" if ema10 is not None else "-")
t.add_row("EMA20", f"{ema20:.2f}" if ema20 is not None else "-")
t.add_row("ATR14", f"{atr14:.2f}" if atr14 is not None else "-")
pnl = state.get("unrealized_pnl")
t.add_row("未实现盈亏", f"{pnl:.2f}$" if pnl is not None else "-")
@@ -132,13 +134,11 @@ class BitmartFuturesTransaction:
self.leverage = "100" # 高杠杆(全仓模式下可开更大仓位)
self.open_type = "cross" # 全仓模式
self.risk_percent = 0 # 未使用;若启用则可为每次开仓占可用余额的百分比
self.trailing_activation_usd = 6 # 盈利达到此金额后启动移动止损(调高避免波动不大就触发
self.trailing_distance_usd = 3 # 从最高盈利回撤此金额则平仓(调高避免小幅回撤就平)
self.max_unrealized_pnl_seen = None # 持仓期间见过的最大盈利(用于移动止损)
# EMA(10) + ATR(14) 平仓(多/空一致):多单跌破 EMA10 或从最高回撤≥ATR 平;空单涨破 EMA10 或从最低反弹≥ATR 平
# 退出:仅 EMA10快退出+ 1.1×ATR(14) 追踪。EMA20 不做先平,只做趋势/方向过滤(见下
self.use_ema_atr_exit = True # 是否启用 EMA/ATR 平仓规则(多单+空单)
self.atr_multiplier = 1.8 # 追踪止盈:从极值回撤/反弹 ≥ 此倍数×ATR(14) 则平仓(调高避免波动不大就平)
self.min_hold_seconds = 90 # 开仓/反手后至少持仓此时长才允许技术性止盈EMA/ATR/移动止损
self.atr_multiplier = 1.1 # 追踪止盈:从当前K线极值回撤/反弹 ≥ 此倍数×ATR(14) 则平仓
self.use_ema20_filter = True # 是否用 EMA20 做开仓/反手方向过滤 + 持仓强制减仓(趋势过滤
self.min_hold_seconds = 90 # 开仓/反手后至少持仓此时长才允许技术性止盈EMA10/EMA20/ATR
self._candle_high_seen = None # 当前K线内见过的最高价多头用
self._candle_low_seen = None # 当前K线内见过的最低价空头用
self._candle_id_for_high_low = None # 记录高低对应的K线 id换线则重置
@@ -527,14 +527,14 @@ class BitmartFuturesTransaction:
self._display_triggers = {"long_trigger": long_trigger, "short_trigger": short_trigger, "long_breakout": long_breakout, "short_breakout": short_breakout}
# 无持仓时检查开仓信号
# 无持仓时检查开仓信号(做多看突破价,做空看做空触发价,与反手阈值一致便于回落即进空)
if self.start == 0:
if current_price >= long_breakout and not skip_long_by_lower_third:
logger.info(LOG_SIGNAL + f"触发做多 | 价 {current_price:.2f} >= 突破价 {long_breakout:.2f}")
return ('long', long_breakout)
elif current_price <= short_breakout and not skip_short_by_upper_third:
logger.info(LOG_SIGNAL + f"触发做空 | 价 {current_price:.2f} <= 突破{short_breakout:.2f}")
return ('short', short_breakout)
elif current_price <= short_trigger and not skip_short_by_upper_third:
logger.info(LOG_SIGNAL + f"触发做空 | 价 {current_price:.2f} <= 做空触发{short_trigger:.2f}")
return ('short', short_trigger)
# 持仓时检查反手信号
elif self.start == 1: # 持多仓
@@ -630,7 +630,6 @@ class BitmartFuturesTransaction:
# 验证开仓是否成功
if self.verify_position_direction(1):
self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录
self.last_open_time = time.time()
self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None)
logger.success(LOG_POSITION + "开多成功")
@@ -655,7 +654,6 @@ class BitmartFuturesTransaction:
# 验证开仓是否成功
if self.verify_position_direction(-1):
self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录
self.last_open_time = time.time()
self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None)
logger.success(LOG_POSITION + "开空成功")
@@ -682,7 +680,6 @@ class BitmartFuturesTransaction:
time.sleep(3)
if self.verify_position_direction(1):
self.max_unrealized_pnl_seen = None
self.last_open_time = time.time() # 反手后的新仓位也受最短持仓时间保护
logger.success(LOG_POSITION + "反手做多成功")
time.sleep(20)
@@ -708,7 +705,6 @@ class BitmartFuturesTransaction:
time.sleep(3)
if self.verify_position_direction(-1):
self.max_unrealized_pnl_seen = None
self.last_open_time = time.time() # 反手后的新仓位也受最短持仓时间保护
logger.success(LOG_POSITION + "反手做空成功")
time.sleep(20)
@@ -828,15 +824,16 @@ class BitmartFuturesTransaction:
kline_series = self.get_klines_series(35)
ema10, ema20, atr14 = self.get_ema_atr_for_exit(kline_series)
self._display_state["ema10"] = ema10
self._display_state["ema20"] = ema20
self._display_state["atr14"] = atr14
if getattr(self, "_display_triggers", None):
self._display_state.update(self._display_triggers)
except Exception:
pass
# 3.5 移动止损 + EMA/ATR 平仓
# 3.5 平仓EMA10 快退出、EMA20 趋势过滤强制减仓、1.1×ATR 追踪
if self.start != 0:
# 换线重置跟踪有持仓时更新本K线内最高/最低价(供 ATR 追踪用)
# 换线重置跟踪有持仓时更新本K线内最高/最低价
if self._candle_id_for_high_low != current_kline_time:
self._candle_high_seen = None
self._candle_low_seen = None
@@ -850,64 +847,63 @@ class BitmartFuturesTransaction:
hold_sec = (time.time() - self.last_open_time) if self.last_open_time else 999999
allow_technical_exit = hold_sec >= self.min_hold_seconds
# 多单EMA(10) + ATR(14) 平仓(需满最短持仓时间
# 多单平仓EMA10 快退出 / EMA20 趋势过滤强制减仓 / 1.1×ATR 追踪组合1能赚点是点
if allow_technical_exit and self.start == 1 and self.use_ema_atr_exit:
kline_series = self.get_klines_series(35)
ema10, ema20, atr14 = self.get_ema_atr_for_exit(kline_series)
# 1) 价格跌破 EMA10 → 先平(能赚点是点)
if ema10 is not None and current_price < ema10:
logger.info(LOG_POSITION + f"多单 EMA10 平仓 | 价 {current_price:.2f} 跌破 EMA10 {ema10:.2f}")
self.平仓()
self._last_exit_kline_id = current_kline_time
self.max_unrealized_pnl_seen = None
self._candle_high_seen = None
time.sleep(3)
continue
# 2) EMA20 趋势过滤:价格跌破 EMA20 → 强制减仓(方向过滤,不做先平触发)
if self.use_ema20_filter and ema20 is not None and current_price < ema20:
logger.info(LOG_POSITION + f"多单 EMA20 强制减仓 | 价 {current_price:.2f} 跌破 EMA20 {ema20:.2f}")
self.平仓()
self._last_exit_kline_id = current_kline_time
self._candle_high_seen = None
time.sleep(3)
continue
# 3) 从最高价回撤 ≥ 1.1×ATR(14) → 平仓
if atr14 is not None and self._candle_high_seen and (self._candle_high_seen - current_price) >= self.atr_multiplier * atr14:
logger.info(LOG_POSITION + f"多单 ATR 追踪止盈 | 最高 {self._candle_high_seen:.2f} 当前 {current_price:.2f} 回撤≥{self.atr_multiplier}×ATR={atr14:.2f}")
self.平仓()
self._last_exit_kline_id = current_kline_time
self.max_unrealized_pnl_seen = None
self._candle_high_seen = None
time.sleep(3)
continue
# 空单EMA(10) + ATR(14) 平仓(需满最短持仓时间)
# 空单平仓EMA10 快退出 / EMA20 趋势过滤强制减仓 / 1.1×ATR 追踪
if allow_technical_exit and self.start == -1 and self.use_ema_atr_exit:
kline_series = self.get_klines_series(35)
ema10, ema20, atr14 = self.get_ema_atr_for_exit(kline_series)
# 1) 价格涨破 EMA10 → 先平
if ema10 is not None and current_price > ema10:
logger.info(LOG_POSITION + f"空单 EMA10 平仓 | 价 {current_price:.2f} 涨破 EMA10 {ema10:.2f}")
self.平仓()
self._last_exit_kline_id = current_kline_time
self.max_unrealized_pnl_seen = None
self._candle_low_seen = None
time.sleep(3)
continue
# 2) EMA20 趋势过滤:价格涨破 EMA20 → 强制减仓
if self.use_ema20_filter and ema20 is not None and current_price > ema20:
logger.info(LOG_POSITION + f"空单 EMA20 强制减仓 | 价 {current_price:.2f} 涨破 EMA20 {ema20:.2f}")
self.平仓()
self._last_exit_kline_id = current_kline_time
self._candle_low_seen = None
time.sleep(3)
continue
# 3) 从最低价反弹 ≥ 1.1×ATR(14) → 平仓
if atr14 is not None and self._candle_low_seen and (current_price - self._candle_low_seen) >= self.atr_multiplier * atr14:
logger.info(LOG_POSITION + f"空单 ATR 追踪止盈 | 最低 {self._candle_low_seen:.2f} 当前 {current_price:.2f} 反弹≥{self.atr_multiplier}×ATR={atr14:.2f}")
self.平仓()
self._last_exit_kline_id = current_kline_time
self.max_unrealized_pnl_seen = None
self._candle_low_seen = None
time.sleep(3)
continue
pnl_usd = self.get_unrealized_pnl_usd()
if pnl_usd is not None:
# 更新持仓期间最大盈利(用于移动止损)
if self.max_unrealized_pnl_seen is None:
self.max_unrealized_pnl_seen = pnl_usd
else:
self.max_unrealized_pnl_seen = max(self.max_unrealized_pnl_seen, pnl_usd)
# 移动止损:盈利曾达到 activation 后,从最高盈利回撤 trailing_distance 则平仓(需满最短持仓时间)
if allow_technical_exit and self.max_unrealized_pnl_seen >= self.trailing_activation_usd:
if pnl_usd < self.max_unrealized_pnl_seen - self.trailing_distance_usd:
logger.info(LOG_POSITION + f"移动止损平仓 | 盈利 {pnl_usd:.2f} 从最高 {self.max_unrealized_pnl_seen:.2f} 回撤≥{self.trailing_distance_usd}$")
self.平仓()
self._last_exit_kline_id = current_kline_time
self.max_unrealized_pnl_seen = None
time.sleep(3)
continue
# 4. 检查信号
signal = self.check_signal(current_price, prev_kline, current_kline)
@@ -926,6 +922,18 @@ class BitmartFuturesTransaction:
else:
self._current_kline_id_for_open = current_kline_time # 供 execute_trade 成功后记录
# 5.6 EMA20 方向过滤:价在 EMA20 上方才开多,下方才开空(趋势过滤,暂停逆势开仓)
if signal and self.use_ema20_filter:
kline_series = self.get_klines_series(35)
_, ema20, _ = self.get_ema_atr_for_exit(kline_series)
if ema20 is not None:
if signal[0] in ('long', 'reverse_long') and current_price <= ema20:
self._log_throttled("ema20_no_long", LOG_SYSTEM + f"EMA20 方向过滤:价 {current_price:.2f} 未在 EMA20 {ema20:.2f} 上方,暂停开多", interval=2.0)
signal = None
elif signal[0] in ('short', 'reverse_short') and current_price >= ema20:
self._log_throttled("ema20_no_short", LOG_SYSTEM + f"EMA20 方向过滤:价 {current_price:.2f} 未在 EMA20 {ema20:.2f} 下方,暂停开空", interval=2.0)
signal = None
# 6. 有信号则执行交易
if signal:
trade_success = self.execute_trade(signal)