lzf_0626
87a753f7b3
feat(sync): 给 fin_market_price 补真实行情同步链路(下单前置)
## 解决的问题
全流程验收时发现:**20 只产品里只有 2 只有行情,其余下单直接 503**;而且行情一旦过期
就**没有任何机制刷新**。根因是这张表此前**只有演示种子脚本写**,而它是下单的硬前置
(TradeService 要求 close_price>0、total_fund_shares>0、source_updated_at 在 MAX_QUOTE_AGE 内)。
## 数据源(踩了两个坑才选对)
1) **东财 push2 / push2his 两个行情域名在本环境一律连不上**
(RemoteProtocolError: Server disconnected),而它的 api.fund(净值)与
fundf10(概况/费率)**正常** —— 即东财只有"行情类"接口不可达。
一开始按 K 线方案写完,20 只全失败;排查时还被我自己的 except 吞掉过异常。
2) 一度怀疑被限流,等 90 秒仍失败;做源可用性对照才确认是**域名级不可达**。
最终选**腾讯行情**(qt.gtimg.cn):一次请求可带多只,给今开/最高/最低/现价/
成交量(手)/成交额(万元)/**总市值(亿元)**,正好够写一行日行情。
K 线能力仍保留在适配器里(别的网络环境可能可达),注释写明本环境不可用。
## 实现
- EastmoneyFundAdapter.fetch_tencent_quotes:解析腾讯的位置约定格式,只取语义明确的
字段并对价格做合理性校验;成交额万元→元、成交量按"手"(与东财 K 线口径一致,实测同为 9666652)。
- MarketPriceSyncService(新):编排 + 落库。总份额按
「已有值 → 腾讯总市值推算 → 季度规模兜底」的优先级确定,source 标明是否含推算成分;
三者都拿不到就**跳过该产品**,不编份额。
- ools/sync_market_prices.py(新):CLI,演示/验收前跑一次。
## 另一个坑:非交易日的假行情行
种子脚本用 rade_date = date.today() 写行情,而 2026-09-13 是**周六**、真实行情时间是
09-11 16:14。TradeService 取 order_by(trade_date.desc()).limit(1),于是那两行假的"今天"
永远排在真实行情前面——表现是"同步成功了、下单还说行情过期"。已删除那两行。
## 验证
- 同步:请求 20 只、落库 19 行(160129 腾讯源没有该代码)
- 下单:510300 @4.579、510500 @7.611、159948 @3.693、511810 @100.012 全部 201 已成交
—— 用的是**真实行情价**,不再是种子编的 4.5/6.2
- 风控处置闭环:新建 ALDEMO0003 后确认接收→进入调查→到达终态,
ack_status=已确认、handler_id=9002
## 顺带发现的疑点(未改,留给风控线确认)
ALDEMO0003 到达终态时 status='已关闭' 但 **closed_at 与 handle_result 都是 NULL**;
对照 ALDEMO0001(已排除)则 closed_at 有值。结案时间是否应该写入,需业务侧确认。
门禁:ruff 通过 / mypy 250 文件 0 错 / 单元+契约 1380 passed 2 skipped。
2026-09-13 21:14:13 +08:00
..
2026-09-12 12:10:10 +08:00
2026-09-12 14:57:17 +08:00
2026-09-10 20:33:13 +08:00
2026-09-11 16:57:47 +08:00
2026-09-11 17:26:18 +08:00
2026-09-13 19:47:10 +08:00
2026-09-12 14:40:53 +08:00
2026-09-10 22:29:23 +08:00
2026-09-10 22:42:17 +08:00
2026-09-12 12:20:01 +08:00
2026-09-12 12:57:16 +08:00
2026-09-12 15:21:34 +08:00
2026-09-12 14:43:05 +08:00
2026-09-10 20:15:09 +08:00
2026-09-12 15:21:34 +08:00
2026-09-10 20:29:12 +08:00
2026-09-11 16:57:47 +08:00
2026-09-11 10:13:48 +08:00
2026-09-13 19:39:16 +08:00
2026-09-10 17:11:52 +08:00
2026-09-11 16:57:47 +08:00
2026-09-11 16:57:47 +08:00
2026-09-10 18:14:03 +08:00
2026-09-12 15:37:36 +08:00
2026-09-12 12:09:55 +08:00
2026-09-12 15:21:34 +08:00
2026-09-12 14:43:05 +08:00
2026-09-11 12:47:01 +08:00
2026-09-11 14:46:40 +08:00
2026-09-11 21:03:58 +08:00
2026-09-11 21:03:58 +08:00
2026-09-09 21:55:37 +08:00
2026-09-12 12:20:01 +08:00
2026-09-10 20:22:53 +08:00
2026-09-10 22:34:20 +08:00
2026-09-12 10:34:28 +08:00
2026-09-11 16:57:47 +08:00
2026-09-11 16:57:47 +08:00
2026-09-12 10:45:40 +08:00
2026-09-09 21:55:37 +08:00
2026-09-09 21:55:37 +08:00
2026-09-13 16:20:39 +08:00
2026-09-11 20:30:27 +08:00
2026-09-11 14:24:45 +08:00
2026-09-11 16:51:52 +08:00
2026-09-11 16:51:52 +08:00
2026-09-11 14:19:05 +08:00
2026-09-11 16:28:19 +08:00
2026-09-12 14:40:53 +08:00
2026-09-13 19:17:56 +08:00
2026-09-13 18:54:09 +08:00
2026-09-11 10:13:48 +08:00
2026-09-11 19:51:44 +08:00
2026-09-11 16:40:15 +08:00
2026-09-11 14:46:40 +08:00
2026-09-10 21:36:23 +08:00
2026-09-10 21:55:03 +08:00
2026-09-11 15:25:45 +08:00
2026-09-11 15:25:45 +08:00
2026-09-11 17:26:18 +08:00
2026-09-11 16:57:47 +08:00
2026-09-12 10:34:28 +08:00
2026-09-11 14:46:40 +08:00
2026-09-11 14:46:40 +08:00
2026-09-12 14:43:05 +08:00
2026-09-11 12:54:51 +08:00
2026-09-13 15:56:54 +08:00
2026-09-13 16:19:54 +08:00
2026-09-12 14:43:05 +08:00
2026-09-11 14:46:40 +08:00
2026-09-12 10:45:40 +08:00
2026-09-11 16:57:47 +08:00
2026-09-12 12:10:10 +08:00
2026-09-11 19:51:51 +08:00
2026-09-13 21:14:13 +08:00
2026-09-11 21:03:58 +08:00
2026-09-11 13:05:33 +08:00
2026-09-11 10:27:29 +08:00
2026-09-11 16:57:47 +08:00