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.

Next