Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

## Unreleased

- Added PIT release rules (`alphaforge.pit.release_rules`): `NthBusinessDay`, `NthWeekday`, `CalendarDay`, `FixedLagMonths`, `QuarterlyRelease`, `WeeklyRelease`, and `CustomRule` with a tagged-union registry for YAML round-trips.
- Added vintage resolvers (`alphaforge.pit.resolvers`): `RealtimeResolver`, `LatestResolver`, and `FrozenResolver` implementing the `VintageResolver` protocol for point-in-time backtesting views.
- Added `VintageView` value object (`alphaforge.pit.views`) to declare realtime / latest / frozen vintage strategies without coupling to resolution logic.
- Added PIT panel builder utilities (`alphaforge.pit.panel`): `build_pit_panel` and `long_to_wide` for assembling aligned panels from PIT snapshots.
- Added missingness taxonomy (`alphaforge.pit.missingness`) for classifying NaN cells in nowcasting panels by cause.
- Added vintage selection and lookahead validation utilities (`alphaforge.pit.vintage`): `select_vintage_for_asof` and `validate_no_lookahead`.
- Fixed CI linting errors: removed unused imports and sorted import blocks across new modules and test files.
- Fixed mypy type errors: tightened `_register` signature in `pit/release_rules.py`, added `name: str` to `Parametric` protocol in `pipeline/protocols.py`, and corrected `Mapping[Any, str]` annotation in `data/short_rates.py`.

