eqdp-brief / src /constants.py
Palani-Unison
Initial commit: flip web layer from Next.js to Streamlit
f6dac2a
Raw
History Blame Contribute Delete
3 kB
"""Canonical constants for sg-eqdp-scanner.
Single source of truth referenced by analytical code, tests, and docs.
Bump deliberately, not accidentally — any change here invalidates downstream
results. Cross-referenced by `memory.md` and `docs/STRATEGY.md`.
"""
from __future__ import annotations
from typing import Final
import pandas as pd
# yfinance ticker convention
SGX_SUFFIX: Final[str] = ".SI"
STI_TICKER: Final[str] = "^STI"
# Programme events. Keys are stable IDs used in abnormal_returns.event_id.
EVENTS: Final[dict[str, str]] = {
"announcement": "2025-02-21",
"tranche_1": "2025-07-21",
"tranche_2": "2025-11-19",
"expansion": "2026-02-12",
}
def event_date(event_id: str) -> pd.Timestamp:
"""Return the canonical event date as a tz-naive Timestamp."""
return pd.Timestamp(EVENTS[event_id]).tz_localize(None)
# The nine EQDP-appointed managers across both tranches.
EQDP_MANAGERS: Final[tuple[str, ...]] = (
# Tranche 1 (Jul 2025)
"Avanda Investment Management",
"Fullerton Fund Management",
"JPMorgan Asset Management",
# Tranche 2 (Nov 2025)
"Amova Asset Management", # formerly Nikko AM
"AR Capital",
"BlackRock",
"Eastspring Investments",
"Lion Global Investors",
"Manulife Investment Management",
)
EQDP_MANAGER_TRANCHE: Final[dict[str, int]] = {
"Avanda Investment Management": 1,
"Fullerton Fund Management": 1,
"JPMorgan Asset Management": 1,
"Amova Asset Management": 2,
"AR Capital": 2,
"BlackRock": 2,
"Eastspring Investments": 2,
"Lion Global Investors": 2,
"Manulife Investment Management": 2,
}
# Candidate-score weights — see docs/METHODOLOGY.md §3. Must sum to 1.0.
SCORE_WEIGHTS: Final[dict[str, float]] = {
"liquidity_rise": 0.30,
"institutional_proxy": 0.20,
"index_inclusion": 0.15,
"broker_named": 0.15,
"filing_present": 0.20,
}
# CAPM β estimation window — 252 trading days (≈1 year) ending 30 days before event.
CAPM_BETA_WINDOW_DAYS: Final[int] = 252
CAPM_GAP_DAYS: Final[int] = 30
# Default event windows (trading-day offsets relative to event date).
EVENT_WINDOWS: Final[dict[str, tuple[int, int]]] = {
"announcement": (-5, 20),
"tranche_1": (-1, 10),
"tranche_2": (-1, 10),
"expansion": (-1, 20),
}
# Benchmark options for abnormal-return computation.
BENCHMARK_CAPM: Final[str] = "capm"
BENCHMARK_FF3: Final[str] = "ff3"
BENCHMARK_MARKET: Final[str] = "market_adjusted"
BENCHMARKS: Final[tuple[str, ...]] = (BENCHMARK_CAPM, BENCHMARK_FF3, BENCHMARK_MARKET)
# Tier identifiers used everywhere in the codebase and DB.
TIER_T1: Final[str] = "T1"
TIER_T2: Final[str] = "T2"
TIER_T3: Final[str] = "T3"
TIER_CONTROL: Final[str] = "control"
TIER_NONE: Final[str] = "none"
TIERS: Final[tuple[str, ...]] = (TIER_T1, TIER_T2, TIER_T3, TIER_CONTROL, TIER_NONE)
# Bootstrap configuration — docs/METHODOLOGY.md §10.
BOOTSTRAP_REPLICATIONS: Final[int] = 5_000
BOOTSTRAP_BLOCK_LENGTH: Final[int] = 5