diff --git a/docs/持仓与成交量低迷期优化分析.md b/docs/持仓与成交量低迷期优化分析.md new file mode 100644 index 0000000..cb81c87 --- /dev/null +++ b/docs/持仓与成交量低迷期优化分析.md @@ -0,0 +1,100 @@ +# 持仓与成交量低迷期优化分析 + +基于 `持仓记录_2026-02-17T02-22-51.json` 与「昨天到今天稳定小亏损、成交量较低」的反馈,做原因归纳和优化方案;并对照你已有的币安接口文档,标出能直接帮助的接口。 + +--- + +## 一、当前持仓快照摘要(2026-02-17) + +| 项目 | 数值 | +|------|------| +| 持仓数 | 9 | +| 多单 / 空单 | 2 / 7(偏空) | +| 总浮盈(USDT) | 约 +0.75(该快照) | +| 浮盈笔数 / 浮亏笔数 | 5 / 4 | +| 浮亏标的 | FILUSDT, XLMUSDT, HUSDT, WLDUSDT | + +说明:若「昨天到今天」整体是稳定小亏损,多半是**已平仓单**的净亏损或**持仓从浮盈回吐**;成交量低会放大滑点、费率占比和假突破,容易加剧小亏。 + +--- + +## 二、成交量偏低时「稳定小亏」的常见原因 + +1. **滑点与冲击成本** + 成交量小 → 盘口薄,市价/条件单成交价差大,开平仓都被「多砍一点」,积少成多。 + +2. **资金费率占比变高** + 持仓过夜/过结算,费率不变但单笔盈利变小,净收益容易被费率吃掉甚至变负。 + +3. **假突破增多** + 波动主要来自少量大单,技术信号(突破、金叉等)更容易假突破,开仓胜率下降。 + +4. **止盈难触发、止损先到** + 波动不足时价格磨蹭,止盈距离难达到,反而先触发止损或长时间横盘后小亏出场。 + +5. **多空结构不利** + 若做多时多头拥挤(费率负、多空比极端),或做空时空头拥挤,结构不利会放大「小亏」。 + +--- + +## 三、你已有的币安文档与可落地的优化 + +下面按「文档 → 能帮上什么」对照,方便你按文档实现或扩展。 + +| 文档 | 能帮助的优化 | +|------|----------------| +| **行情接口REST.txt** | exchangeInfo(规则/合约信息)、ticker/深度/K 线:用于**成交量/深度过滤**(如 24h 量、盘口深度)、**流动性检查**;低量标的可直接从扫描候选剔除或降权。 | +| **行情ws接口.txt / ws行情推送.txt** | 实时 ticker、深度、K 线:可做**入场前二次确认**(如信号满足时再查一次深度或最近成交),减少在极薄盘口下单。 | +| **订单交易更新推送.txt** | ORDER_TRADE_UPDATE(NEW/FILLED/TRADE):已有 User Data 时可用于**成交回报、部分成交处理**;结合「条件单触发」可更快更新 DB、减少重复操作。 | +| **条件订单交易更新推送.txt** | 条件单/ALGO 状态:**止损/止盈/跟踪止损**触发后的实时反馈,便于统计「因何平仓」、优化 SL/TP 参数。 | +| **ws交易接口.txt** | WS 下单(order.place / algoOrder.place):已实现「WS 条件单 + REST 回退」,**减少下单超时**,在弱网或低流动性时更稳。 | +| **用户余额.txt** | 账户余额/可用保证金:用于**按可用保证金动态控仓**,避免在低量、高波动时过度开仓。 | +| **账户信息流连接.txt** | 账户/持仓推送:与现有 User Data 一致,**实时保证金与强平风险**,可做风控与告警。 | + +--- + +## 四、可落地的优化方案(按优先级) + +### 1. 成交量/流动性过滤(直接缓解「低量小亏」) + +- **扫描阶段**:在现有 `MIN_VOLUME_24H_STRICT` 上,可再设「**最低 24h 成交额**」或「**相对前几日量比**」门槛,低量币不进 TOP_N。 +- **开仓前**:用 **行情接口REST** 的深度(如 `GET /fapi/v1/depth`)或 24h ticker,对当前 symbol 做一次**流动性检查**(例如买一卖一价差、前几档挂单量),价差过大或挂单过薄则跳过或减小仓位。 +- **文档**:`行情接口REST.txt` 中的 ticker、depth、K 线即可支持上述逻辑。 + +### 2. 资金费率与多空结构(减少「结构不利」导致的磨损) + +- **开仓前**:已实现的「资金费率过滤」继续保留;可适当**收紧阈值**(如做多时 `lastFundingRate > 0.0005` 就跳过),在低波动期减少费率侵蚀。 +- **扫描阶段**:已实现的「扫描阶段资金费率过滤」可保持或略加强(如 `SCAN_FUNDING_RATE_MAX_ABS` 从 0.001 降到 0.0008),避免把「费率极端」的币选进候选。 +- 若有**大户多空比 / taker 买卖比**接口(在行情或衍生文档中),可作为**排序或过滤**:与开仓方向一致则优先,极端反向则跳过或降权。 + +### 3. 出场优化(止盈难触发、亏损单拿太久) + +- **跟踪止损**:文档与策略建议里已多次提到;在浮盈达到 X% 后改为 `TRAILING_STOP_MARKET`,**锁定部分利润**,避免回吐成小亏。 +- **时间/无盈利止损**:持仓超过 N 小时且浮盈 < 某阈值(或浮亏)→ 市价平仓或收紧止损,减少在低波动里「耗着」造成的资金占用和小亏。 +- **条件单推送**:结合「条件订单交易更新推送」统计**止损/止盈/跟踪止损**的触发比例,用于调 SL/TP 距离和跟踪止损参数。 + +### 4. 开仓节奏与仓位(低量期少开、小开) + +- **降低开仓频率**:低量日可适当增大 `SCAN_INTERVAL` 或提高 `MIN_SIGNAL_STRENGTH`,减少「为做而做」的次优单。 +- **单笔仓位**:在配置里略降 `MAX_POSITION_PERCENT` 或固定风险比例,**单笔亏损上限变小**,整体回撤更可控。 +- **余额与风控**:用「用户余额」或账户信息流,**按可用保证金**动态限制总敞口,避免在波动放大时超额开仓。 + +### 5. 监控与统计(用现有接口即可) + +- **按平仓时间统计**:已实现「按平仓时间」筛选与统计,可看**每日/每周「平仓笔数、平仓盈亏」**,区分「开仓日」与「平仓日」表现。 +- **按标的/按方向**:统计哪些 symbol、多/空在低量期亏损集中,用于**黑名单或降权**(例如某几类币在低量期一律不开或只做一侧)。 + +--- + +## 五、小结与建议顺序 + +- **可能原因**:成交量低 → 滑点大、费率占比高、假突破多、止盈难触发而止损/横盘小亏多;若再叠加多空结构不利,会放大「稳定小亏」。 +- **文档利用**:你已有的行情 REST/WS、订单与条件单推送、WS 交易、用户余额与账户流,**足够**支撑:流动性过滤、资金费率/多空过滤、跟踪止损与时间止损、按保证金控仓、以及统计与监控。 +- **建议实施顺序**: + 1. 加强**成交量/深度过滤**(扫描 + 开仓前检查); + 2. 略**收紧资金费率**阈值、保持或略加强扫描阶段费率过滤; + 3. 上**跟踪止损**与**时间/无盈利止损**; + 4. 低量期**降频、降单笔仓位**,并用余额/账户流做风控; + 5. 用**按平仓时间统计**与条件单推送,持续观察「谁在亏、因何平仓」,再微调标的与参数。 + +如需,我可以按上述某一条(例如「开仓前深度检查」或「时间止损参数」)写出具体实现步骤或伪代码,直接对接到你现有 `market_scanner` / `strategy` / `position_manager`。 diff --git a/trading_system/config.py b/trading_system/config.py index 1ec7208..8e051fb 100644 --- a/trading_system/config.py +++ b/trading_system/config.py @@ -242,6 +242,19 @@ DEFAULT_TRADING_CONFIG = { # 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的,避免进入 TOP_N 'SCAN_FUNDING_RATE_FILTER_ENABLED': True, 'SCAN_FUNDING_RATE_MAX_ABS': 0.001, # 绝对值超过 0.1% 则从扫描候选剔除 + # ===== 市场节奏自动识别(低波动期 vs 正常期,自动切换参数,无需手动)===== + 'MARKET_REGIME_AUTO': True, # 是否根据波动率自动识别并切换低波动期参数 + 'LOW_VOLATILITY_THRESHOLD': 2.5, # 24h |changePercent| 中位数低于此值判为低波动期(%) + 'LOW_VOLATILITY_MAX_POSITION_PERCENT': 0.15, # 低波动期单币最大仓位(正常期用 MAX_POSITION_PERCENT) + 'LOW_VOLATILITY_MIN_SIGNAL_STRENGTH': 9, # 低波动期信号强度门槛(更严) + 'LOW_VOLATILITY_SCAN_FUNDING_RATE_MAX_ABS': 0.0005, # 低波动期扫描阶段资金费率更严(0.05%) + 'TIME_STOP_MAX_HOLD_HOURS': 8, # 持仓超过 N 小时且未达最小盈利则考虑平仓(低波动期更适用) + 'TIME_STOP_MIN_PNL_PCT_TO_HOLD': 0.0, # 持仓超过时间阈值时,若 pnl% 低于此值则平仓(0=允许小亏即走) + 'TIME_STOP_ENABLED': True, # 是否启用时间/无盈利止损(可与 regime 结合:仅低波动期或始终启用) + # 开仓前流动性检查(价差/深度):低量期可减少滑点与冲击成本 + 'LIQUIDITY_CHECK_BEFORE_ENTRY': False, # 默认关闭;开启后开仓前检查盘口价差与深度,不通过则跳过 + 'LIQUIDITY_MAX_SPREAD_PCT': 0.005, # 买一卖一价差超过此比例(0.5%)则跳过 + 'LIQUIDITY_MIN_DEPTH_USDT': 30000, # 前 5 档买卖深度合计名义价值低于此值(USDT)则跳过 # 主动买卖量过滤(可选):与方向一致时通过,极端反向时跳过 'TAKER_RATIO_FILTER_ENABLED': False, # 默认关闭,开启后做多要求 buySellRatio≥下限、做空要求≤上限 'MIN_TAKER_BUY_RATIO_FOR_LONG': 0.85, # 做多时最近1h buySellRatio 低于此值则跳过(主动买不足) @@ -369,6 +382,20 @@ for key, value in DEFAULT_TRADING_CONFIG.items(): if key not in TRADING_CONFIG: TRADING_CONFIG[key] = value + +def get_effective_config(key: str, default=None): + """ + 按当前市场节奏返回有效配置:若 MARKET_REGIME_AUTO 且为低波动期, + 则返回 LOW_VOLATILITY_(若存在),否则返回 TRADING_CONFIG[key]。 + 用于仓位、信号门槛、资金费率阈值、时间止损等,实现自动把握市场节奏。 + """ + try: + from . import market_regime + return market_regime.get_effective_config(key, default) + except ImportError: + return TRADING_CONFIG.get(key, default) + + # 提供一个函数来重新加载配置 def reload_config(): """重新加载配置(供外部调用)""" diff --git a/trading_system/market_regime.py b/trading_system/market_regime.py new file mode 100644 index 0000000..3d66920 --- /dev/null +++ b/trading_system/market_regime.py @@ -0,0 +1,122 @@ +""" +市场节奏自动识别:根据当前波动率/成交量判断「低波动期」与「正常期」, +并自动切换参数(仓位、信号门槛、资金费率阈值、时间止损等),无需手动切换。 +""" +import logging +import time +from typing import Optional, Any + +logger = logging.getLogger(__name__) + +REDIS_KEY_REGIME = "market_regime" +REDIS_KEY_UPDATED_AT = "market_regime_updated_at" +REGIME_LOW = "low_volatility" +REGIME_NORMAL = "normal" +TTL_SEC = 3600 # 1 小时内无更新则视为过期,策略侧回退为 normal + + +def _get_redis(): + """获取 Redis 客户端(与 binance_client 一致)。""" + try: + from . import config + from .redis_cache import RedisCache + rc = RedisCache( + redis_url=getattr(config, "REDIS_URL", "redis://localhost:6379"), + use_tls=getattr(config, "REDIS_USE_TLS", False), + ssl_cert_reqs=getattr(config, "REDIS_SSL_CERT_REQS", "required"), + ssl_ca_certs=getattr(config, "REDIS_SSL_CA_CERTS", None), + username=getattr(config, "REDIS_USERNAME", None), + password=getattr(config, "REDIS_PASSWORD", None), + ) + return rc + except Exception as e: + logger.debug("market_regime Redis 不可用: %s", e) + return None + + +async def update_regime_from_scan( + change_percents: list, + redis_cache: Any = None, + low_volatility_threshold: float = 2.5, +) -> str: + """ + 根据本次扫描得到的 24h 涨跌幅列表,计算中位数绝对波动,更新市场节奏并写入 Redis。 + change_percents: 各 symbol 的 24h changePercent 列表(可含正负) + 返回当前写入的 regime:low_volatility 或 normal。 + """ + if not change_percents: + return REGIME_NORMAL + abs_changes = [abs(float(x)) for x in change_percents if x is not None] + if not abs_changes: + return REGIME_NORMAL + abs_changes.sort() + n = len(abs_changes) + median_abs = abs_changes[n // 2] if n % 2 else (abs_changes[n // 2 - 1] + abs_changes[n // 2]) / 2 + regime = REGIME_LOW if median_abs < low_volatility_threshold else REGIME_NORMAL + cache = redis_cache or _get_redis() + if cache: + try: + await cache.connect() + await cache.set(REDIS_KEY_REGIME, regime, ttl=TTL_SEC) + await cache.set(REDIS_KEY_UPDATED_AT, str(int(time.time())), ttl=TTL_SEC) + logger.info(f"市场节奏: median_24h_change={median_abs:.2f}% -> {regime} (阈值={low_volatility_threshold}%)") + except Exception as e: + logger.debug("写入 market_regime 失败: %s", e) + return regime + + +async def get_regime(redis_cache: Any = None) -> str: + """从 Redis 读取当前市场节奏;无或过期则返回 normal。""" + cache = redis_cache or _get_redis() + if not cache: + return REGIME_NORMAL + try: + await cache.connect() + r = await cache.get(REDIS_KEY_REGIME) + if r in (REGIME_LOW, REGIME_NORMAL): + return r + ts = await cache.get(REDIS_KEY_UPDATED_AT) + if ts and (time.time() - int(ts)) > TTL_SEC: + return REGIME_NORMAL + except Exception as e: + logger.debug("读取 market_regime 失败: %s", e) + return REGIME_NORMAL + + +def get_effective_config(key: str, default: Any = None, account_id: int = None) -> Any: + """ + 根据当前市场节奏返回「有效配置」:若开启自动节奏且当前为低波动期, + 则优先返回 LOW_VOLATILITY_,否则返回 TRADING_CONFIG[key]。 + 用于仓位、信号门槛、资金费率阈值、时间止损等。 + """ + try: + from . import config + except ImportError: + import config + cfg = getattr(config, "TRADING_CONFIG", None) or {} + auto = cfg.get("MARKET_REGIME_AUTO") + if not auto: + return cfg.get(key, default) + low_key = f"LOW_VOLATILITY_{key}" + if low_key not in cfg: + return cfg.get(key, default) + # 同步读 Redis 会阻塞;这里用缓存避免每次读 Redis。策略层在每轮扫描后已更新 regime,本进程内可用内存缓存 + regime = _cached_regime + if regime == REGIME_LOW: + val = cfg.get(low_key) + if val is not None: + return val + return cfg.get(key, default) + + +# 进程内缓存:由扫描器在每次 scan 结束后异步更新,get_effective_config 同步读 +_cached_regime: str = REGIME_NORMAL + + +def set_cached_regime(regime: str) -> None: + global _cached_regime + _cached_regime = regime if regime in (REGIME_LOW, REGIME_NORMAL) else REGIME_NORMAL + + +def get_cached_regime() -> str: + return _cached_regime diff --git a/trading_system/market_scanner.py b/trading_system/market_scanner.py index 50e6553..6eb5367 100644 --- a/trading_system/market_scanner.py +++ b/trading_system/market_scanner.py @@ -120,9 +120,9 @@ class MarketScanner: logger.info(f"初步筛选后,需要详细分析的交易对: {len(pre_filtered_symbols)} 个") - # 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的(文档建议的后续方向) + # 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的;低波动期使用更严阈值(有效配置) scan_funding_enabled = cfg.get('SCAN_FUNDING_RATE_FILTER_ENABLED', False) - scan_funding_max_abs = float(cfg.get('SCAN_FUNDING_RATE_MAX_ABS', 0.001)) + scan_funding_max_abs = float(config.get_effective_config('SCAN_FUNDING_RATE_MAX_ABS', 0.001)) if scan_funding_enabled and pre_filtered_symbols: try: premium_all = await self.client.get_premium_index(None) # 全量,一次请求 @@ -228,6 +228,21 @@ class MarketScanner: self.top_symbols = top_n + # 市场节奏自动识别:用本次扫描的 24h 涨跌幅中位数判断低波动/正常,写入 Redis 并更新进程内缓存 + try: + from . import market_regime + except ImportError: + market_regime = None + if market_regime and getattr(self.client, "redis_cache", None): + # 用过滤后的全部结果计算中位数(样本更多),无则用 top_n + source = filtered_results if filtered_results else top_n + change_percents = [r["changePercent"] for r in source if r.get("changePercent") is not None] + threshold = float(cfg.get("LOW_VOLATILITY_THRESHOLD", config.TRADING_CONFIG.get("LOW_VOLATILITY_THRESHOLD", 2.5))) + regime = await market_regime.update_regime_from_scan( + change_percents, self.client.redis_cache, low_volatility_threshold=threshold + ) + market_regime.set_cached_regime(regime) + # ⚠️ 已禁用扫描结果缓存,确保每个账户都使用最新的市场数据 # 虽然中间数据(K线、技术指标)已经缓存,但最终扫描结果不缓存 # 这样可以避免使用过期的交易对,确保每个账户都基于最新市场数据扫描 diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index 71c030e..b3efe58 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -3835,6 +3835,32 @@ class PositionManager: except Exception as e: logger.debug(f"从Redis重新加载配置失败: {e}") + # 时间/无盈利止损:持仓超过 N 小时且盈利未达阈值则平仓(低波动期减少磨单) + time_stop_enabled = config.TRADING_CONFIG.get('TIME_STOP_ENABLED', False) + if time_stop_enabled: + max_hold_hours = float(config.get_effective_config('TIME_STOP_MAX_HOLD_HOURS', 8) or 8) + min_pnl_to_hold = float(config.TRADING_CONFIG.get('TIME_STOP_MIN_PNL_PCT_TO_HOLD', 0.0) or 0.0) + entry_time = position_info.get('entryTime') + hold_hours = 0.0 + if entry_time: + try: + if isinstance(entry_time, datetime): + hold_hours = (get_beijing_time() - entry_time).total_seconds() / 3600.0 + elif isinstance(entry_time, str): + entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') + hold_hours = (get_beijing_time() - entry_dt).total_seconds() / 3600.0 + else: + hold_hours = (time.time() - (float(entry_time) if isinstance(entry_time, (int, float)) else 0)) / 3600.0 + except Exception as e: + logger.debug(f"{symbol} 解析 entryTime 失败: {e}") + if hold_hours >= max_hold_hours and pnl_percent_margin < min_pnl_to_hold: + logger.info( + f"{symbol} [时间止损] 持仓 {hold_hours:.1f}h >= {max_hold_hours}h 且盈亏 {pnl_percent_margin:.2f}% < {min_pnl_to_hold}%,平仓" + ) + if await self.close_position(symbol, reason='time_stop'): + logger.info(f"{symbol} [时间止损] 平仓成功") + return + # ⚠️ 优化:已完全移除时间锁限制 # 理由:1) 止损和止盈都应该立即执行,不受时间限制 # 2) 交易所级别的止损/止盈单已提供保护 diff --git a/trading_system/risk_manager.py b/trading_system/risk_manager.py index 661acc0..c838ed5 100644 --- a/trading_system/risk_manager.py +++ b/trading_system/risk_manager.py @@ -96,9 +96,10 @@ class RiskManager: margin_value = notional_value / actual_leverage # 重要语义:POSITION_PERCENT 均按“保证金占用比例”计算(更符合 stop_loss/take_profit 的 margin 逻辑) - max_margin_value = available_balance * config.TRADING_CONFIG['MAX_POSITION_PERCENT'] + max_position_pct = config.get_effective_config('MAX_POSITION_PERCENT', 0.20) + max_margin_value = available_balance * max_position_pct min_margin_value = available_balance * config.TRADING_CONFIG['MIN_POSITION_PERCENT'] - max_margin_pct = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] * 100 + max_margin_pct = max_position_pct * 100 min_margin_pct = config.TRADING_CONFIG['MIN_POSITION_PERCENT'] * 100 logger.info(f" 数量: {quantity:.4f}") @@ -593,8 +594,8 @@ class RiskManager: logger.info(f" 名义价值: {notional_value:.2f} USDT") logger.info(f" 保证金: {margin_value:.4f} USDT ({margin_value/total_balance*100:.2f}%)") - # 检查是否超过最大仓位限制 - max_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] + # 检查是否超过最大仓位限制(低波动期自动降低单笔上限) + max_position_percent = config.get_effective_config('MAX_POSITION_PERCENT', 0.20) # ⚠️ 如果启用了固定风险模型,且计算出的仓位合理(风险可控),则放宽 MAX_POSITION_PERCENT 限制 # 因为固定风险模型的核心是控制亏损额,而不是仓位大小 @@ -640,8 +641,9 @@ class RiskManager: logger.info(f" ✓ 信号强度{signal_strength}分,使用100%仓位(高质量信号)") # 根据涨跌幅调整仓位大小(涨跌幅越大,保证金占比可以适当增加) - base_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] * signal_multiplier - max_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] * signal_multiplier + effective_max = config.get_effective_config('MAX_POSITION_PERCENT', 0.20) + base_position_percent = effective_max * signal_multiplier + max_position_percent = effective_max * signal_multiplier min_position_percent = config.TRADING_CONFIG['MIN_POSITION_PERCENT'] # 涨跌幅超过5%时,可以适当增加保证金占比,但必须遵守 MAX_POSITION_PERCENT 上限 @@ -717,7 +719,7 @@ class RiskManager: max_position_percent = 0.95 max_margin_value = available_balance * 0.95 else: - max_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] + max_position_percent = config.get_effective_config('MAX_POSITION_PERCENT', 0.20) max_margin_value = available_balance * max_position_percent if min_margin_usdt <= max_margin_value: @@ -761,7 +763,7 @@ class RiskManager: quantity = quantity * position_scale final_notional_value = quantity * current_price final_margin = final_notional_value / actual_leverage if actual_leverage > 0 else final_notional_value - max_margin_cap = available_balance * config.TRADING_CONFIG.get('MAX_POSITION_PERCENT', 0.08) + max_margin_cap = available_balance * config.get_effective_config('MAX_POSITION_PERCENT', 0.20) if final_margin > max_margin_cap: final_margin = max_margin_cap final_notional_value = final_margin * actual_leverage diff --git a/trading_system/strategy.py b/trading_system/strategy.py index ebcbefd..646e972 100644 --- a/trading_system/strategy.py +++ b/trading_system/strategy.py @@ -196,6 +196,10 @@ class TradingStrategy: if not await self._check_taker_ratio_filter(symbol, trade_direction): logger.info(f"{symbol} 主动买卖量过滤未通过,跳过开仓") continue + # 开仓前流动性检查(可选):价差/深度不达标则跳过,低量期减少滑点 + if not await self._check_liquidity_before_entry(symbol, symbol_info.get('price')): + logger.info(f"{symbol} 流动性检查未通过,跳过开仓") + continue entry_reason = trade_signal['reason'] signal_strength = trade_signal.get('strength', 0) @@ -430,6 +434,48 @@ class TradingStrategy: logger.debug(f"{symbol} 主动买卖量检查失败(放行): {e}") return True + async def _check_liquidity_before_entry(self, symbol: str, current_price: Optional[float] = None) -> bool: + """ + 开仓前流动性检查:盘口价差过大或深度过薄则跳过,减少低量期滑点与冲击成本。 + 依赖 get_depth(symbol, limit=10),检查买一卖一价差与前 5 档深度(USDT)。 + """ + enabled = bool(config.TRADING_CONFIG.get('LIQUIDITY_CHECK_BEFORE_ENTRY', False)) + if not enabled: + return True + try: + depth = await self.client.get_depth(symbol, limit=10) + if not depth or not isinstance(depth, dict): + return True + bids = depth.get('bids') or [] + asks = depth.get('asks') or [] + if not bids or not asks: + logger.info(f"{symbol} 流动性检查:深度为空,跳过开仓") + return False + bid1_p = float(bids[0][0]) + ask1_p = float(asks[0][0]) + mid = (bid1_p + ask1_p) / 2.0 + if mid <= 0: + return True + spread_pct = (ask1_p - bid1_p) / mid + max_spread = float(config.TRADING_CONFIG.get('LIQUIDITY_MAX_SPREAD_PCT', 0.005)) + if spread_pct > max_spread: + logger.info(f"{symbol} 流动性检查:价差 {spread_pct*100:.3f}% > {max_spread*100:.2f}%,跳过开仓") + return False + # 前 5 档深度名义价值(USDT) + depth_usdt = 0.0 + for i, (p, q) in enumerate(bids[:5]): + depth_usdt += float(p) * float(q) + for i, (p, q) in enumerate(asks[:5]): + depth_usdt += float(p) * float(q) + min_depth = float(config.TRADING_CONFIG.get('LIQUIDITY_MIN_DEPTH_USDT', 30000)) + if depth_usdt < min_depth: + logger.info(f"{symbol} 流动性检查:前5档深度 {depth_usdt:.0f} USDT < {min_depth:.0f},跳过开仓") + return False + return True + except Exception as e: + logger.debug(f"{symbol} 流动性检查失败(放行): {e}") + return True + async def _check_volume_confirmation(self, symbol_info: Dict) -> bool: """ 成交量确认 - 确保有足够的成交量支撑 @@ -595,8 +641,8 @@ class TradingStrategy: signal_strength = 0 reasons.append("❌ 逆4H趋势,拒绝交易") - # 判断是否应该交易(信号强度 >= MIN_SIGNAL_STRENGTH 才交易,提高胜率) - min_signal_strength = config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 7) + # 判断是否应该交易(信号强度 >= 有效 MIN_SIGNAL_STRENGTH 才交易;低波动期自动提高门槛) + min_signal_strength = config.get_effective_config('MIN_SIGNAL_STRENGTH', 7) # 强度上限归一到 0-10,避免出现 12/10 这种误导显示 try: signal_strength = max(0, min(int(signal_strength), 10)) diff --git a/持仓记录_2026-02-16T09-45-37.json b/持仓记录_2026-02-16T09-45-37.json deleted file mode 100644 index ce15456..0000000 --- a/持仓记录_2026-02-16T09-45-37.json +++ /dev/null @@ -1,870 +0,0 @@ -[ - { - "id": 5110, - "symbol": "1000BONKUSDT", - "side": "BUY", - "quantity": 3531, - "entry_price": 0.006565, - "entry_value_usdt": 23.181015, - "notional_usdt": 23.459964, - "margin_usdt": 5.864991, - "original_notional_usdt": 23.181015, - "original_margin_usdt": 5.79525375, - "mark_price": 0.006644, - "pnl": 0.278949, - "pnl_percent": 4.7561709813365445, - "leverage": 4, - "entry_time": 1771214454, - "stop_loss_price": 0.00636805, - "take_profit_price": 0.00697531, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460584754, - "type": "TAKE_PROFIT_MARKET", - "side": "SELL", - "stopPrice": 0.006975, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584735, - "type": "STOP_MARKET", - "side": "SELL", - "stopPrice": 0.006369, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.006369 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.006975 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584754, - "type": "TAKE_PROFIT_MARKET", - "side": "SELL", - "stopPrice": 0.006975, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584735, - "type": "STOP_MARKET", - "side": "SELL", - "stopPrice": 0.006369, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5157, - "symbol": "ZECUSDT", - "side": "SELL", - "quantity": 0.077, - "entry_price": 284.54, - "entry_value_usdt": 21.909580000000002, - "notional_usdt": 22.23683, - "margin_usdt": 5.5592075, - "original_notional_usdt": 21.92881912, - "original_margin_usdt": 5.48220478, - "mark_price": 288.79, - "pnl": -0.32725, - "pnl_percent": -5.886630423491117, - "leverage": 4, - "entry_time": 1771226616, - "stop_loss_price": null, - "take_profit_price": null, - "take_profit_1": null, - "take_profit_2": null, - "atr": 14.62428571, - "entry_order_id": 797717260491, - "entry_order_type": "LIMIT", - "open_orders": [ - { - "orderId": 2000000460584806, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 266.76, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584795, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 293.07, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 293.07 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 266.76 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584806, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 266.76, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584795, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 293.07, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5109, - "symbol": "HYPEUSDT", - "side": "SELL", - "quantity": 0.7, - "entry_price": 30.158, - "entry_value_usdt": 21.110599999999998, - "notional_usdt": 20.984715002999998, - "margin_usdt": 5.2461787507499995, - "original_notional_usdt": 21.1106, - "original_margin_usdt": 5.27765, - "mark_price": 29.97816429, - "pnl": 0.12588499, - "pnl_percent": 2.3995558668679244, - "leverage": 4, - "entry_time": 1771214453, - "stop_loss_price": null, - "take_profit_price": null, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": 5837357832, - "entry_order_type": "LIMIT", - "open_orders": [ - { - "orderId": 2000000460584837, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 28.274, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584833, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 31.062, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 31.062 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 28.274 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584837, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 28.274, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584833, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 31.062, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5112, - "symbol": "FILUSDT", - "side": "SELL", - "quantity": 22, - "entry_price": 0.963, - "entry_value_usdt": 21.186, - "notional_usdt": 21.37234946, - "margin_usdt": 5.343087365, - "original_notional_usdt": 21.186, - "original_margin_usdt": 5.2965, - "mark_price": 0.97147043, - "pnl": -0.18634946, - "pnl_percent": -3.4876738348073033, - "leverage": 4, - "entry_time": 1771214455, - "stop_loss_price": 0.99189, - "take_profit_price": 0.9028125, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460584866, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.903, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584857, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.991, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.991 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.903 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584866, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.903, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584857, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.991, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5113, - "symbol": "TAKEUSDT", - "side": "SELL", - "quantity": 172, - "entry_price": 0.03629, - "entry_value_usdt": 6.24188, - "notional_usdt": 5.387599, - "margin_usdt": 5.387599, - "original_notional_usdt": 6.24188, - "original_margin_usdt": 6.24188, - "mark_price": 0.03132325, - "pnl": 0.854281, - "pnl_percent": 15.856432522168037, - "leverage": 1, - "entry_time": 1771214456, - "stop_loss_price": 0.0373787, - "take_profit_price": 0.0272175, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460584904, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.02722, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584895, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.03737, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.03737 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.02722 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584904, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.02722, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584895, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.03737, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5135, - "symbol": "ZROUSDT", - "side": "SELL", - "quantity": 13.5, - "entry_price": 1.6807, - "entry_value_usdt": 22.68945, - "notional_usdt": 22.76581086, - "margin_usdt": 5.691452715, - "original_notional_usdt": 22.68945, - "original_margin_usdt": 5.6723625, - "mark_price": 1.68635636, - "pnl": -0.07636086, - "pnl_percent": -1.3416760855932017, - "leverage": 4, - "entry_time": 1771223082, - "stop_loss_price": 1.731121, - "take_profit_price": 1.57565625, - "take_profit_1": 1.57565625, - "take_profit_2": 1.49288286, - "atr": 0.07825714, - "entry_order_id": 6021914660, - "entry_order_type": "LIMIT", - "open_orders": [ - { - "orderId": 2000000460584948, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 1.4929, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584947, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 1.7311, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 1.7311 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 1.4929 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584948, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 1.4929, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584947, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 1.7311, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5115, - "symbol": "AXSUSDT", - "side": "SELL", - "quantity": 18, - "entry_price": 1.388, - "entry_value_usdt": 24.983999999999998, - "notional_usdt": 24.42318858, - "margin_usdt": 6.105797145, - "original_notional_usdt": 24.984, - "original_margin_usdt": 6.246, - "mark_price": 1.35684381, - "pnl": 0.56081142, - "pnl_percent": 9.184900950390155, - "leverage": 4, - "entry_time": 1771214457, - "stop_loss_price": 1.42964, - "take_profit_price": 1.30125, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460584986, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 1.302, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584975, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 1.429, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 1.429 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 1.302 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460584986, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 1.302, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460584975, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 1.429, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5137, - "symbol": "XLMUSDT", - "side": "SELL", - "quantity": 127, - "entry_price": 0.16858, - "entry_value_usdt": 21.409660000000002, - "notional_usdt": 21.68884283, - "margin_usdt": 5.4222107075, - "original_notional_usdt": 21.40966, - "original_margin_usdt": 5.352415, - "mark_price": 0.17077829, - "pnl": -0.27918283, - "pnl_percent": -5.1488746022694105, - "leverage": 4, - "entry_time": 1771223321, - "stop_loss_price": 0.1736374, - "take_profit_price": 0.15804375, - "take_profit_1": 0.15804375, - "take_profit_2": 0.15550343, - "atr": 0.00544857, - "entry_order_id": 20994894391, - "entry_order_type": "LIMIT", - "open_orders": [ - { - "orderId": 2000000460585021, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.15551, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585020, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.17363, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.17363 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.15551 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460585021, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.15551, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585020, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.17363, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5116, - "symbol": "DASHUSDT", - "side": "SELL", - "quantity": 0.571, - "entry_price": 37.25, - "entry_value_usdt": 21.26975, - "notional_usdt": 21.304009999999998, - "margin_usdt": 5.3260024999999995, - "original_notional_usdt": 21.26975, - "original_margin_usdt": 5.3174375, - "mark_price": 37.31, - "pnl": -0.03426, - "pnl_percent": -0.6432591798445457, - "leverage": 4, - "entry_time": 1771214458, - "stop_loss_price": 38.3675, - "take_profit_price": 34.921875, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460585100, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 34.93, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585093, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 38.36, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 38.36 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 34.93 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460585100, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 34.93, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585093, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 38.36, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5117, - "symbol": "USELESSUSDT", - "side": "BUY", - "quantity": 150, - "entry_price": 0.04083, - "entry_value_usdt": 6.124499999999999, - "notional_usdt": 7.085999999999999, - "margin_usdt": 7.085999999999999, - "original_notional_usdt": 6.1245, - "original_margin_usdt": 6.1245, - "mark_price": 0.04724, - "pnl": 0.9615, - "pnl_percent": 13.56900931414056, - "leverage": 1, - "entry_time": 1771214459, - "stop_loss_price": 0.0396051, - "take_profit_price": 0.0510375, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460585145, - "type": "TAKE_PROFIT_MARKET", - "side": "SELL", - "stopPrice": 0.05103, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585138, - "type": "STOP_MARKET", - "side": "SELL", - "stopPrice": 0.03961, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.03961 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.05103 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460585145, - "type": "TAKE_PROFIT_MARKET", - "side": "SELL", - "stopPrice": 0.05103, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585138, - "type": "STOP_MARKET", - "side": "SELL", - "stopPrice": 0.03961, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5118, - "symbol": "ENAUSDT", - "side": "SELL", - "quantity": 194, - "entry_price": 0.1196, - "entry_value_usdt": 23.2024, - "notional_usdt": 23.53230864, - "margin_usdt": 5.88307716, - "original_notional_usdt": 23.2024, - "original_margin_usdt": 5.8006, - "mark_price": 0.12130056, - "pnl": -0.32990864, - "pnl_percent": -5.607756468725288, - "leverage": 4, - "entry_time": 1771214460, - "stop_loss_price": 0.123188, - "take_profit_price": 0.112125, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460585199, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.1122, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585168, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.1231, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.1231 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.1122 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460585199, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.1122, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460585168, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.1231, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - }, - { - "id": 5151, - "symbol": "WLFIUSDT", - "side": "SELL", - "quantity": 219, - "entry_price": 0.1011, - "entry_value_usdt": 22.1409, - "notional_usdt": 22.23684171, - "margin_usdt": 5.5592104275, - "original_notional_usdt": 22.1409, - "original_margin_usdt": 22.1409, - "mark_price": 0.10153809, - "pnl": -0.09594171, - "pnl_percent": -1.7258154058245532, - "leverage": 4, - "entry_time": 1771226264, - "stop_loss_price": null, - "take_profit_price": null, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": 2846730648, - "entry_order_type": "LIMIT", - "open_orders": [], - "active_sl_orders": "", - "active_tp_orders": "", - "binance_open_orders_raw": [] - }, - { - "id": 5123, - "symbol": "WLDUSDT", - "side": "SELL", - "quantity": 56, - "entry_price": 0.4028, - "entry_value_usdt": 22.5568, - "notional_usdt": 22.65973696, - "margin_usdt": 5.66493424, - "original_notional_usdt": 22.5568, - "original_margin_usdt": 5.6392, - "mark_price": 0.40463816, - "pnl": -0.10293696, - "pnl_percent": -1.8170901133002384, - "leverage": 4, - "entry_time": 1771214479, - "stop_loss_price": 0.414884, - "take_profit_price": 0.377625, - "take_profit_1": null, - "take_profit_2": null, - "atr": null, - "entry_order_id": null, - "entry_order_type": null, - "open_orders": [ - { - "orderId": 2000000460523250, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.3777, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460523242, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.4148, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ], - "active_sl_orders": "STOP_MARKET @ 0.4148 (NEW)", - "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.3777 (NEW)", - "binance_open_orders_raw": [ - { - "orderId": 2000000460523250, - "type": "TAKE_PROFIT_MARKET", - "side": "BUY", - "stopPrice": 0.3777, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - }, - { - "orderId": 2000000460523242, - "type": "STOP_MARKET", - "side": "BUY", - "stopPrice": 0.4148, - "price": 0, - "origType": "CONDITIONAL", - "reduceOnly": true, - "status": "NEW" - } - ] - } -] \ No newline at end of file