From 8fd134a063b8c0492f3848387adda1f066b46198 Mon Sep 17 00:00:00 2001 From: hmo Date: Tue, 30 Jun 2026 01:31:42 +0800 Subject: [PATCH] fix: mo_bridge cache path (reports/ + data/market_review/) + mo_dsa_opinion.py standalone DSA strategy reference script --- mo_bridge.py | 19 ++++++++++-- mo_dsa_opinion.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 mo_dsa_opinion.py diff --git a/mo_bridge.py b/mo_bridge.py index 76648df..5acbe48 100644 --- a/mo_bridge.py +++ b/mo_bridge.py @@ -159,10 +159,23 @@ def get_market_review(region: str = "cn", force_refresh: bool = False) -> str: return "" # 先读缓存(优先,快) - cache_dir = Path(str(_DSA_BASE)) / "data" / "market_review" - if cache_dir.exists(): + cache_dirs = [ + Path(str(_DSA_BASE)) / "reports", # DSA 生成的市场报告目录 + Path(str(_DSA_BASE)) / "data" / "market_review", + ] + for cache_dir in cache_dirs: + if not cache_dir.exists(): + continue try: - files = sorted(cache_dir.glob("*.md"), key=os.path.getmtime, reverse=True) + pattern = f"market_review_*.md" if "report" in str(cache_dir) else "*.md" + files = [] + for p in cache_dir.glob("market_review_*.md"): + files.append(p) + if not files: + for p in cache_dir.glob("*.md"): + if "market" in p.name.lower() or "review" in p.name.lower(): + files.append(p) + files.sort(key=os.path.getmtime, reverse=True) if files: if (datetime.now().timestamp() - os.path.getmtime(str(files[0]))) < 86400: content = files[0].read_text(encoding="utf-8") diff --git a/mo_dsa_opinion.py b/mo_dsa_opinion.py new file mode 100644 index 0000000..85407e2 --- /dev/null +++ b/mo_dsa_opinion.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +""" +mo_dsa_opinion.py — DSA 策略问股(第二意见) + +用 DSA 的 15 种策略独立分析一只股票,和 MoFin 自己的分析做交叉验证。 +不替代 MoFin,只做参考。 + +用法: + # 分析一只股票 + python3 mo_dsa_opinion.py 00700 腾讯控股 + + # 指定策略 + python3 mo_dsa_opinion.py 600519 贵州茅台 --skills ma_golden_cross,chan_theory + + # 作为 cron job 调用(静默模式,输出到文件) + python3 mo_dsa_opinion.py 00700 腾讯控股 --quiet + +输出格式: + ## 🤖 DSA 策略参考 + - 评分: 72/100 + - 建议: 持有 + - 趋势: 看多 + - 策略: ma_golden_cross, bull_trend + - 摘要: ... + - 风险: ... +""" + +import sys, os, json, argparse + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +def main(): + parser = argparse.ArgumentParser(description="DSA 策略问股") + parser.add_argument("code", help="股票代码") + parser.add_argument("name", nargs="?", default="", help="股票名称") + parser.add_argument("--skills", default="ma_golden_cross,bull_trend", + help="策略列表,逗号分隔") + parser.add_argument("--quiet", action="store_true", help="静默模式") + parser.add_argument("--json", action="store_true", help="JSON 输出") + args = parser.parse_args() + + skills = [s.strip() for s in args.skills.split(",") if s.strip()] + + if not args.quiet: + print(f"🔍 DSA 分析 {args.code} {args.name}...", flush=True) + print(f" 策略: {', '.join(skills)}", flush=True) + + from mo_bridge import get_stock_analysis, get_strategy_opinion_text + + # 先获取新闻和大盘上下文 + from mo_bridge import enrich_analysis_context + ctx = enrich_analysis_context(args.code, args.name, region="cn") + + opinion = get_stock_analysis(args.code, args.name, skills=skills) + + if not opinion: + print("❌ DSA 分析失败(LLM 超时或 DSA 不可用)") + sys.exit(1) + + if args.json: + print(json.dumps(opinion, ensure_ascii=False, indent=2)) + else: + print() + print(get_strategy_opinion_text(opinion)) + + # MoFin 对比提示 + print() + print("---") + print("⚠️ 以上是 DSA 独立分析,仅供参考。") + print(" MoFin 的分析以 strategy_lifecycle 为准。") + print(" 如果两方结论一致 → 增强信心") + print(" 如果两方结论冲突 → 关注分歧点,人工判断") + +if __name__ == "__main__": + main()