84 lines
2.8 KiB
Markdown
84 lines
2.8 KiB
Markdown
---
|
||
name: parse-signal-trader-and-price-pitfall
|
||
description: "trader 解析 fallback + 价格格式化 (避免 18 位小数和"币种"误标)"
|
||
version: 1.0.0
|
||
type: reference
|
||
---
|
||
|
||
# ⚠️ process_signal.py: trader 解析 + 价格格式化 实战教训
|
||
|
||
## Bug 1: `trader` 字段错误 = "币种"
|
||
|
||
**症状**: 推送里显示 `信号源: 币种 ? SKHY (价值$?)` — trader 字段名是 "币种",不是真 trader。
|
||
|
||
**根因**: `parse_signal` L41 用 `re.search(r'【([^】]+)】', text)` 抓**第一个**方括号 — 第一个就是 `【币种】...`,导致 trader = "币种"。
|
||
|
||
**真实 trader** 通常不是 `【X】` 格式,而是 **`👉 跟单就选 X聚合社区`**(在信号末尾)。
|
||
|
||
### 修复方案 (3 层 fallback)
|
||
|
||
```python
|
||
FIELD_NAMES = {'币种', '方向', '杠杆', '仓位大小', '仓位价值', '开仓价',
|
||
'当前价', '未实现盈亏', '收益额', '持仓量', '强平价', '数量'}
|
||
|
||
# 1. 优先: 【交易员】标签
|
||
m_trader = re.search(r'【交易员】\s*[::]?\s*([^【\n]{1,20})', text)
|
||
if m_trader:
|
||
fields['trader'] = m_trader.group(1).strip()
|
||
else:
|
||
# 2. Fallback: 👉 跟单就选 X (真实 trader 来源)
|
||
m_follow = re.search(r'👉\s*跟单就选\s*(\S+)', text)
|
||
if m_follow:
|
||
fields['trader'] = m_follow.group(1).strip()
|
||
else:
|
||
# 3. 最终 fallback: 第一个【xx】但跳过字段名
|
||
m_first = re.search(r'【([^】]{1,20})】', text)
|
||
if m_first and m_first.group(1) not in FIELD_NAMES:
|
||
fields['trader'] = m_first.group(1).strip()
|
||
else:
|
||
fields['trader'] = 'unknown'
|
||
```
|
||
|
||
### 测试用例
|
||
|
||
```python
|
||
signal = """📈 注意
|
||
【币种】: SKHYUSDT|永续|5x
|
||
【方向】: 做空 🟥
|
||
【仓位】: 528.16 SKHY
|
||
【开仓价】: 161.90000
|
||
👉 跟单就选 X聚合社区"""
|
||
|
||
parse_signal(signal)['trader'] # ✅ "X聚合社区" (不再是 "币种")
|
||
```
|
||
|
||
## Bug 2: 价格小数位溢出 (18 位)
|
||
|
||
**症状**: `入场: $161.01076124567473` — OKX 返回的浮点 × 比率算出 18 位小数。
|
||
|
||
**根因**: f-string 直接嵌入 float,没有 round。
|
||
|
||
### 修复: 通用 _fmt() helper
|
||
|
||
```python
|
||
def _fmt(x, n=4):
|
||
"""格式化数字: 字符串保留原样, 数字 round 到 n 位."""
|
||
try:
|
||
return f"{float(x):.{n}f}"
|
||
except (ValueError, TypeError):
|
||
return str(x)
|
||
|
||
# 模板里全部用 _fmt()
|
||
msg = f"""⚡ 跟单建议 ...
|
||
入场: ${_fmt(entry_price)} | 当前: ${_fmt(current)}
|
||
• SL: ${_fmt(rec['sl_price'])} → 预亏 -{_fmt(rec.get('sl_pnl', 0))} USDT
|
||
"""
|
||
```
|
||
|
||
⚠️ **`value` 缺失**: OKX 信号有时价值字段空 (e.g. `价值 $?`),`_fmt` 不能 float('?') 抛异常,**保留 `?`** — 让推送显示 "?" 但不报错。
|
||
|
||
## 相关
|
||
|
||
- `process_signal.py` L36-67 (parse_signal)
|
||
- `process_signal.py` L217-302 (format_message)
|
||
- 测试: `python3 -c "import process_signal; process_signal.parse_signal(s)"` |