日志展示优化
This commit is contained in:
@@ -123,38 +123,26 @@ class BitmartFuturesTransaction:
|
||||
|
||||
self.last_kline_time = None # 上一次处理的K线时间戳,用于判断是否是新K线
|
||||
|
||||
# 反手频率控制
|
||||
self.reverse_cooldown_seconds = 1.5 * 60 # 反手冷却时间(秒)
|
||||
# 反手过滤(仅价差,无冷却)
|
||||
self.reverse_min_move_pct = 0.05 # 反手最小价差过滤(百分比)
|
||||
self.last_reverse_time = None # 上次反手时间
|
||||
|
||||
# 开仓频率控制
|
||||
self.open_cooldown_seconds = 60 # 开仓冷却时间(秒),两次开仓至少间隔此时长
|
||||
self.last_open_time = None # 上次开仓时间
|
||||
self.last_open_time = None # 上次开仓时间(用于最短持仓时间判断)
|
||||
self.last_open_kline_id = None # 上次开仓所在 K 线 id(仅记录,不限制单 K 线开仓次数)
|
||||
|
||||
self.leverage = "100" # 高杠杆(全仓模式下可开更大仓位)
|
||||
self.open_type = "cross" # 全仓模式
|
||||
self.risk_percent = 0 # 未使用;若启用则可为每次开仓占可用余额的百分比
|
||||
self.stop_loss_usd = -3 # 固定止损:亏损达到 3 美元平仓
|
||||
self.trailing_activation_usd = 6 # 盈利达到此金额后启动移动止损(调高避免波动不大就触发)
|
||||
self.trailing_distance_usd = 3 # 从最高盈利回撤此金额则平仓(调高避免小幅回撤就平)
|
||||
self.max_unrealized_pnl_seen = None # 持仓期间见过的最大盈利(用于移动止损)
|
||||
# 当前K线从极值回落平仓
|
||||
# 模式: 'fixed'=固定点数(drop_from_high_to_close);'pct_retrace'=按本K线涨幅比例动态算回撤
|
||||
self.drop_from_high_mode = 'pct_retrace' # 'fixed' | 'pct_retrace'
|
||||
self.drop_from_high_to_close = 2 # fixed 模式下:回落/反弹超过此价格(点数)则平仓,0 表示关闭
|
||||
# pct_retrace 模式:本K线涨幅 = (最高-开盘)/开盘*100;允许回撤% = 涨幅% * retrace_ratio,从最高点回撤超过则平仓
|
||||
self.retrace_ratio = 0.5 # 回撤系数,如 0.5 表示允许回撤涨幅的 50%(类似斐波那契 50% 回撤)
|
||||
self.min_rise_pct_to_activate = 0.06 # 至少涨/跌这么多才启用动态回撤(调高避免波动不大就触发)
|
||||
self.min_drop_pct_from_high = 0.08 # 至少从最高点回撤这么多%才平仓(调高避免小幅波动就平)
|
||||
# EMA(10) + ATR(14) 平仓(多/空一致):多单跌破 EMA10 或从最高回撤≥ATR 平;空单涨破 EMA10 或从最低反弹≥ATR 平
|
||||
self.use_ema_atr_exit = True # 是否启用 EMA/ATR 平仓规则(多单+空单)
|
||||
self.atr_multiplier = 1.8 # 追踪止盈:从极值回撤/反弹 ≥ 此倍数×ATR(14) 则平仓(调高避免波动不大就平)
|
||||
self.min_hold_seconds = 90 # 开仓/反手后至少持仓此时长才允许技术性止盈(EMA/ATR/K线回撤/移动止损);固定止损始终生效
|
||||
self.min_hold_seconds = 90 # 开仓/反手后至少持仓此时长才允许技术性止盈(EMA/ATR/移动止损)
|
||||
self._candle_high_seen = None # 当前K线内见过的最高价(多头用)
|
||||
self._candle_low_seen = None # 当前K线内见过的最低价(空头用)
|
||||
self._candle_id_for_high_low = None # 记录高低对应的K线 id,换线则重置
|
||||
self._last_exit_kline_id = None # 当前K线出场后,本K线内不再开仓,等下一根K线再判断
|
||||
|
||||
self.open_avg_price = None # 开仓价格
|
||||
self.current_amount = None # 持仓量
|
||||
@@ -570,22 +558,11 @@ class BitmartFuturesTransaction:
|
||||
return None
|
||||
|
||||
def can_open(self, current_kline_id):
|
||||
"""开仓前过滤:仅开仓冷却时间。单根 K 线符合规则可多次开仓。"""
|
||||
now = time.time()
|
||||
if self.last_open_time is not None and now - self.last_open_time < self.open_cooldown_seconds:
|
||||
remain = self.open_cooldown_seconds - (now - self.last_open_time)
|
||||
self._log_throttled("open_cooldown", LOG_SYSTEM + f"开仓冷却中,剩余 {remain:.0f} 秒", interval=1.0)
|
||||
return False
|
||||
"""开仓前过滤(已删除开仓冷却,保留接口便于后续扩展)。"""
|
||||
return True
|
||||
|
||||
def can_reverse(self, current_price, trigger_price):
|
||||
"""反手前过滤:冷却时间 + 最小价差"""
|
||||
now = time.time()
|
||||
if self.last_reverse_time and now - self.last_reverse_time < self.reverse_cooldown_seconds:
|
||||
remain = self.reverse_cooldown_seconds - (now - self.last_reverse_time)
|
||||
self._log_throttled("reverse_cooldown", LOG_SYSTEM + f"反手冷却中,剩余 {remain:.0f} 秒", interval=1.0)
|
||||
return False
|
||||
|
||||
"""反手前过滤:仅最小价差"""
|
||||
if trigger_price and trigger_price > 0:
|
||||
move_pct = abs(current_price - trigger_price) / trigger_price * 100
|
||||
if move_pct < self.reverse_min_move_pct:
|
||||
@@ -708,7 +685,6 @@ class BitmartFuturesTransaction:
|
||||
self.max_unrealized_pnl_seen = None
|
||||
self.last_open_time = time.time() # 反手后的新仓位也受最短持仓时间保护
|
||||
logger.success(LOG_POSITION + "反手做多成功")
|
||||
self.last_reverse_time = time.time()
|
||||
time.sleep(20)
|
||||
return True
|
||||
else:
|
||||
@@ -735,7 +711,6 @@ class BitmartFuturesTransaction:
|
||||
self.max_unrealized_pnl_seen = None
|
||||
self.last_open_time = time.time() # 反手后的新仓位也受最短持仓时间保护
|
||||
logger.success(LOG_POSITION + "反手做空成功")
|
||||
self.last_reverse_time = time.time()
|
||||
time.sleep(20)
|
||||
return True
|
||||
else:
|
||||
@@ -859,9 +834,9 @@ class BitmartFuturesTransaction:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 3.5 止损/止盈/移动止损 + EMA/ATR 平仓 + 当前K线从极值回落平仓
|
||||
# 3.5 移动止损 + EMA/ATR 平仓
|
||||
if self.start != 0:
|
||||
# 当前K线从最高/最低点回落平仓:换线重置跟踪,有持仓时更新本K线内最高/最低价并检查
|
||||
# 换线重置跟踪,有持仓时更新本K线内最高/最低价(供 ATR 追踪用)
|
||||
if self._candle_id_for_high_low != current_kline_time:
|
||||
self._candle_high_seen = None
|
||||
self._candle_low_seen = None
|
||||
@@ -873,7 +848,7 @@ class BitmartFuturesTransaction:
|
||||
self._candle_low_seen = min(self._candle_low_seen or float('inf'), current_price)
|
||||
|
||||
hold_sec = (time.time() - self.last_open_time) if self.last_open_time else 999999
|
||||
allow_technical_exit = hold_sec >= self.min_hold_seconds # 未满最短持仓时间则只允许固定止损
|
||||
allow_technical_exit = hold_sec >= self.min_hold_seconds
|
||||
|
||||
# 多单:EMA(10) + ATR(14) 平仓(需满最短持仓时间)
|
||||
if allow_technical_exit and self.start == 1 and self.use_ema_atr_exit:
|
||||
@@ -882,6 +857,7 @@ class BitmartFuturesTransaction:
|
||||
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)
|
||||
@@ -889,6 +865,7 @@ class BitmartFuturesTransaction:
|
||||
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)
|
||||
@@ -901,6 +878,7 @@ class BitmartFuturesTransaction:
|
||||
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)
|
||||
@@ -908,69 +886,14 @@ class BitmartFuturesTransaction:
|
||||
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
|
||||
|
||||
use_fixed = self.drop_from_high_mode == 'fixed' and self.drop_from_high_to_close and self.drop_from_high_to_close > 0
|
||||
use_pct = self.drop_from_high_mode == 'pct_retrace'
|
||||
if allow_technical_exit and (use_fixed or use_pct):
|
||||
if self.start == 1: # 多头:最高价已在上面更新,这里只做回落判断
|
||||
do_close = False
|
||||
if use_fixed and self._candle_high_seen and current_price <= self._candle_high_seen - self.drop_from_high_to_close:
|
||||
do_close = True
|
||||
reason = f"固定回落 {self.drop_from_high_to_close}"
|
||||
elif use_pct and self._candle_high_seen and current_kline.get('open'):
|
||||
candle_open = float(current_kline['open'])
|
||||
rise_pct = (self._candle_high_seen - candle_open) / candle_open * 100 if candle_open > 0 else 0
|
||||
if rise_pct >= self.min_rise_pct_to_activate:
|
||||
drop_trigger_pct = max(self.min_drop_pct_from_high, rise_pct * self.retrace_ratio)
|
||||
drop_pct = (self._candle_high_seen - current_price) / self._candle_high_seen * 100 if self._candle_high_seen else 0
|
||||
if drop_pct >= drop_trigger_pct:
|
||||
do_close = True
|
||||
reason = f"涨幅 {rise_pct:.3f}% → 允许回撤 {drop_trigger_pct:.3f}%,实际回撤 {drop_pct:.3f}%"
|
||||
else:
|
||||
pass # 涨幅不足,不启用动态回撤
|
||||
if do_close:
|
||||
logger.info(LOG_POSITION + f"多单K线回落平仓 | 最高 {self._candle_high_seen:.2f} 当前 {current_price:.2f} | {reason}")
|
||||
self.平仓()
|
||||
self.max_unrealized_pnl_seen = None
|
||||
self._candle_high_seen = None
|
||||
time.sleep(3)
|
||||
continue
|
||||
elif self.start == -1: # 空头:跟踪当前K线最低价,从最低点反弹超过阈值则平仓
|
||||
self._candle_low_seen = min(self._candle_low_seen or float('inf'), current_price)
|
||||
do_close = False
|
||||
if use_fixed and self._candle_low_seen and current_price >= self._candle_low_seen + self.drop_from_high_to_close:
|
||||
do_close = True
|
||||
reason = f"固定反弹 {self.drop_from_high_to_close}"
|
||||
elif use_pct and self._candle_low_seen and current_kline.get('open'):
|
||||
candle_open = float(current_kline['open'])
|
||||
rise_pct = (candle_open - self._candle_low_seen) / candle_open * 100 if candle_open > 0 else 0 # 对空头是“跌幅”
|
||||
if rise_pct >= self.min_rise_pct_to_activate:
|
||||
drop_trigger_pct = max(self.min_drop_pct_from_high, rise_pct * self.retrace_ratio)
|
||||
bounce_pct = (current_price - self._candle_low_seen) / self._candle_low_seen * 100 if self._candle_low_seen else 0
|
||||
if bounce_pct >= drop_trigger_pct:
|
||||
do_close = True
|
||||
reason = f"跌幅 {rise_pct:.3f}% → 允许反弹 {drop_trigger_pct:.3f}%,实际反弹 {bounce_pct:.3f}%"
|
||||
if do_close:
|
||||
logger.info(LOG_POSITION + f"空单K线反弹平仓 | 最低 {self._candle_low_seen:.2f} 当前 {current_price:.2f} | {reason}")
|
||||
self.平仓()
|
||||
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:
|
||||
# 固定止损:亏损达到 3 美元平仓
|
||||
if pnl_usd <= self.stop_loss_usd:
|
||||
logger.info(LOG_POSITION + f"固定止损平仓 | 亏损 {pnl_usd:.2f} 美元")
|
||||
self.平仓()
|
||||
self.max_unrealized_pnl_seen = None
|
||||
time.sleep(3)
|
||||
continue
|
||||
# 更新持仓期间最大盈利(用于移动止损)
|
||||
if self.max_unrealized_pnl_seen is None:
|
||||
self.max_unrealized_pnl_seen = pnl_usd
|
||||
@@ -981,20 +904,24 @@ class BitmartFuturesTransaction:
|
||||
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)
|
||||
|
||||
# 5. 反手过滤:冷却时间 + 最小价差
|
||||
# 5. 反手过滤:最小价差
|
||||
if signal and signal[0].startswith('reverse_'):
|
||||
if not self.can_reverse(current_price, signal[1]):
|
||||
signal = None
|
||||
|
||||
# 5.5 开仓频率过滤:仅冷却时间,单根 K 线符合规则可多次开仓
|
||||
# 5.5 开仓过滤:当前K线已出场则等下一根K线再开仓
|
||||
if signal and signal[0] in ('long', 'short'):
|
||||
if not self.can_open(current_kline_time):
|
||||
if self._last_exit_kline_id == current_kline_time:
|
||||
self._log_throttled("same_kline_no_open", LOG_SYSTEM + "当前K线已出场,等下一根K线再开仓", interval=2.0)
|
||||
signal = None
|
||||
elif not self.can_open(current_kline_time):
|
||||
signal = None
|
||||
else:
|
||||
self._current_kline_id_for_open = current_kline_time # 供 execute_trade 成功后记录
|
||||
|
||||
Reference in New Issue
Block a user