"""修正 Hummingbot bitget_perpetual candles feed 的换根延迟。 上游 _parse_websocket_message 里是: candle = data["data"][0] 而 Bitget 在换根时会推一条带两根的消息 [上一根, 新一根]。取 [0] 拿到的是 上一根,其时间戳与 deque 尾部相同,于是只做了原地更新;新一根要等下一条 单元素消息才进入 deque——实测晚约 1.1 秒。 不能简单改成 [-1]:那样上一根的收盘价就永远停在换根前约 1 秒的那次推送上。 1m 信号对 0.25bp 的扰动都会换掉一半(见 signal_sensitivity.py),收盘价 偏一个 tick 是不能接受的。所以这里把**除最后一根外的元素就地写回 deque**, 再把最后一根交给基类走正常的 append 流程。 已向上游反馈前,本地用子类覆盖,不改动镜像。 """ from __future__ import annotations from typing import Any, Dict, Optional import numpy as np from hummingbot.data_feed.candles_feed.bitget_perpetual_candles import ( BitgetPerpetualCandles, ) def _row_to_dict(row: list, ensure_s) -> Dict[str, Any]: return {"timestamp": ensure_s(int(row[0])), "open": float(row[1]), "high": float(row[2]), "low": float(row[3]), "close": float(row[4]), "volume": float(row[5]), "quote_asset_volume": float(row[6]), "n_trades": 0., "taker_buy_base_volume": 0., "taker_buy_quote_volume": 0.} class PatchedBitgetPerpetualCandles(BitgetPerpetualCandles): """与上游唯一的差别:一条消息里的多根 K 线全部处理,而非只取第一根。""" def _parse_websocket_message(self, data: dict) -> Optional[Dict[str, Any]]: if data == "pong": return None if not (data and data.get("data") and data.get("action") == "update"): return None rows = data["data"] # 前面的元素都是已收盘 K 线的最终值:就地覆盖,保住真实收盘价 for row in rows[:-1]: d = _row_to_dict(row, self.ensure_timestamp_in_seconds) self._overwrite_existing(d) # 最后一根交给基类:时间戳更大就 append,相同就原地更新 return _row_to_dict(rows[-1], self.ensure_timestamp_in_seconds) def _overwrite_existing(self, d: Dict[str, Any]) -> None: if not len(self._candles): return ts = int(d["timestamp"]) if int(self._candles[-1][0]) != ts: return self._candles[-1] = np.array( [d["timestamp"], d["open"], d["high"], d["low"], d["close"], d["volume"], d["quote_asset_volume"], d["n_trades"], d["taker_buy_base_volume"], d["taker_buy_quote_volume"]] ).astype(float)