-- astock-kg 候选卡插槽视图:三张只读视图,供 akg-factor-bridge 的候选卡与复盘消费。 -- 应用【桥机 155 · ~/project/akg-factor-bridge】: -- docker compose exec -T akg-factor-bridge python run.py apply-views --file sql/astock_kg_card_views.sql --dry-run -- docker compose exec -T -e AKG_PG_USER= -e AKG_PG_PASSWORD= \ -- akg-factor-bridge python run.py apply-views --file sql/astock_kg_card_views.sql -- -- 与 sql/astock_kg_slot_views.sql 分开放:那份文件用 DROP + CREATE 且含 ALTER TABLE, -- 整文件重跑会把生产在用的四张视图重删重建;本文件只用 CREATE OR REPLACE,反复应用无害。 -- 基座零代码:只读现有表 transmission_candidates、segment_members_projection、 -- segment_member_review、mkt_daily。应用时避开 06:10 的投影重建窗口。 -- 出处:docs/主观选股改进方案_2026-09-02.md 第 2.2 节第二项。 -- 一、已动成员视图 v_factor_transmission_moved -- 被传导指向的环节(只认 Segment 目标;Concept 与 Company 目标的成员不在投影表里)的 -- 投影成员,减去传导台账里的未动名单 quiet,再减去复核账本判定"不属于本环节"的成员 -- (verdict = 'exclude',与基座 transmission.scan 在算已动之前的剔除口径一致)。 -- 连接键用投影表的原名 COALESCE(orig_segment_name, segment_name):投影期有改派重排, -- 传导扫描用的目标名是图上原名。 -- 本视图只做集合差,不重算涨幅;"已动"的口径与基座 hotspot._movers_set 同源 -- (数据日涨幅达到 3%),涨幅本身从 v_factor_stock_daily 取。 -- 对账:按 (scan_date, target) 数本视图行数 + quiet 行数,与 transmission_candidates 的 -- members_total 比;不等的环节多半是基座扫描时成员集有上限(cap=200)而投影表没有, -- 差异分"截断"与"真差异"两类,只对后者要求为零。 CREATE OR REPLACE VIEW v_factor_transmission_moved AS WITH tc AS ( SELECT t.scan_date, t.rank, t.target, t.mkt_trade_date, t.chain_fit, t.members_total, t.moved, t.moved_ratio, (SELECT count(DISTINCT p->>'source') FROM jsonb_array_elements(COALESCE(t.paths, '[]'::jsonb)) p) AS n_sources, t.quiet FROM transmission_candidates t WHERE t.target_type = 'Segment' ), quiet AS ( SELECT c.scan_date, c.target, q->>'ts_code' AS ts_code FROM tc c CROSS JOIN LATERAL jsonb_array_elements(COALESCE(c.quiet, '[]'::jsonb)) q WHERE q->>'ts_code' IS NOT NULL AND q->>'ts_code' <> '' ), members AS ( SELECT DISTINCT COALESCE(orig_segment_name, segment_name) AS seg, ts_code, member_name, segment_name AS projected_segment FROM segment_members_projection WHERE ts_code IS NOT NULL AND ts_code <> '' ) SELECT c.scan_date, c.target, c.rank, c.n_sources, c.chain_fit, c.members_total, c.moved, c.moved_ratio, c.mkt_trade_date, m.ts_code, m.member_name, m.projected_segment FROM tc c JOIN members m ON m.seg = c.target LEFT JOIN quiet q ON q.scan_date = c.scan_date AND q.target = c.target AND q.ts_code = m.ts_code WHERE q.ts_code IS NULL AND NOT EXISTS ( SELECT 1 FROM segment_member_review r WHERE r.ts_code = m.ts_code AND r.segment_name = c.target AND r.verdict = 'exclude'); -- 二、个股日行情视图 v_factor_stock_daily -- 候选卡"已启动"门槛(pct_change)与两条展示线(net_z 主力净额对自身二十日基线的 -- 标准化偏离、heat_chg 热度较往前第五个交易日的变化)的数据来源,只留行情列。 -- 吸筹不从这里取:基座落库的吸筹状态没有评分日,候选卡的吸筹三项只认决策系统结论表。 CREATE OR REPLACE VIEW v_factor_stock_daily AS SELECT trade_date, code AS ts_code, (metrics->>'pct_change')::numeric AS pct_change, (metrics->>'net_z')::numeric AS net_z, (metrics->>'heat_chg')::numeric AS heat_chg, (metrics->>'heat')::numeric AS heat, (metrics->>'net_amount')::numeric AS net_amount FROM mkt_daily WHERE kind = 'stock'; -- 三、环节日行情视图 v_factor_segment_daily -- 按投影表把个股日行情聚成环节行,只给原始值与成员明细集合;"主力净额前两名"、 -- "涨停近似(涨幅超 9.8%)"这类派生判断在桥的 card.py 算,不写进基座视图。 -- 投影表是当前态(每晨 06:10 删后插),历史日的成员集合带成员前视,复盘按冻结快照重建。 CREATE OR REPLACE VIEW v_factor_segment_daily AS WITH members AS ( SELECT DISTINCT COALESCE(orig_segment_name, segment_name) AS seg, ts_code, member_name FROM segment_members_projection WHERE ts_code IS NOT NULL AND ts_code <> '' ) SELECT s.trade_date, p.seg AS segment_name, count(*) AS members, count(*) FILTER (WHERE s.pct_change >= 3) AS moved, percentile_cont(0.5) WITHIN GROUP (ORDER BY s.pct_change) AS pct_median, percentile_cont(0.5) WITHIN GROUP (ORDER BY s.heat_chg) AS heat_chg_median, jsonb_agg(jsonb_build_object('ts_code', p.ts_code, 'name', p.member_name, 'pct', s.pct_change, 'net_amount', s.net_amount) ORDER BY s.pct_change DESC NULLS LAST) AS members_detail FROM members p JOIN ( SELECT trade_date, code AS ts_code, (metrics->>'pct_change')::numeric AS pct_change, (metrics->>'heat_chg')::numeric AS heat_chg, (metrics->>'net_amount')::numeric AS net_amount FROM mkt_daily WHERE kind = 'stock' ) s ON s.ts_code = p.ts_code GROUP BY s.trade_date, p.seg;