NovaMarket
← All strategies

Statistical arbitrage

HyperliquidMarket-neutralPerpetuals (leverage/short)Medium risk

mean-revert a cointegrated pair on z-score dislocation

Track record

Return
+5.6%
Sharpe
2.03
Max DD
1.4%
AUM
$0
Created
2026-07-06
Investors
0
Pools
0
Settled days
0

Market fit

Market-neutralNo directional bet — harvests spreads and funding
  • Runs in any market; steadier but smaller returns
  • Spreads and funding can blow out in extreme conditions

Backtest (deterministic simulator)

Parameters: window / k / size

Backtest curve is an example on a deterministic simulated price path — not real returns.

"""统计套利(Statistical arbitrage)—— 配对比价 z-score 均值回归。

思路:对一组相关资产(如 ETH 与其配对腿)计算比价序列的 z-score:主腿相对配对腿显著便宜(z ≤ -k)
做多主腿、显著偏贵(z ≥ +k)做空主腿,比价回归(|z| 收敛)后平仓。经典 pairs trading 的单腿化简:
配对腿仅作信号、不下单,避免单 connector 下的双腿撮合复杂度,同时保留统计套利的核心信号结构。
参数:window(z-score 窗口)、k(进出场偏离倍数)、size(目标数量)。

降级行为:feed 未提供配对行情(ctx.pair_symbol() 为 None)时保持空仓——拒绝退化成裸方向敞口;
连接器不支持做空时只做多腿(z ≤ -k 进、回归出)。
"""
from __future__ import annotations

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


@register("统计套利")
class StatArb(StrategyBase):
    description = "配对比价 z-score 偏离入场、回归平仓(配对腿作信号,主腿交易)。"
    params = {"window": 40, "k": 1.5, "size": 4.0}

    def __init__(self, window: int = 40, k: float = 1.5, size: float = 4.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()
        pair = ctx.pair_symbol()
        if pair is None:
            return  # 无配对行情:不建仓
        n = self.window + 1
        a = await ctx.history(sym, n)
        b = await ctx.history(pair, n)
        m = min(len(a), len(b))
        if m < self.window:
            return
        ratio = [x / y for x, y in zip(a[-m:], b[-m:]) if y]
        z = zscore(ratio, self.window)
        if z is None:
            return
        allow_short = bool(getattr(ctx.conn, "allow_short", True))
        band = self.size * 0.1
        if z <= -self.k:
            await ctx.target(sym, self.size, band=band)       # 主腿便宜 → 做多
        elif z >= self.k:
            await ctx.target(sym, -self.size if allow_short else 0.0, band=band)
        elif abs(z) < 0.3:
            await ctx.target(sym, 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.