NovaMarket
← All strategies

Momentum

HyperliquidTrendingPerpetuals (leverage/short)Higher risk

ride established trends with breakout entries and trailing exits

Track record

Return
+17.1%
Sharpe
2.42
Max DD
2.4%
AUM
$0
Created
2026-07-06
Investors
0
Pools
0
Settled days
0

Market fit

TrendingOne-directional moves that keep going
  • Shines when the market has a clear direction and breakouts follow through
  • Gets chopped up by whipsaws and false breakouts in sideways markets
Not sure where the market is headed? Browse market-neutral strategies →

Backtest (deterministic simulator)

Parameters: lookback / breakout / size

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

"""动量(Momentum)—— Donchian 通道突破 + 移动止损。

思路:价格突破近 lookback 期高点(再加 breakout 缓冲)说明趋势已确立,顺势入场;入场后记录最高价,
回撤超过 3×breakout 移动止损离场。源自海龟交易法则(Donchian channel breakout)这一最经典的开源
动量范式(各开源量化系统均有同型实现;此处为独立重写)。
参数:lookback(通道周期)、breakout(突破缓冲,比例)、size(目标数量)。
适用:单边趋势行情;震荡市会被假突破反复止损,靠移动止损限制单次亏损。
"""
from __future__ import annotations

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


@register("动量")
class Momentum(StrategyBase):
    description = "Donchian 通道突破入场、移动止损离场:跟随已确立趋势。"
    params = {"lookback": 40, "breakout": 0.01, "size": 5.0}

    def __init__(self, lookback: int = 40, breakout: float = 0.01, size: float = 5.0) -> None:
        self.lookback = int(lookback)
        self.breakout = float(breakout)
        self.size = float(size)
        self._peak: float | None = None  # 入场以来最高价(移动止损参考)

    async def on_tick(self, ctx: StrategyContext) -> None:
        sym = ctx.conn_symbol()
        hist = await ctx.history(sym, self.lookback + 1)
        if len(hist) < self.lookback + 1:
            return
        px = hist[-1]
        prior_high = max(hist[:-1])
        pos = await ctx.position(sym)
        band = self.size * 0.1
        if pos <= band:
            self._peak = None
            if px > prior_high * (1.0 + self.breakout):
                await ctx.target(sym, self.size, band=band)
                self._peak = px
        else:
            self._peak = max(self._peak or px, px)
            if px < self._peak * (1.0 - 3.0 * self.breakout):
                await ctx.target(sym, 0.0, band=band)
                self._peak = None

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.