akg-factor-bridge/sql/astock_kg_card_views.sql

104 lines
5.7 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 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=<owner> -e AKG_PG_PASSWORD=<pw> \
-- 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;