From 1ff12eaba396960309ef44f2a0f0a832f02ec466 Mon Sep 17 00:00:00 2001 From: ddrwode <34234@3来 34> Date: Fri, 6 Feb 2026 16:36:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=B1=95=E7=A4=BA=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../四分之一,五分钟,反手条件充足修改版.py | 94 +++++++++++++------ 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/bitmart/四分之一,五分钟,反手条件充足修改版.py b/bitmart/四分之一,五分钟,反手条件充足修改版.py index b7a290c..e5f7bde 100644 --- a/bitmart/四分之一,五分钟,反手条件充足修改版.py +++ b/bitmart/四分之一,五分钟,反手条件充足修改版.py @@ -1,6 +1,7 @@ import sys import time from datetime import datetime +from collections import deque from tqdm import tqdm from loguru import logger @@ -40,7 +41,7 @@ LOG_SYSTEM = _tag("系统", _M) if not USE_RICH_DASHBOARD: logger.remove() - logger.add(sys.stderr, format="\033[2m│\033[0m {message}", colorize=False) + logger.add(sys.stderr, format="\033[2m│\033[0m {message}", colorize=False, level="INFO") def log_kline_header(kline_id): """新 K 线分块头(仅非 Rich 模式使用)""" @@ -81,7 +82,8 @@ def make_metrics_panel(state: dict) -> Panel: return Panel(t, title="[bold]价格 / 指标[/bold]", border_style="magenta") def make_logs_panel(logs: list) -> Panel: - body = "\n".join(logs[-12:]) if logs else "等待日志..." + recent = list(logs)[-16:] if logs else [] + body = "\n".join(recent) if recent else "等待日志..." text = Text.from_ansi(body) if body else Text("等待日志...", style="dim") return Panel(text, title="[bold]状态 / 日志[/bold]", border_style="green") @@ -166,8 +168,10 @@ class BitmartFuturesTransaction: self.current_open = None # Rich 仪表盘:状态与日志(供 build_dashboard_layout 使用) self._display_state = {} - self._display_logs = [] + self._display_logs = deque(maxlen=120) self._display_triggers = {} + self._last_signal_log_kline_id = None + self._log_throttle_at = {} def get_klines(self): """获取最近2根K线(当前K线和上一根K线)""" @@ -424,6 +428,15 @@ class BitmartFuturesTransaction: else: logger.info(text) + def _log_throttled(self, key, text, interval=1.0, level="info"): + """同类日志限频,避免 0.1 秒循环刷屏。""" + now = time.time() + last = self._log_throttle_at.get(key, 0) + if now - last < interval: + return + self._log_throttle_at[key] = now + getattr(logger, level)(text) + def calculate_entity(self, kline): """计算K线实体大小(绝对值)""" return abs(kline['close'] - kline['open']) @@ -458,12 +471,17 @@ class BitmartFuturesTransaction: 检查交易信号 返回: ('long', trigger_price) / ('short', trigger_price) / None """ + current_kline_id = current_kline.get('id') + should_log_snapshot = self._last_signal_log_kline_id != current_kline_id + # 计算上一根K线实体 prev_entity = self.calculate_entity(prev_kline) # 实体过小不交易(实体 < 0.1) if prev_entity < 0.1: - logger.info(LOG_PRICE + f"上一根K线实体过小: {prev_entity:.4f},跳过信号检测") + if should_log_snapshot: + logger.info(LOG_PRICE + f"上一根K线实体过小: {prev_entity:.4f},跳过信号检测") + self._last_signal_log_kline_id = current_kline_id return None # 获取上一根K线的实体上下边 @@ -504,17 +522,19 @@ class BitmartFuturesTransaction: 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(LOG_PRICE + f"上一根阳线且当前开盘价({current_kline['open']:.2f})>上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") - else: - logger.info(LOG_PRICE + f"上一根阴线且当前开盘价({current_kline['open']:.2f})<上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") - logger.info(LOG_PRICE + f"当前价: {current_price:.2f} | 上一根实体: {prev_entity:.4f} | 实体上边: {prev_entity_upper:.2f} 下边: {prev_entity_lower:.2f}") - logger.info(LOG_PRICE + f"做多触发(下1/4): {long_trigger:.2f} | 做空触发(上1/4): {short_trigger:.2f} | 突破做多: {long_breakout:.2f} | 突破做空: {short_breakout:.2f}") - if skip_short_by_upper_third: - logger.info(LOG_PRICE + "上一根阴+当前阳(做多形态),不按上1/4做空") - if skip_long_by_lower_third: - logger.info(LOG_PRICE + "上一根阳+当前阴(做空形态),不按下1/4做多") + if should_log_snapshot: + if use_current_open_as_base: + if prev_is_bullish_for_calc and current_open_above_prev_close: + logger.info(LOG_PRICE + f"上一根阳线且当前开盘价({current_kline['open']:.2f})>上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") + else: + logger.info(LOG_PRICE + f"上一根阴线且当前开盘价({current_kline['open']:.2f})<上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") + logger.info(LOG_PRICE + f"当前价: {current_price:.2f} | 上一根实体: {prev_entity:.4f} | 实体上边: {prev_entity_upper:.2f} 下边: {prev_entity_lower:.2f}") + logger.info(LOG_PRICE + f"做多触发(下1/4): {long_trigger:.2f} | 做空触发(上1/4): {short_trigger:.2f} | 突破做多: {long_breakout:.2f} | 突破做空: {short_breakout:.2f}") + if skip_short_by_upper_third: + logger.info(LOG_PRICE + "上一根阴+当前阳(做多形态),不按上1/4做空") + if skip_long_by_lower_third: + logger.info(LOG_PRICE + "上一根阳+当前阴(做空形态),不按下1/4做多") + self._last_signal_log_kline_id = current_kline_id self._display_triggers = {"long_trigger": long_trigger, "short_trigger": short_trigger, "long_breakout": long_breakout, "short_breakout": short_breakout} @@ -553,7 +573,7 @@ class BitmartFuturesTransaction: 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) - logger.info(LOG_SYSTEM + f"开仓冷却中,剩余 {remain:.0f} 秒") + self._log_throttled("open_cooldown", LOG_SYSTEM + f"开仓冷却中,剩余 {remain:.0f} 秒", interval=1.0) return False return True @@ -562,13 +582,13 @@ class BitmartFuturesTransaction: 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) - logger.info(LOG_SYSTEM + f"反手冷却中,剩余 {remain:.0f} 秒") + 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: - logger.info(LOG_SYSTEM + f"反手价差不足: {move_pct:.4f}% < {self.reverse_min_move_pct}%") + self._log_throttled("reverse_move_small", LOG_SYSTEM + f"反手价差不足: {move_pct:.4f}% < {self.reverse_min_move_pct}%", interval=1.0) return False return True @@ -733,13 +753,25 @@ class BitmartFuturesTransaction: page_start = True if USE_RICH_DASHBOARD: - self._display_logs = [] + self._display_logs.clear() logger.remove() + level_color = { + "DEBUG": "\033[2m", + "INFO": "\033[36m", + "SUCCESS": "\033[32m", + "WARNING": "\033[33m", + "ERROR": "\033[31m", + "CRITICAL": "\033[35m", + } + def _sink(msg): - self._display_logs.append(msg.record["message"]) - if len(self._display_logs) > 50: - self._display_logs.pop(0) - logger.add(_sink, format="{message}") + record = msg.record + ts = record["time"].strftime("%H:%M:%S") + level = record["level"].name + color = level_color.get(level, "\033[37m") + line = f"\033[2m{ts}\033[0m {color}{level:<7}\033[0m {record['message']}" + self._display_logs.append(line) + logger.add(_sink, format="{message}", level="INFO") live = None if USE_RICH_DASHBOARD: @@ -783,8 +815,11 @@ class BitmartFuturesTransaction: current_kline_time = current_kline['id'] if self.last_kline_time != current_kline_time: self.last_kline_time = current_kline_time - logger.info("") - log_kline_header(current_kline_time) + if USE_RICH_DASHBOARD: + logger.info(LOG_SYSTEM + f"进入新K线: {current_kline_time}") + else: + logger.info("") + log_kline_header(current_kline_time) # 2. 获取当前价格 current_price = self.get_current_price() @@ -799,7 +834,12 @@ class BitmartFuturesTransaction: time.sleep(2) continue - logger.debug(f"当前持仓状态: {self.start} (0=无, 1=多, -1=空)") + self._log_throttled( + "position_state", + f"当前持仓状态: {self.start} (0=无, 1=多, -1=空)", + interval=2.0, + level="debug", + ) # 更新仪表盘左侧数据(供 Rich 展示) try: @@ -984,7 +1024,7 @@ class BitmartFuturesTransaction: if USE_RICH_DASHBOARD: logger.remove() - logger.add(sys.stderr, format="{message}") + logger.add(sys.stderr, format="{message}", level="INFO") if __name__ == '__main__':