From fbb1171a45d988f8a3bc98f06b00e5a324c6fb8e Mon Sep 17 00:00:00 2001 From: Windows Date: Fri, 11 Sep 2026 19:51:51 +0800 Subject: [PATCH] feat: add quote sync command --- docs/21-投顾Agent迁移TODO.md | 2 +- tools/sync_advisor_market_quotes.py | 40 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tools/sync_advisor_market_quotes.py diff --git a/docs/21-投顾Agent迁移TODO.md b/docs/21-投顾Agent迁移TODO.md index b947a79..b848570 100644 --- a/docs/21-投顾Agent迁移TODO.md +++ b/docs/21-投顾Agent迁移TODO.md @@ -160,7 +160,7 @@ Redis 不可用时实测按设计降级放行;生产装配模式因本机 Milv 3 warnings`,契约测试 `8 passed`,独立迁移库集成测试 `28 passed,1 skipped`,Ruff 和 MyPy 通过。 真实验收:`159511` 与 `510500` 对比返回 `ready`、2 个产品和差异字段。实现提交:`b6429e0`。 -阶段十六完成双源行情编排:新增 `MarketQuoteSyncService` 及三个行情健康/来源运行/告警表的 ORM +阶段十六完成双源行情编排:新增 `MarketQuoteSyncService` 和 `tools/sync_advisor_market_quotes.py` 入口及三个行情健康/来源运行/告警表的 ORM 映射,东方财富主源失败或部分返回时按优先级切换腾讯备用源;记录来源状态、连续失败次数、开放告警 及恢复关闭,成功行情按字段精度量化后写入场内行情快照。真实独立库同步验证两源均失败时返回 `degraded=true`、不写入伪行情并进入失败告警链路;本次无可用行情,推荐和动态配置继续失败关闭。 diff --git a/tools/sync_advisor_market_quotes.py b/tools/sync_advisor_market_quotes.py new file mode 100644 index 0000000..694039c --- /dev/null +++ b/tools/sync_advisor_market_quotes.py @@ -0,0 +1,40 @@ +"""Refresh listed-fund quotes through the dual-source health pipeline.""" + +from __future__ import annotations + +import argparse +import asyncio +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +from app.service.market_quote_sync_service import MarketQuoteSyncService # noqa: E402 + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Sync listed Southern Fund market quotes") + parser.add_argument( + "--product-code", action="append", dest="product_codes", + help="Limit sync to a product code; can be repeated", + ) + return parser.parse_args() + + +async def run(args: argparse.Namespace) -> None: + codes = tuple(args.product_codes) if args.product_codes else None + result = await MarketQuoteSyncService().sync(product_codes=codes) + print( + f"sync_run_no={result['sync_run_no']} requested={result['requested_count']} " + f"quotes={result['quote_count']} degraded={result['degraded']}" + ) + for source in result["sources"]: + print( + f"source={source['source']} status={source['status']} " + f"quotes={source['quote_count']} error={source['error_type']}" + ) + + +if __name__ == "__main__": + asyncio.run(run(parse_args()))