| Overall Statistics |
|
Total Orders 655 Average Win 4.20% Average Loss -4.22% Compounding Annual Return -12.572% Drawdown 83.000% Expectancy 0.009 Start Equity 100000 End Equity 51060.54 Net Profit -48.939% Sharpe Ratio 0.166 Sortino Ratio 0.202 Probabilistic Sharpe Ratio 1.654% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 0.99 Alpha -0.058 Beta 2.274 Annual Standard Deviation 0.675 Annual Variance 0.456 Information Ratio 0.06 Tracking Error 0.621 Treynor Ratio 0.049 Total Fees $3345.25 Estimated Strategy Capacity $190000000.00 Lowest Capacity Asset ZC Z0PZXJ6AS0F9 Portfolio Turnover 46.00% Drawdown Recovery 225 |
# region imports
from AlgorithmImports import *
from datetime import datetime
import math
# endregionfs
class InverseVolatilityFuturesAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(self.end_date - timedelta(5*365))
self.settings.seed_initial_prices = True
# Add a universe of Futures.
tickers = [
Futures.Indices.VIX,
Futures.Indices.SP_500_E_MINI,
Futures.Indices.NASDAQ_100_E_MINI,
Futures.Indices.DOW_30_E_MINI,
Futures.Energies.BRENT_CRUDE,
Futures.Energies.GASOLINE,
Futures.Energies.HEATING_OIL,
Futures.Energies.NATURAL_GAS,
Futures.Grains.CORN,
Futures.Grains.OATS,
Futures.Grains.SOYBEANS,
Futures.Grains.WHEAT
]
self._futures = []
for ticker in tickers:
future = self.add_future(ticker, extended_market_hours=True)
# Add a volaility indicator on the continuous contract.
future.vol = IndicatorExtensions.of(
StandardDeviation(30),
self.roc(future, 1, Resolution.DAILY)
)
self._futures.append(future)
# Warm up the indicators.
self.set_warmup(31, Resolution.DAILY)
# Add a Scheduled Event to rebalance the portfolio.
self.schedule.on(
self.date_rules.week_start(),
self.time_rules.at(10, 0, 0),
self._rebalance
)
def _rebalance(self):
if self.is_warming_up:
return
# Select the 5 Futures with the lowest volatility.
futures = [
future for future in self._futures
if (future.mapped and
future.vol.is_ready and
future.exchange.hours.is_open(self.time, True))
]
selected = sorted(futures, key=lambda future: future.vol)[:5]
# Sum the inverse of volatilities.
inverse_sum = sum([1/future.vol.current.value for future in selected])
if inverse_sum == 0:
return
# Form the inverse-volaility weighted portfolio.
targets = [
PortfolioTarget(future.mapped, 1/future.vol.current.value/inverse_sum/2)
for future in selected
]
self.set_holdings(targets, True)