Gold Market Timing
Log in to collectAcademic paper
Strategy in a nutshell
Use Fed model: buy gold when stock E/P ≥ 1.15 × 10-year bond yield; rebalance monthly based on updated signals.
Economic rationale
Expected inflation lowers equity returns; Fed model signals undervaluation prompt a shift to gold, exploiting periods when stocks appear overpriced relative to bonds.
Backtest performance
Annualised return31%
Volatility29.63%
Beta-0.006
Sharpe ratio0.91
Sortino ratio0.238
Win rate100%
Full Python code
import data_tools
from AlgorithmImports import *
class GoldMarketTiming(QCAlgorithm):
def Initialize(self) -> None:
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
self.leverage: int = 5
# United States Government 10-Year Bond Yield
self.bond_yield: str = "US10YT"
self.AddData(data_tools.QuantpediaBondYield, self.bond_yield, Resolution.Daily)
# S&P 500 Earnings Yield. Earnings Yield = trailing 12 month earnings divided by index price
self.earnings_yield: str = "SP500_EARNINGS_YIELD_MONTH"
self.AddData(data_tools.QuantpediaMonthlyData, self.earnings_yield, Resolution.Daily)
# Gold Prices (Daily) - Currency USD (All values are national currency units per troy ounce)
self.gold: str = "CME_GC1"
data: Securities = self.AddData(data_tools.QuantpediaFutures, self.gold, Resolution.Daily)
data.SetLeverage(self.leverage)
data.SetFeeModel(data_tools.CustomFeeModel())
# Custom chart.
yieldPlot: Chart = Chart("Yield Plot")
yieldPlot.AddSeries(Series("Bond Yield", SeriesType.Line, 0))
yieldPlot.AddSeries(Series("Earnings Yield", SeriesType.Line, 0))
self.AddChart(yieldPlot)
def OnData(self, data: Slice) -> None:
custom_data_last_update_date: Dict[Symbol, datetime.date] = data_tools.LastDateHandler.get_last_update_date()
# monthly rebalance
if self.earnings_yield in data and data[self.earnings_yield]:
if self.Securities.ContainsKey(self.bond_yield) and self.Securities.ContainsKey(self.gold):
by_data = self.Securities[self.bond_yield].GetLastData()
gold_data = self.Securities[self.gold].GetLastData()
if by_data and gold_data:
if self.Time.date() <= custom_data_last_update_date[self.bond_yield] \
and self.Time.date() <= custom_data_last_update_date[self.gold]:
# Update custom chart.
self.Plot("Yield Plot", "Bond Yield", self.Securities[self.bond_yield].Price)
self.Plot("Yield Plot", "Earnings Yield", self.Securities[self.earnings_yield].Price)
# Buy gold if E/P is higher than the bond yield and their ratio is at least 2.
# NOTE: Ratio of 1.15 in paper is not used due to low number of positions opened.
if self.Securities[self.earnings_yield].Price > self.Securities[self.bond_yield].Price * 1.15:
self.SetHoldings(self.gold, 1)
else:
self.Liquidate()
else:
self.Liquidate()
if self.Securities.ContainsKey(self.earnings_yield):
ey_data = self.Securities[self.earnings_yield].GetLastData()
if ey_data:
if self.Time.date() > custom_data_last_update_date[self.earnings_yield]:
self.Liquidate()
return