NovaMarket
← All strategies

Probability mean-reversion

PolymarketEventEvent marketHigher risk

fade over-reactions in logit space (buy NO when over-priced, YES when under), flat near resolution

Track record

Return
+15.4%
Sharpe
1.84
Max DD
4.8%
AUM
$0
Created
2026-07-12
Investors
0
Pools
0
Settled days
0

Market fit

EventBets on a specific outcome (e.g. BTC price by year-end)
  • When your view of the odds differs from the market's pricing
  • Liquidity thins near resolution; binary outcomes can go to zero
Not sure where the market is headed? Browse market-neutral strategies →

Backtest (deterministic simulator)

Parameters: window / k / size

Binary prediction-market simulation (YES/NO, settles YES after 240 steps) — not a promise of future returns.

"""概率均值回归(Probability mean-reversion)—— logit 空间的 z-score 反向下注。

思路:事件概率(YES 价格)常在短期过度反应。把 YES 价格映射到 logit(log-odds)空间计算滚动 z-score:
概率被显著高估(z ≥ +k)时买入 NO(等价于看空 YES,因 token 不能做空)、被显著低估(z ≤ -k)时买入
YES,回归(|z| 收敛)后两腿平仓。临近结算的窗口内停止加仓——此时结算跳变主导,均值回归假设失效。

适用性:instrument="event"、venues=["POLYMARKET"]。做空由"买对侧 token"实现。
"""
from __future__ import annotations

from ..base import StrategyBase
from ..context import StrategyContext
from ..indicators import logit, zscore
from ..registry import register


@register("概率均值回归")
class PmProbMeanRev(StrategyBase):
    description = "事件概率在 logit 空间偏离滚动均值时反向下注(高估买 NO、低估买 YES),回归平仓。"
    params = {"window": 30, "k": 1.2, "size": 15.0}
    venues = ["POLYMARKET"]
    symbols: list = []
    instrument = "event"

    def __init__(self, window: int = 30, k: float = 1.2, size: float = 15.0) -> None:
        self.window = int(window)
        self.k = float(k)
        self.size = float(size)

    async def on_tick(self, ctx: StrategyContext) -> None:
        sym = ctx.conn_symbol()
        no = ctx.complement_token(sym)
        hist = await ctx.history(sym, self.window + 1)
        if len(hist) < self.window:
            return
        z = zscore([logit(p) for p in hist], self.window)
        if z is None:
            return
        band = self.size * 0.15

        # 临近结算:停止均值回归,平掉两腿(结算跳变主导)
        ttr = ctx.time_to_resolution()
        if ttr is not None and ttr < self.window:
            await ctx.target(sym, 0.0, band=band)
            if no is not None:
                await ctx.target(no, 0.0, band=band)
            return

        if z >= self.k:  # 概率高估 → 买 NO 看空
            await ctx.target(sym, 0.0, band=band)
            if no is not None:
                await ctx.target(no, self.size, band=band)
        elif z <= -self.k:  # 概率低估 → 买 YES
            if no is not None:
                await ctx.target(no, 0.0, band=band)
            await ctx.target(sym, self.size, band=band)
        elif abs(z) < 0.3:  # 回归 → 平两腿
            await ctx.target(sym, 0.0, band=band)
            if no is not None:
                await ctx.target(no, 0.0, band=band)

The full SDK and all strategies are MIT-licensed open source — backtest, paper-trade, or fork them directly.

Pools running this strategy

No pools are running this strategy yet — be the first to launch one.