Quant Buffet放轻松,别过度思虑

小盘股效应的时机选择 第3版

登录后收藏

学术论文

Realized Semibetas: Signs of Things to Come

作者Realized Semibetas: Signs of Things to Come [点击查看论文]

机构
  • Duke University
  • National Bureau of Economic Research
  • ?Duke University - Department of Economics
  • ?Duke University - Finance
  • ?National Bureau of Economic Research (NBER)
  • DEEuropean Central Bank
  • ?European Central Bank (ECB)

策略概要

投资范围包括小盘股和大盘股。该投资组合可以通过投资ETF(做多小盘股,做空大盘股)或直接投资小盘股和大盘股来构建。高风险月份被定义为预期市场波动率与历史波动率相比位于最高五分之一的月份。在这种月份之后,投资者做多小盘股,做空大盘股,并持有该投资组合6个月。每月检查基于月度波动率相对于历史波动率的择时指标,以相应地调整投资组合。

II. 策略合理性

股票规模溢价存在正向的风险回报关系,这归因于高风险时期,在这些时期,小盘股面临相对较高的市场波动率、违约和流动性风险。时变的SMB溢价似乎可以为评估股票市场中的跨期风险回报权衡提供有用的依据。

回测表现

波动率7.81%
夏普比率0.69
索提诺比率-0.095
胜率52%

完整 Python 代码

import numpy as np
from AlgorithmImports import *

class TimingtheSmallCapEffect(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)

self.period = 21
self.SetWarmUp(self.period, Resolution.DAILY)

self.market = self.AddEquity('SPY', Resolution.Daily).Symbol
self.data = RollingWindow[float](self.period)   # spy history
self.historical_volatility = []
self.min_vol_history_period = 12
self.was_high_risk_month = False

self.trade_month_count = 0

data = self.AddEquity("DIA", Resolution.Daily)
data.SetLeverage(5)
self.large_cap = data.Symbol

data = self.AddEquity("IWM", Resolution.Daily)
data.SetLeverage(5)
self.small_cap = data.Symbol

self.Schedule.On(self.DateRules.MonthEnd(self.market), self.TimeRules.BeforeMarketClose(self.market), self.Rebalance)

def OnData(self, data):
# store market prices
if self.market in data and data[self.market]:
    price = data[self.market].Value
    self.data.Add(price)

def Rebalance(self):
if self.IsWarmingUp: return
if not self.data.IsReady: return

if self.time.year == 2023 and self.time.month == 8:
    foo=3

self.trade_month_count += 1
if self.trade_month_count == 6:
    self.trade_month_count = 0
    self.Liquidate()

if self.was_high_risk_month:
    self.was_high_risk_month = False
    self.trade_month_count = 0

    # One month after high risk month.
    self.SetHoldings(self.small_cap, 1)
    self.SetHoldings(self.large_cap, -1)            

market_prices = np.array([x for x in self.data])
market_returns = market_prices[:-1] / market_prices[1:] - 1
market_volatility = np.std(market_returns) * np.sqrt(252)

self.historical_volatility.append(market_volatility)
if len(self.historical_volatility) >= self.min_vol_history_period:
    top_quintile = np.percentile(self.historical_volatility[1:], 80)
    
    if market_volatility > top_quintile:
        # one month lag
        self.was_high_risk_month = True