| Overall Statistics |
|
Total Trades 4746 Average Win 0.51% Average Loss -0.54% Compounding Annual Return 3.932% Drawdown 37.800% Expectancy 0.042 Net Profit 58.559% Sharpe Ratio 0.276 Probabilistic Sharpe Ratio 0.128% Loss Rate 46% Win Rate 54% Profit-Loss Ratio 0.93 Alpha 0.002 Beta 0.358 Annual Standard Deviation 0.129 Annual Variance 0.017 Information Ratio -0.384 Tracking Error 0.151 Treynor Ratio 0.1 Total Fees $54404.70 Estimated Strategy Capacity $45000000.00 Lowest Capacity Asset ZO Y6RTF5MGZVOL |
# region imports
from AlgorithmImports import *
from datetime import datetime
import math
# endregionfs
class InverseVolatility(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2011, 1, 1) # Jens
#self.SetEndDate(2021, 12, 31)
self.SetCash(1000000) # Set Strategy Cash
self.SetSecurityInitializer(BrokerageModelSecurityInitializer(self.BrokerageModel, FuncSecuritySeeder(self.GetLastKnownPrices)))
self.volatility = {}
tickers = [
Futures.Indices.VIX,
Futures.Indices.SP500EMini,
Futures.Indices.NASDAQ100EMini,
Futures.Indices.Dow30EMini,
Futures.Energies.BrentCrude,
Futures.Energies.Gasoline,
Futures.Energies.HeatingOil,
Futures.Energies.NaturalGas,
Futures.Grains.Corn,
Futures.Grains.Oats,
Futures.Grains.Soybeans,
Futures.Grains.Wheat
]
for ticker in tickers:
future = self.AddFuture(ticker, extendedMarketHours=True)
# 30-day standard deviation of 1-day returns
roc = self.ROC(future.Symbol, 1, Resolution.Daily)
self.volatility[future] = IndicatorExtensions.Of(StandardDeviation(30), roc)
self.SetWarmup(31, Resolution.Daily)
self.Schedule.On(
self.DateRules.WeekStart(),
self.TimeRules.At(10,0,0),
self.Rebalance)
def Rebalance(self):
if self.IsWarmingUp:
return
sorted_by_value = sorted([kvp for kvp in self.volatility.items() if kvp[1].IsReady],
key=lambda item: item[1].Current.Value)
top5 = {k: v for k, v in sorted_by_value[:5]}
# Sum the inverse STD of ROC
# Jens: Added exception here as well. Not sure if that still works as it should. I ignore values that have no std yet
inverse_sum = sum([1/std.Current.Value if std.Current.Value else 0 for std in top5.values()])
if inverse_sum == 0:
return
# Create Portfoliotarget for the inverse weighted STD
targets = [PortfolioTarget(future.Mapped, 0.1/std.Current.Value/inverse_sum)
# Jens: added exception for std being zero then no target will be given. This accounts for the fact that these
# contracts are also not included in the inverse_sum
for future,std in top5.items() if future.Mapped and std.Current.Value]
# Liquidate if invested and no new negative news
for symbol, holdings in self.Portfolio.items():
if holdings.Invested and symbol not in top5:
targets.append(PortfolioTarget(symbol, 0))
#for target in targets:
# self.Plot("Targets", target.Symbol.Value, target.Quantity)
self.SetHoldings(targets)