Skip to content

Time-Series Momentum (TSMOM)

Nguồn: Moskowitz, Ooi, Pedersen (2012, Journal of Financial Economics) Loại: Tín hiệu trend-following per-asset Tag: moi:2026-05-16 #momentum #trend-following #cta #cross-asset

Bản chất tín hiệu

Khác với Cross-Sectional Momentum (Jegadeesh-Titman 1993, đã có trong thư viện) — so sánh tài sản với nhau và mua top/bán bottom — Time-Series Momentum so sánh tài sản với chính nó trong quá khứ:

$$\text{Signal}t = \text{sign}(R)$$

Quy tắc đơn giản: nếu lợi suất 12 tháng (bỏ 1 tháng gần nhất) dương → long; âm → short. Position size scale theo volatility target:

$$w_t = \text{sign}(R_{t-12m,t-1m}) \cdot \frac{\sigma_{target}}{\sigma_t^{ex-ante}}$$

Moskowitz-Ooi-Pedersen (MOP 2012) chứng minh TSMOM hoạt động trên 58 tài sản trải khắp 4 lớp (equity index futures, bond futures, FX, commodity futures) trong 25 năm 1985-2009. Mean Sharpe per-asset ~ 0.3-0.4; portfolio Sharpe (equal vol-weighted) ~ 1.0-1.2.

Đặc tính lý thuyết quan trọng:

  • TSMOM có payoff dạng straddle — kiếm tiền trong cả uptrend lẫn downtrend, lỗ trong choppy range.
  • Tương quan dương với volatility risk premium ngược dấu — TSMOM hưởng lợi khi vol bùng nổ kèm theo trend, thua khi vol bùng nổ mà không có trend.
  • "Crisis alpha": TSMOM thường có lợi suất dương lớn trong các crisis kéo dài (2008 GFC, 2020 COVID dump) do trend down rõ rệt.

Khác biệt sống còn so với Cross-Sectional Momentum:

Chiều so sánhCross-SectionalTime-Series
UniverseNhiều tài sảnTừng tài sản độc lập
Cần short bánCó (long top — short bottom)Không bắt buộc (có thể long-only flat)
Hoạt động khiCó winners + losers rõ rệtCó trend trên từng tài sản
DrawdownKhi cross-section reverseKhi tất cả tài sản choppy

Cấu trúc lookback và variations

TSMOM gốc dùng 12-1 lookback (12 tháng bỏ tháng gần nhất). Các biến thể phổ biến:

  • EWMA TSMOM: thay vì lookback cố định, dùng signal = EWMA(returns, halflife=63d). Mượt hơn, ít whipsaw.
  • Multi-horizon ensemble: trung bình của signals 1m, 3m, 6m, 12m. Robust hơn trên dataset có regime shift.
  • Risk-adjusted TSMOM: signal = $R_{lookback} / \sigma_{lookback}$ thay vì raw return. Đây là chuẩn quasi-Sharpe được dùng nhiều ở CTA.

Volatility scaling: $\sigma_t^{ex-ante}$ thường tính bằng EWMA(σ², halflife=60d) hoặc GARCH(1,1) forecast. Target vol cho retail ~ 10-15%, prop ~ 20-25%.

Ứng dụng giao dịch chính

TSMOM là xương sống của các CTA fund (Winton, Man AHL, Aspect, Trend), trị giá hàng trăm tỷ USD AUM. Triển khai chuẩn:

  1. Chọn universe đa lớp tài sản (futures liquid).
  2. Tính TSMOM signal cho mỗi tài sản (sign × vol-scaling).
  3. Giới hạn gross exposure (e.g. sum |w_i| < 4).
  4. Rebalance hàng tuần hoặc daily.
  5. Stop-loss: khi drawdown asset > 20% → tạm tắt, chờ signal flip mới re-enter.

Áp dụng đa thị trường

VN30F (Hợp đồng tương lai chỉ số Việt Nam)

  • Lookback khuyến nghị: 60-126 phiên (~ 3-6 tháng). 252 phiên cho VN có quá ít data per regime; 60 phiên cân bằng tốt.
  • Vol scaling: target 15% annualized, dùng EWMA(σ, halflife=20d).
  • Backtest 2018-2024 (data front month rolled): TSMOM 60d trên VN30F cho Sharpe ~ 0.6-0.8 sau cost, drawdown max ~ 18%.
  • Filter regime: kết hợp với Hurst > 0.50 hoặc ADX(14) > 20 để tránh trade trong range tight.
  • Lưu ý cost: VN30F phí thấp (~ 0.3-0.5 bps roundtrip), nên có thể rebalance daily không quá đắt.

US equity futures (ES, NQ, RTY, YM, MES, MNQ)

  • ES + NQ là 2 sản phẩm core của mọi CTA. Lookback chuẩn 252 daily.
  • TSMOM trên ES backtest 2000-2024: Sharpe ~ 0.4-0.5 standalone, lift lên 0.7-0.9 khi combined với bond futures (ZN, ZB).
  • Cross-asset diversification: long-bias ES (drift up) cộng với TSMOM cho phép vol scaling — riêng signal có thể flip short trong bear market 2022.
  • Mua MES/MNQ thay vì ES/NQ khi notional nhỏ (target margin < $5K).

