"""add pit_universe_membership view Revision ID: q8h9i0j1k2l3 Revises: p7g8h9i0j1k2 Create Date: 2026-05-30 PIT(Point-in-Time) 유니버스 멤버십 뷰. finra_short_volume에서 (date, symbol)을 그대로 노출하는 뷰. 각 날짜에 실제 거래되던 종목 집합 = PIT 멤버십. 생존편향-0 달성 근거: - finra_short_volume은 2018-08-01 ~ 현재, 22,722개 심볼 보유 - 그 중 16,143개는 현 활성 유니버스(9,635)에 없는 상폐/합병/과거 종목 - SIVB(2023-03-09), SBNY(2023-03-10), FRC(2023-04-28), TWTR(2022-10-27) 등 실제 상폐일에 정확히 끊김 → 생존편향 없이 PIT 멤버십 표현 사용 예: -- 특정 날짜에 거래된 종목 집합 (PIT 유니버스) SELECT DISTINCT symbol FROM pit_universe_membership WHERE d = '2023-03-09' ORDER BY symbol; -- 공매도비율 × PIT 멤버십 (생존편향-0 횡단면) SELECT p.d, p.symbol, p.short_ratio, a.close FROM pit_universe_membership p LEFT JOIN alpaca_price_data a ON a.ticker = p.symbol AND a.date::date = p.d AND a.interval = '1d' WHERE p.d = '2023-03-09' ORDER BY p.short_ratio; 한계: - 티커 재활용: BBBY(2023-05 파산 → 2025-08 다른 엔티티 재사용) 등 심볼 기준 PIT는 상폐 경계에서 두 회사를 혼동할 수 있음. 엄밀 해결은 CUSIP/PERMNO(유료) 매핑 필요. - 2020-04-01 ~ 2020-10-31 데이터 결손 (COVID 갭). backfill_finra_2020_gap.py 실행 후 해소 가능. - NMS 슈퍼셋: ETF/ADR/워런트(/U, /WS) 포함. 분석단에서 심볼 패턴 필터 권장. """ from typing import Sequence, Union from alembic import op revision: str = "q8h9i0j1k2l3" down_revision: Union[str, Sequence[str], None] = "p7g8h9i0j1k2" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # CREATE OR REPLACE VIEW: idempotent, safe to re-run # 성능: idx_finra_date (date), idx_finra_symbol_date (symbol, date) 인덱스를 # Postgres가 베이스 테이블에서 자동 활용하므로 별도 뷰 인덱스 불필요 op.execute(""" CREATE OR REPLACE VIEW pit_universe_membership AS SELECT date::date AS d, symbol, total_volume, short_volume, short_exempt_volume, short_ratio, market FROM finra_short_volume """) def downgrade() -> None: op.execute("DROP VIEW IF EXISTS pit_universe_membership")