币种标记标准化 + data-pipeline诊断文档
stale_detector: HK股价格输出加(HKD)标记,防止LLM混读CNY/HKD per_stock_reassess: 写回decisions.json的HK股加上currency: HKD docs/data-pipeline-diagnosis.md: 完整数据管道重构需求文档 避免建滔积层板CNY/HKD错配类问题复发
This commit is contained in:
@@ -43,29 +43,23 @@ def main():
|
||||
try:
|
||||
import urllib.request
|
||||
code_raw = entry.get("code", "")
|
||||
sym_map = {"6":"sh","5":"sh","0":"sz","3":"sz"}
|
||||
prefix = ""
|
||||
for k, v in sym_map.items():
|
||||
if code_raw.startswith(k):
|
||||
prefix = v
|
||||
break
|
||||
# 港股5位代码(含0开头)→ 前缀hk
|
||||
if len(code_raw) == 5 and code_raw[0] in '01':
|
||||
prefix = "hk"
|
||||
else:
|
||||
sym_map = {"6":"sh","5":"sh","0":"sz","3":"sz"}
|
||||
for k, v in sym_map.items():
|
||||
if code_raw.startswith(k):
|
||||
prefix = v
|
||||
break
|
||||
if not prefix:
|
||||
prefix = "hk" if len(code_raw) == 5 else "sz"
|
||||
prefix = "sz"
|
||||
url = f"http://qt.gtimg.cn/q={prefix}{code_raw}"
|
||||
resp = urllib.request.urlopen(url, timeout=5)
|
||||
text = resp.read().decode("gbk")
|
||||
fields = text.split('"')[1].split("~")
|
||||
price = float(fields[3]) if fields[3] else 0
|
||||
# 港股:腾讯API返回HKD,统一转CNY
|
||||
if len(code_raw) == 5 and code_raw[0] in '01':
|
||||
try:
|
||||
sys.path.insert(0, '/home/hmo/MoFin')
|
||||
from hk_rate import hkd_to_cny
|
||||
_hkd_rate = hkd_to_cny()
|
||||
except Exception:
|
||||
_hkd_rate = 0.87
|
||||
price = round(price * _hkd_rate, 2)
|
||||
print(f" 实时价: {price} {'(CNY)' if len(code_raw) == 5 and code_raw[0] in '01' else ''}")
|
||||
print(f" 实时价: {price} {'(港股HKD)' if len(code_raw) == 5 and code_raw[0] in '01' else ''}")
|
||||
except Exception as e:
|
||||
print(f" 实时价获取失败: {e}", file=sys.stderr)
|
||||
# Try portfolio.json as fallback (price_monitor keeps live prices)
|
||||
@@ -117,6 +111,8 @@ def main():
|
||||
|
||||
# 更新 decisions_map 中对应的条目
|
||||
updated = entry.copy()
|
||||
# 币种标记:HK股保留HKD原始值,A股为CNY
|
||||
is_hk = len(str(code)) == 5 and str(code)[0] in '01'
|
||||
updated.update({
|
||||
"action": result["action"],
|
||||
"stop_loss": result.get("stop_loss", entry.get("stop_loss")),
|
||||
@@ -128,6 +124,7 @@ def main():
|
||||
"rr_ratio": result.get("rr_ratio", entry.get("rr_ratio", 0)),
|
||||
"status": result.get("status", "updated"),
|
||||
"price": price,
|
||||
"currency": "HKD" if is_hk else "CNY",
|
||||
})
|
||||
# Save last reassessed price for debounce tracking
|
||||
updated["last_reassessed_price"] = price
|
||||
|
||||
@@ -55,6 +55,9 @@ def fetch_prices(codes):
|
||||
if not oc:
|
||||
continue
|
||||
p = float(fld[3]) if fld[3] else 0
|
||||
# NOTE: HK stock prices kept in HKD — decisions.json also stores HK values in HKD
|
||||
# (stop_loss/take_profit/entry). Never convert here or we mismatch CNY price vs HKD stop.
|
||||
# Downstream tools that need CNY should convert at display time.
|
||||
c = fld[32] if len(fld) > 32 else "0"
|
||||
results[oc] = (p, c)
|
||||
except (ValueError, IndexError):
|
||||
@@ -120,6 +123,10 @@ def main():
|
||||
|
||||
issues, flags = [], []
|
||||
tag = "[自选]" if is_wl else "[持仓]"
|
||||
# 币种标记(港股HKD vs A股CNY,辅助下游LLM避免混读)
|
||||
currency_suffix = "(HKD)" if len(str(code)) == 5 and str(code)[0] in '01' else ""
|
||||
price_str = f"{price:.2f}{currency_suffix}"
|
||||
buy_zone_str = f"{el}~{eh}{currency_suffix}" if currency_suffix else f"{el}~{eh}"
|
||||
|
||||
# -- 偏离 --
|
||||
if is_wl and el and eh:
|
||||
@@ -152,16 +159,16 @@ def main():
|
||||
if strategy_deficient:
|
||||
flags.append("[STRATEGY_STALE]")
|
||||
prefix = "⚠️仓位挤占 " if position_pct > 80 else ""
|
||||
issues.append(f"[STRATEGY_STALE] {prefix}价{price:.2f}在买入区{el}~{eh}但策略不完整({'RR='+f'{rr:.2f}<1.5' if rr_invalid else '无止盈位' if not tp else '非买入信号'}),买入区需重评")
|
||||
issues.append(f"[STRATEGY_STALE] {prefix}价{price_str}在买入区{buy_zone_str}但策略不完整({'RR='+f'{rr:.2f}<1.5' if rr_invalid else '无止盈位' if not tp else '非买入信号'}),买入区需重评")
|
||||
else:
|
||||
prefix = "⚠️仓位挤占 " if position_pct > 80 else ""
|
||||
issues.append(f"[PUSH] {prefix}价{price:.2f}入买入区{el}~{eh}")
|
||||
issues.append(f"[PUSH] {prefix}价{price_str}入买入区{buy_zone_str}")
|
||||
elif price > eh * 1.35:
|
||||
flags.append("[WL_HIGH]")
|
||||
issues.append(f"价{price:.2f}高出买入区+{((price/eh)-1)*100:.0f}%,买入区需重评")
|
||||
issues.append(f"价{price_str}高出买入区+{((price/eh)-1)*100:.0f}%,买入区需重评")
|
||||
elif price > eh * 1.20:
|
||||
flags.append("[WL_DRIFT]")
|
||||
issues.append(f"价{price:.2f}高于买入区+{((price/eh)-1)*100:.0f}%")
|
||||
issues.append(f"价{price_str}高于买入区+{((price/eh)-1)*100:.0f}%")
|
||||
elif not is_wl and eh:
|
||||
dp = (price / eh - 1) * 100
|
||||
if dp > 35:
|
||||
@@ -215,7 +222,7 @@ def main():
|
||||
pass
|
||||
|
||||
if issues:
|
||||
print(f"{' '.join(flags)} {tag} {name}({code}) 价{price:.2f}{chg} | 买入{el}~{eh} | {'; '.join(issues)}")
|
||||
print(f"{' '.join(flags)} {tag} {name}({code}) 价{price_str}{chg} | 买入{el}~{eh} | {'; '.join(issues)}")
|
||||
found += 1
|
||||
|
||||
if found == 0:
|
||||
|
||||
Reference in New Issue
Block a user