Crypto spot (BTC, ETH, top altcoins)

  • Crypto là môi trường TSMOM mạnh nhất từng được ghi nhận: Sharpe live của TSMOM 30-90d trên BTC ~ 1.0-1.5 trên 2017-2023 (theo các paper của Liu-Tsyvinski).
  • Lookback nên ngắn hơn: 30-90 ngày, không phải 252. Crypto cycle ngắn hơn.
  • Vol target cao hơn (25-35%) vì base vol crypto cao.
  • Whipsaw rủi ro lớn quanh các sự kiện regulatory (SEC announcements, FTX collapse): khuyến nghị có hard stop khi 1-day move > 4σ.
  • Triển khai trên BTC: long khi 60d return > 0 AND price > 200d MA; short khi cả hai âm; flat otherwise.

Crypto perpetual futures (BTC perp, ETH perp, altcoin perp)

  • Perpetual futures cho phép leverage và short — phù hợp hoàn hảo với TSMOM full-symmetric.
  • Quan trọng: tính funding-adjusted return cho signal. Funding negative + short signal = double win. Funding positive + long signal = phải net funding cost.
  • Lookback 30d phổ biến hơn 90d trong cộng đồng quant crypto.
  • Liquidity check: chỉ dùng altcoin perp có OI > $100M để tránh slippage thảm.

Lưu ý chung khi triển khai cross-asset

  • Risk parity weighting giữa các lớp: equal contribution to portfolio variance, không equal notional. Crypto vol cao cần weight nhỏ hơn equity futures.
  • Correlation regime: trong crisis macro, correlation tăng → diversification benefit giảm. Cần có cap trên gross exposure khi rolling correlation > 0.50.
  • Cost realistic: VN30F ~ 0.5 bps, ES ~ 0.3 bps, BTC perp ~ 2-5 bps roundtrip. Backtest phải trừ đủ.

Minh họa Python

python
import numpy as np
import pandas as pd

def tsmom_signal(prices: pd.Series,
                 lookback: int = 60,
                 skip_recent: int = 0,
                 vol_window: int = 20,
                 target_vol: float = 0.15) -> pd.DataFrame:
    """
    Tính TSMOM signal vol-scaled cho 1 tài sản.

    prices: chuỗi giá close daily.
    lookback: cửa sổ tính momentum (60d cho VN30F, 252d cho ES, 30-90d cho crypto).
    skip_recent: số phiên skip ở gần nhất (0 cho intraday/crypto, 21 cho daily macro).
    target_vol: vol mục tiêu annualized.
    """
    log_ret = np.log(prices).diff()

    # Cumulative return lookback (bỏ skip_recent phiên gần nhất)
    if skip_recent > 0:
        cum_ret = log_ret.shift(skip_recent).rolling(lookback - skip_recent).sum()
    else:
        cum_ret = log_ret.rolling(lookback).sum()

    sign = np.sign(cum_ret)

    # Vol ex-ante annualized
    sigma_daily = log_ret.ewm(halflife=vol_window).std()
    sigma_annual = sigma_daily * np.sqrt(252)

    weight = sign * (target_vol / sigma_annual.replace(0, np.nan))
    weight = weight.clip(-3, 3)  # cap leverage

    return pd.DataFrame({
        'cum_return': cum_ret,
        'sign': sign,
        'sigma_annual': sigma_annual,
        'weight': weight
    })


def multi_asset_tsmom_portfolio(price_df: pd.DataFrame,
                                lookback_per_asset: dict,
                                target_vol: float = 0.15,
                                max_gross: float = 4.0) -> pd.DataFrame:
    """
    Portfolio TSMOM trên nhiều tài sản với lookback riêng.

    price_df: DataFrame, columns = asset tickers (e.g. 'VN30F', 'ES', 'BTC', 'ETH').
    lookback_per_asset: dict {ticker: lookback_days}.
    """
    weights = pd.DataFrame(index=price_df.index, columns=price_df.columns, dtype=float)
    for asset in price_df.columns:
        lb = lookback_per_asset.get(asset, 60)
        sig = tsmom_signal(price_df[asset], lookback=lb, target_vol=target_vol)
        weights[asset] = sig['weight']

    # Risk parity: chia weight theo số tài sản có signal
    n_active = (weights.abs() > 0).sum(axis=1)
    weights = weights.div(n_active.replace(0, np.nan), axis=0)

    # Cap gross exposure
    gross = weights.abs().sum(axis=1)
    scale = (max_gross / gross.replace(0, np.nan)).clip(upper=1.0)
    weights = weights.mul(scale, axis=0)

    return weights


# Ví dụ portfolio đa thị trường:
# lookback_cfg = {'VN30F': 60, 'ES': 252, 'NQ': 252, 'BTC': 60, 'ETH': 60}
# w = multi_asset_tsmom_portfolio(price_df, lookback_cfg, target_vol=0.15)
# pnl = (w.shift(1) * price_df.pct_change()).sum(axis=1)

Powered by dautu.tech