- Added `alphaforge.evaluation` package with pluggable metric infrastructure:
- `MetricFn` protocol (runtime-checkable) for composable forecast accuracy metrics.
- Built-in implementations: `RMSE`, `MAE`, `DirectionalAccuracy`, `MAPE`, `MeanError`.
- Pre-built suites: `DEFAULT_METRICS` (RMSE + MAE + DA), `BENCHMARK_METRICS` (adds MeanError + MAPE).
- API reference page: `docs/api/evaluation-metrics.md`.
- Fixed type annotation errors in `pit/accessor.py` and `pit/models.py` (stale `type: ignore` comments, TypedDict narrowing, and `ast.Call` attribute access error codes).
- Fixed linting errors: sorted import blocks (ruff I001) in `alphaforge/__init__.py`, `alphaforge/pit/__init__.py`, `alphaforge/pit/accessor.py`, `alphaforge/pit/gdp.py`, `alphaforge/pit/tasks.py`; removed unused imports (ruff F401) in `alphaforge/data/public_web/cftc_cot.py`.
- Fixed mypy type narrowing error in `iter_walk_forward_folds` (`pit/tasks.py`): replaced `int(min_train_size)` with a direct reference guarded by a type-narrowing assertion.
Expand Down
17 changes: 10 additions & 7 deletions alphaforge/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@
from .data.fred_source import FREDDataSource
from .data.panel import PanelFrame
from .data.pit_source import PITDataSource
from .data.short_rates import (
ShortRateDataset,
build_duan_weekly_dataset,
build_kim_orphanides_dataset,
build_macro_finance_dataset,
build_policy_rule_dataset,
)
from .data.public_web import (
ANPFuelPricesDataSource,
B3HistoricalQuotesDataSource,
Expand All @@ -35,6 +28,13 @@
)
from .data.query import Query
from .data.schema import TableSchema
from .data.short_rates import (
ShortRateDataset,
build_duan_weekly_dataset,
build_kim_orphanides_dataset,
build_macro_finance_dataset,
build_policy_rule_dataset,
)
from .data.universe import EntityMetadata, Universe
from .features.frame import Artifact, FeatureFrame
from .features.ops import join_feature_frames, materialize
Expand Down Expand Up @@ -92,6 +92,7 @@
)
from .pit.transforms import PITTransformResult, PITTransformSpec
from .pit.validation import PITValidationReport, validate_pit_observations
from .registry import EntityEntry, EntityRegistry
from .store.cache import MaterializationPolicy
from .store.duckdb_parquet import DuckDBParquetStore
from .time.align import AlignedPanel, AlignSpec, AvailabilityState, align_panel
Expand Down Expand Up @@ -206,4 +207,6 @@
"build_snapshot_tape",
"make_ref_entity_id",
"parse_ref_entity_id",
"EntityEntry",
"EntityRegistry",
]
27 changes: 27 additions & 0 deletions alphaforge/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Generic configuration resolution utilities."""
from __future__ import annotations

import os
from dataclasses import dataclass


def resolve_config_value(
explicit: str | None,
env_var: str,
default: str,
) -> str:
"""Resolve from explicit → env → default."""
return explicit or os.environ.get(env_var, default)


@dataclass(frozen=True)
class ConfigEntry:
"""A single resolvable configuration value."""

name: str
env_var: str
default: str
description: str = ""

def resolve(self, explicit: str | None = None) -> str:
return resolve_config_value(explicit, self.env_var, self.default)
27 changes: 27 additions & 0 deletions alphaforge/data/public_web/cftc_cot.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,40 @@
"13874A": "sp500_e_mini",
"33874E": "sp500_micro",
"209742": "vix", # VIX futures (alternative code)
# G10 FX futures (CME)
"099741": "eur", # Euro FX
"096742": "gbp", # British Pound
"097741": "jpy", # Japanese Yen
"092741": "chf", # Swiss Franc
"090741": "cad", # Canadian Dollar
"232741": "aud", # Australian Dollar
"112741": "nzd", # New Zealand Dollar
"095741": "mxn", # Mexican Peso (not G10 but heavily traded)
"089741": "sek", # Swedish Krona
"088741": "nok", # Norwegian Krone
# US rates futures
"13874P": "sofr_3m", # Three-Month SOFR (CME)
"134741": "ust_10y", # 10-Year T-Note
"020601": "ust_30y", # T-Bond (30Y)
"044601": "ust_5y", # 5-Year T-Note
"042601": "ust_2y", # 2-Year T-Note
"043602": "fed_funds", # 30-Day Federal Funds
}

# Regex fallbacks for market-name-based contract detection.
_MARKET_NAME_PATTERNS: list[tuple[re.Pattern[str], str]] = [
(re.compile(r"\bVIX\b", re.IGNORECASE), "vix"),
(re.compile(r"\bCBOE VOLATILITY INDEX\b", re.IGNORECASE), "vix"),
(re.compile(r"\bS&P 500\b", re.IGNORECASE), "sp500"),
(re.compile(r"\bEURO FX\b", re.IGNORECASE), "eur"),
(re.compile(r"\bBRITISH POUND\b", re.IGNORECASE), "gbp"),
(re.compile(r"\bJAPANESE YEN\b", re.IGNORECASE), "jpy"),
(re.compile(r"\bSWISS FRANC\b", re.IGNORECASE), "chf"),
(re.compile(r"\bCANADIAN DOLLAR\b", re.IGNORECASE), "cad"),
(re.compile(r"\bAUSTRALIAN DOLLAR\b", re.IGNORECASE), "aud"),
(re.compile(r"\bNEW ZEALAND DOLLAR\b|\bNZ DOLLAR\b", re.IGNORECASE), "nzd"),
(re.compile(r"\bSOFR\b", re.IGNORECASE), "sofr_3m"),
(re.compile(r"\b10.YEAR\b.*\bT.NOTE\b", re.IGNORECASE), "ust_10y"),
]


Expand Down
4 changes: 2 additions & 2 deletions alphaforge/data/short_rates.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Mapping
from typing import Any, Mapping

import pandas as pd

Expand Down Expand Up @@ -105,7 +105,7 @@ def _fetch_fred_panel(
ctx: DataContext,
*,
source: str,
series_map: Mapping[object, str],
series_map: Mapping[Any, str],
start: pd.Timestamp,
end: pd.Timestamp,
sort_labels: bool = True,
Expand Down
48 changes: 48 additions & 0 deletions alphaforge/evaluation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Evaluation primitives — metric protocol and standard implementations.

This package provides the foundational building blocks for forecast
evaluation. It is intentionally generic (not specific to nowcasting or
PIT data) so that downstream libraries like ``nowcast-data`` can compose
these primitives into domain-specific evaluation pipelines.

Key components:

- :class:`MetricFn` — a ``Protocol`` that any accuracy metric must satisfy.
- Five built-in metric classes: :class:`RMSE`, :class:`MAE`,
:class:`DirectionalAccuracy`, :class:`MAPE`, :class:`MeanError`.
- Two pre-built suites: :data:`DEFAULT_METRICS` (RMSE + MAE + DA) and
:data:`BENCHMARK_METRICS` (adds MeanError + MAPE).

Downstream usage (nowcast-data)::

from alphaforge.evaluation.metrics import BENCHMARK_METRICS
from nowcast_data.models.evaluation import benchmark_evaluation_suite

results = benchmark_evaluation_suite(
predictions,
truth_definitions={"advance": ("y_true_release_1", 1)},
metrics=list(BENCHMARK_METRICS),
)
"""

from .metrics import (
BENCHMARK_METRICS,
DEFAULT_METRICS,
MAE,
MAPE,
RMSE,
DirectionalAccuracy,
MeanError,
MetricFn,
)

__all__ = [
"MetricFn",
"RMSE",
"MAE",
"DirectionalAccuracy",
"MAPE",
"MeanError",
"DEFAULT_METRICS",
"BENCHMARK_METRICS",
]
Loading
Loading