Factor Timing Strategy¶
Dynamically adjust factor weights based on market conditions.
Strategy Overview¶
Different factors work in different environments: - Momentum: Strong in trending markets - Value: Strong in recoveries - Quality: Strong in downturns
Complete Strategy¶
Text Only
data:
source = "prices_fundamentals.parquet"
format = parquet
// Individual factors
signal momentum:
emit neutralize(zscore(ret(prices, 60)), by=sectors)
signal value:
emit neutralize(zscore(book_to_market), by=sectors)
signal quality:
emit neutralize(zscore(roe), by=sectors)
// Regime detection
signal volatility_regime:
vol = rolling_std(ret(market, 1), 20) * sqrt(252)
long_vol = rolling_std(ret(market, 1), 60) * sqrt(252)
high_vol = vol > long_vol * 1.3
emit high_vol
signal trend_regime:
ma_50 = rolling_mean(market, 50)
ma_200 = rolling_mean(market, 200)
uptrend = ma_50 > ma_200
emit uptrend
// Dynamic weighting
signal factor_timed:
high_vol = volatility_regime
uptrend = trend_regime
// Bull + Low Vol: Momentum heavy
// Bull + High Vol: Balanced
// Bear + Low Vol: Value heavy
// Bear + High Vol: Quality heavy
w_mom = where(uptrend and not(high_vol), 0.45,
where(uptrend and high_vol, 0.30, 0.20))
w_val = where(not(uptrend) and not(high_vol), 0.45,
where(uptrend, 0.30, 0.25))
w_qual = 1.0 - w_mom - w_val
emit w_mom * momentum + w_val * value + w_qual * quality
portfolio factor_timed:
weights = rank(factor_timed).long_short(
top = 0.2,
bottom = 0.2,
cap = 0.03
)
constraints:
gross_exposure = 2.0
net_exposure = 0.0
costs = tc.bps(10)
backtest rebal=21 from 2010-01-01 to 2024-12-31
Expected Results¶
Text Only
Factor-Timed vs Equal Weight
============================
Equal Weight Factor-Timed
Annual Return: 8.2% 9.1%
Sharpe Ratio: 0.82 0.91
Max Drawdown: -16.5% -14.2%