"""把真实场内日行情同步进 `fin_market_price`(下单的硬前置)。 ## 什么时候要跑 `fin_market_price` 是下单的硬前置:`TradeService` 要求产品在这张表里有 `close_price > 0`、`total_fund_shares > 0`,且 `source_updated_at` 落在 `MAX_QUOTE_AGE` 内。 **行情过期后没有任何自动刷新机制**,表现是下单全线 `503 FUND_QUOTE_UNAVAILABLE`, 而错误信息只说"行情已过期",看不出根因。 所以:**每次演示/验收之前跑一次本脚本**。它同时解决两件事: · 把只有 2 只产品的行情补齐到全部场内产品(`seed_sim_account_demo` 只写 2 只); · 把已有行情的时间戳刷新到当前,让新鲜度校验通过。 ## 数据源 腾讯行情(`qt.gtimg.cn`)—— 本环境唯一可用的行情源:东财的 push2 / push2his 两个行情域名实测一律连接被拒(`Server disconnected`),而它的净值/概况域名正常。 总份额按"已有值 → 腾讯总市值推算 → 季度规模兜底"的优先级确定,详见 `app/service/market_price_sync_service.py`。 ## 用法 python tools/sync_market_prices.py # 全部场内产品 python tools/sync_market_prices.py --codes 510300,510500 """ from __future__ import annotations import argparse import asyncio import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from app.service.market_price_sync_service import ( # noqa: E402 MarketPriceSyncService, summarize, ) if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(errors="replace") # type: ignore[union-attr] async def main() -> int: parser = argparse.ArgumentParser(description="同步场内日行情到 fin_market_price") parser.add_argument("--codes", default="", help="只同步这些产品代码(逗号分隔)") args = parser.parse_args() codes = tuple(code.strip() for code in args.codes.split(",") if code.strip()) service = MarketPriceSyncService() result = await service.sync(product_codes=codes or None) print(summarize(result)) skipped = result.get("skipped") or [] if skipped: print("\n未同步的产品(以及原因):") for item in skipped: print(f" · {item['product_code']} {item['reason']}") if not result.get("written"): print("\n[警告] 一行都没写 —— 下单仍然会失败。") return 1 print("\n完成。下单应已可用(过期校验看的是 source_updated_at)。") return 0 if __name__ == "__main__": sys.exit(asyncio.run(main()))