Files
Chan/ChanMacro/config.py
T
jackyu66gitandClaude 71951019fb chanmacro: Signal Expectancy Engine V1 — Market Memory System
Phase A-C complete: 4 core factors, regime detection, signal tracking, Bayesian expectancy.

chanmacro/ (32 files, ~4000 lines):
- models: 12 enums + 15 Pydantic v2 models (DateAwareModel, MarketStateVector, etc.)
- fetchers: OHLCV + Breadth (from data_provider) + Derivatives (new endpoint)
- scoring: Price Structure / Breadth (quantile buckets) / OI Matrix (5 discrete states) / Volatility Regime
- regime_detector: 3-state (TREND/RANGE/PANIC), factor-locked (Price+Breadth+Vol), versioned, 2-day confirmation
- expectancy: SignalTracker (record+outcomes), TimeDecay (half-life=180d), BayesianExpectancyEngine (Empirical Bayes, Leveled, SufficiencyGuard)
- validation: FactorValidator (IC/ICIR/Hit Ratio), RegimeValidator (MI/KL/ANOVA), TransitionValidator (stability)
- CLI: fetch|score|regime|track|backfill|expectancy|validate|serve
- tests: 52 passing (models, scoring, regime, expectancy)

data_provider:
- /api/derivatives endpoint: funding rate, OI, OI change, basis
- _derivatives storage: same persist pattern as K-line (merge→lock→snapshot→atomic write)
- background refresh every 60s

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 17:44:55 +08:00

115 lines
4.6 KiB
Python

"""
config.py — Global configuration for ChanMacro.
All weights, thresholds, and paths are configurable.
V1 weights are deliberately simple; they will be tuned via Phase 0 validation.
"""
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional
@dataclass
class Config:
"""Global configuration. Override via config.json or env vars."""
# ── Paths ──────────────────────────────────────────────
db_path: str = "data/macro.db"
data_dir: str = "data"
# ── Data Provider ──────────────────────────────────────
provider_url: str = "http://127.0.0.1:80"
btc_symbol: str = "BTC/USDT:USDT"
top50_symbols: list[str] = field(default_factory=lambda: [
"BTC/USDT:USDT", "ETH/USDT:USDT", "SOL/USDT:USDT",
"BNB/USDT:USDT", "XRP/USDT:USDT", "DOGE/USDT:USDT",
"ADA/USDT:USDT", "AVAX/USDT:USDT", "DOT/USDT:USDT",
"LINK/USDT:USDT", "MATIC/USDT:USDT", "UNI/USDT:USDT",
"ATOM/USDT:USDT", "LTC/USDT:USDT", "ETC/USDT:USDT",
"FIL/USDT:USDT", "APT/USDT:USDT", "ARB/USDT:USDT",
"OP/USDT:USDT", "NEAR/USDT:USDT",
"INJ/USDT:USDT", "TIA/USDT:USDT", "SUI/USDT:USDT",
"SEI/USDT:USDT", "RUNE/USDT:USDT",
])
# ── Breadth ────────────────────────────────────────────
breadth_top_n: list[int] = field(default_factory=lambda: [20, 30, 50])
breadth_ema_period: int = 20
breadth_new_high_window: int = 20
# ── Regime (factor-locked: Price + Breadth + Vol) ─────
regime_version: str = "v1_price_breadth_vol"
# Weights for trend_score within regime detection
regime_w_price: float = 0.35
regime_w_breadth: float = 0.50
regime_w_vol: float = 0.15
# Weights for panic_score
regime_panic_w_anti_trend: float = 0.60
regime_panic_w_vol_extreme: float = 0.40
# ── Price Structure ────────────────────────────────────
ps_ema_fast: int = 20
ps_ema_mid: int = 60
ps_ema_slow: int = 120
ps_adx_period: int = 14
ps_adx_threshold: int = 25
ps_atr_period: int = 14
ps_bb_period: int = 20
ps_roc_periods: list[int] = field(default_factory=lambda: [5, 10, 20])
# ── OI Matrix ──────────────────────────────────────────
oi_price_threshold_pct: float = 0.5 # min price change% to classify
oi_oi_threshold_pct: float = 0.5 # min OI change% to classify
# ── Volatility Regime ──────────────────────────────────
vol_atr_period: int = 14
vol_hv_short: int = 20
vol_hv_long: int = 60
# Thresholds (ATR/Close %)
vol_low_threshold: float = 2.0
vol_high_threshold: float = 5.0
vol_explosive_threshold: float = 10.0
# ── Trend (L2 aggregation) ─────────────────────────────
trend_w_price: float = 0.30
trend_w_breadth: float = 0.70
# ── Maturity Score ─────────────────────────────────────
maturity_w_trend: float = 0.50
maturity_w_breadth: float = 0.30
maturity_w_vol: float = 0.20
# ── Expectancy ─────────────────────────────────────────
half_life_days: int = 180
sufficiency_min_effective: int = 30
sufficiency_low: int = 50
sufficiency_medium: int = 100
level_min_samples: int = 50
knn_max_distance: float = 0.35
knn_k: int = 200
# ── Validation ─────────────────────────────────────────
min_history_days: int = 365
regime_min_avg_duration: int = 5
regime_max_flip_rate: float = 0.15
@classmethod
def from_json(cls, path: str = "config.json") -> "Config":
"""Load config from JSON file, overriding defaults."""
import json
config = cls()
try:
with open(path) as f:
data = json.load(f)
for key, value in data.items():
if hasattr(config, key):
setattr(config, key, value)
except FileNotFoundError:
pass
return config
# Global singleton
config = Config()