基于主成分分析的市场时机策略

登录后收藏

学术论文

作者尽管有交易成本,仍然是一种盈利的交易和风险管理策略 [点击查看论文]

策略概要

该策略使用168只大型S&P 500股票,并通过100天的滚动窗口进行主成分分析(PCA),计算相关矩阵的最大特征值。如果特征值超过A百分位数或低于B百分位数的历史值(例如,35%-77%),投资者将投资于无风险资产。否则,投资者会计算每只股票的平均收益、标准差、偏度和峰度,并将这些指标在所有股票中进行平均,确定其百分位分区。通过匹配状态向量的历史数据,投资者决定:如果平均收益/方差 > 1,则做多;如果 < -1,则做空;如果没有匹配,则持有现金。

II. 策略合理性

PCA方法使投资者能够提取股票价格变动的前几个重要决定因素。这些决定因素用于表征当前市场的状态。然后,基于历史市场在当前状态下的发展,估算未来的市场回报。

入场与出场

入场

每月由 make_on_day 决定目标权重。当前宇宙:SPY, EFA, EEM, VNQ, DBC, GLD, TLT, IEF, HYG。请对照实验室代码中的 engine.set_target_weights。

出场

权重被设为空或该标的权重为 0 即视为出场。引擎按 5 bps 佣金 + 2 bps 滑点执行。

所需行情数据

需要 SPY, EFA, EEM, VNQ, DBC, GLD (+3 more) 至少 60 根复权收盘价,才能形成第一个有效信号。ETF 仅交易日有行情。 实验室通过 backtest.data.load_daily_prices 读取 Yahoo Finance。

标的

SPY, EFA, EEM, VNQ, DBC, GLD, TLT, IEF, HYG

频率

每日 · 日频复权收盘价;信号按月再平衡(用当月最后一个有效交易日)

所需历史

每个标的至少 60 根交易日 K 线(约 3 个交易月),外加数根缓冲才能发出第一个信号。

字段

  • 复权收盘价(Adj Close / auto_adjust Close)
  • 交易日日期索引

凭证

  • 回测与实验室:无需密钥
  • 实盘下单才需要券商 / 交易所 API

API 与数据源

Quant Buffet 数据 API

实验室用 load_daily_prices 拉取 ASSETS 的复权收盘价面板,磁盘缓存后回测可复现。

提供方
backtest.data.load_daily_prices
鉴权
回测无需密钥
接口
load_daily_prices(ASSETS, start="2000-01-01")
API / docs → /zh/docs/data-api

Yahoo Finance(yfinance)

美股 / ETF 复权 OHLCV,免费研究接口,有速率限制。

提供方
yfinance → Yahoo Finance
鉴权
公开历史无需密钥
接口
Ticker.history / yf.download(auto_adjust=True)
API / docs → github.com/ranaroussi/yfinance

Onsite backtest IDE

Quant Buffet 原生回测 IDE

Edit and run Quant Buffet Python for 基于主成分分析的市场时机策略 in the browser. Results update live with equity, drawdown, and metrics charts. Allowed: backtest.data, backtest.engine, backtest.metrics, numpy, pandas. Define ASSETS and make_on_day(prices). Shortcut: Ctrl+Enter. API docs →

Ready — edit code, then Run backtest.
IDE · 43 lines
Quant Buffet syntax cheat sheet (copy / insert)

Paste these fragments into the editor. The sandbox rejects QuantConnect, os, and network libraries.

Required imports
Only these libraries are allowed in the sandbox.
from __future__ import annotations

import numpy as np
import pandas as pd

from backtest.data import load_daily_prices
from backtest.engine import EngineConfig, PortfolioEngine
from backtest.metrics import compute_metrics
ASSETS list (whitelisted ETFs)
Module-level list. Tickers must be in the Quant Buffet whitelist.
ASSETS = ["SPY", "QQQ", "TLT", "GLD", "BIL"]
make_on_day contract
Must return (on_day, ready). on_day calls engine.set_target_weights.
def make_on_day(prices: pd.DataFrame):
    cols = [c for c in ASSETS if c in prices.columns]
    sma = prices[cols].rolling(200, min_periods=200).mean()
    state = {"last": None}

    def on_day(engine: PortfolioEngine, dt: pd.Timestamp) -> None:
        if sma.loc[dt].isna().all():
            return
        key = (dt.year, dt.month)
        if state["last"] == key:
            return
        state["last"] = key
        long = [
            s for s in cols
            if pd.notna(prices.at[dt, s]) and pd.notna(sma.at[dt, s])
            and prices.at[dt, s] > sma.at[dt, s]
        ]
        weights = {} if not long else {s: 1.0 / len(long) for s in long}
        engine.set_target_weights(dt, weights)

    ready = sma.dropna(how="all").index.min() if sma.notna().any().any() else None
    return on_day, ready
Set target weights
Weights should sum to about 1.0. Empty dict = 100% cash.
engine.set_target_weights(dt, {"SPY": 0.60, "BIL": 0.40})

Live backtest performance

CAGR
8.16%
Sharpe
0.75
Max DD
-37.01%
Vol
11.33%
Sortino
1.17
Beta
0.51

Run the backtest to populate charts.

Order records

Run the backtest to load every order fill alongside performance.

Export to your platform

Transform Quant Buffet lab code (ASSETS + make_on_day / PortfolioEngine) into native classes for a third-party IDE — then copy and paste.

Target platform

Run in: QuantConnect Cloud or LEAN CLI · QCAlgorithm with Equity securities and monthly rebalance.

Detected pattern: Custom / hybridAssets: SPY, EFA, EEM, VNQ, DBC, GLD, TLT, IEF, HYG
# Generated from Quant Buffet → QuantConnect LEAN
# Strategy: 基于主成分分析的市场时机策略
# Detected pattern: Custom / hybrid
# Source uses Quant Buffet lab APIs (ASSETS + make_on_day / PortfolioEngine).
# Review fees, data, and risk before live trading — educational export only.

from AlgorithmImports import *


class QuantBuffetExport(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2010, 1, 1)
        self.SetCash(100000)
        tickers = ["SPY", "EFA", "EEM", "VNQ", "DBC", "GLD", "TLT", "IEF", "HYG"]
        self.symbols = []
        for t in tickers:
            if "-" in t:  # crypto proxy e.g. BTC-USD
                self.symbols.append(self.AddCrypto(t.replace("-USD", ""), Resolution.Daily).Symbol)
            else:
                self.symbols.append(self.AddEquity(t, Resolution.Daily).Symbol)
        self.Schedule.On(
            self.DateRules.MonthStart(self.symbols[0]),
            self.TimeRules.AfterMarketOpen(self.symbols[0], 30),
            self.Rebalance,
        )
        # Logic: Custom Quant Buffet logic — adapt the signal block to match your lab on_day().

    def Rebalance(self):
        # Pattern: custom — Custom Quant Buffet logic — adapt the signal block to match your lab on_day().
        # Default: equal-weight. Port your make_on_day weights here via SetHoldings.
        w = 1.0 / len(self.symbols) if self.symbols else 0.0
        for symbol in self.symbols:
            self.SetHoldings(symbol, w)

导出代码使用目标平台的原生类与库。请在第三方 IDE 中安装依赖后运行;实盘前请自行验证。