AlphaModel
Seven-factor IC-weighted edge estimation
AlphaModel replaces naive edge assumptions (e.g. “assume 0.05 × fitness”) with factor-based self-calibrating estimation. Seven prediction-market factors are computed per tick, their historical information coefficient (IC) is tracked against realized outcomes, and the composite alpha is a weighted sum where weights come from IC.
Import
python
from horizon.fund._alpha_model import (
AlphaModel,
AlphaEstimate,
FactorValue,
FactorIC,
)
The seven factors
liquidity `tanh(volume_24h / median_volume - 1)`: normalized volume ratio vs. the market's own history.
momentum Recent log-return over a short window, normalized to `[-1, +1]` via tanh.
mean_reversion Distance from the 0.5 midpoint for binary prediction markets, signed by the implied direction.
event_proximity Inverse days-to-resolution. Closer resolution → higher factor value → time-decay pricing gets more aggressive.
spread Current bid-ask spread vs. historical median spread. Tight spreads → liquid → trustworthy factor.
cross_market Cross-exchange price divergence (e.g., Polymarket vs Kalshi for the same event).
entropy Shannon entropy of the current price distribution. captures uncertainty / regime change.
How IC weighting works
Compute factor values
For each market on each tick, compute all seven factors. Values are normalized to
[-1, +1].Record predictions
Each factor's value is appended to a rolling deque (default lookback: 100).
Record outcomes
When the market resolves (or a short-horizon outcome is known), append to the outcomes deque.
Compute per-factor IC
information_coefficient(factor_predictions, outcomes) computes the Spearman rank correlation per factor. Factors with IC > threshold are considered significant.Weight by IC
Significant factors get weights proportional to their IC. Non-significant factors get a small floor weight. The weights are normalized to sum to 1.
Combine
Composite alpha = Σ (weight × factor_value). Confidence is a function of the number of observations and the information ratio (IC mean / IC std).
API
python
class AlphaModel:
def __init__(
self,
lookback: int = 100,
min_ic_observations: int = 20,
) -> None:
...
def estimate_alpha(
self,
market_id: str,
market_data: dict,
) -> AlphaEstimate:
"""Compute composite alpha for a market."""
def record_outcome(
self,
market_id: str,
outcome: float,
) -> None:
"""Record a realized outcome for IC recalculation."""
def get_factor_ics(self) -> dict[str, FactorIC]:
"""Current IC statistics for all factors."""
def get_factor_weights(self) -> dict[str, float]:
"""Current IC-proportional weights."""
Result types
python
@dataclass(frozen=True)
class FactorValue:
name: str
value: float # normalized [-1, +1]
raw_value: float
timestamp: float
@dataclass(frozen=True)
class FactorIC:
name: str
ic: float
ic_ir: float # mean IC / std IC
n_observations: int
is_significant: bool
@dataclass(frozen=True)
class AlphaEstimate:
market_id: str
composite_alpha: float # [-1, +1]
factor_values: list[FactorValue]
confidence: float # [0, 1]
Usage
python
from horizon.fund._alpha_model import AlphaModel
model = AlphaModel(lookback=100, min_ic_observations=20)
# For each market snapshot, compute alpha
market_data = {
"volume_24h": 500_000,
"median_volume": 200_000,
"recent_return": 0.015,
"price": 0.65,
"days_to_expiry": 14,
"spread": 0.02,
"median_spread": 0.015,
"cross_market_divergence": 0.01,
"entropy": 0.7,
}
estimate = model.estimate_alpha("polymarket:event-xyz", market_data)
print(f"Alpha: {estimate.composite_alpha:+.3f}")
print(f"Confidence: {estimate.confidence:.3f}")
for factor in estimate.factor_values:
print(f" {factor.name}: {factor.value:+.3f}")
# Later, when the market resolves
model.record_outcome("polymarket:event-xyz", outcome=1.0) # YES
# Check current IC-based weights
print(model.get_factor_weights())
Wrapping into a Horizon strategy
You can wrap AlphaModel as a custom Strategy that emits Horizon-style signals:
python
from horizon.fund._alpha_model import AlphaModel
from horizon import Strategy, Signal, Direction
from horizon.asset_classes import Equity
class AlphaModelStrategy(Strategy):
asset_classes = [Equity]
features = {}
def __init__(self):
self.model = AlphaModel(lookback=100)
def evaluate(self, f, universe):
signals = []
for m in universe:
market_data = self._build_market_data(m)
estimate = self.model.estimate_alpha(m.id, market_data)
if abs(estimate.composite_alpha) > 0.1:
signals.append(Signal(
market_id=m.id,
direction=(
Direction.Increase if estimate.composite_alpha > 0
else Direction.Decrease
),
confidence=estimate.confidence,
expected_edge_bps=abs(estimate.composite_alpha) * 1000,
expected_expected_vol_bps=2000,
horizon=timedelta(days=7),
reason=f"alpha={estimate.composite_alpha:+.3f}",
features={f.name: f.value for f in estimate.factor_values},
))
return signals
def _build_market_data(self, market):
# Pull volume, price, spread etc from your feed manager
...
When to use
Pitfalls
Source
python/horizon/fund/_alpha_model.py. ~400 lines. Uses horizon._horizon.information_coefficient (Rust-backed) for fast rolling IC computation.