| Overall Statistics |
|
Total Orders 352 Average Win 0.50% Average Loss -1.61% Compounding Annual Return 23.068% Drawdown 10.900% Expectancy 0.015 Start Equity 10000 End Equity 14015.57 Net Profit 40.156% Sharpe Ratio 1.005 Sortino Ratio 1.355 Probabilistic Sharpe Ratio 72.586% Loss Rate 22% Win Rate 78% Profit-Loss Ratio 0.31 Alpha 0.087 Beta 0.153 Annual Standard Deviation 0.107 Annual Variance 0.012 Information Ratio -0.197 Tracking Error 0.14 Treynor Ratio 0.705 Total Fees $366.07 Estimated Strategy Capacity $5200000.00 Lowest Capacity Asset VXZB WRBPJAJZ2Q91 Portfolio Turnover 2.71% |
from AlgorithmImports import *
from scipy.optimize import minimize
class LeverageEtfRiskParity(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 1)
self.set_cash(10000)
self.symbols = [self.add_equity(ticker, data_normalization_mode=DataNormalizationMode.RAW).symbol for ticker in ["TQQQ", "SVXY", "VXZ", "TMF", "EDZ", "UGL"]]
self.dynamic_leverage = 1 # Start with base leverage of 1
self.stop_loss_threshold = 0.1 # Define a 10% stop-loss limit
self.schedule.on(self.date_rules.week_start(), self.time_rules.at(8, 0), self.rebalance)
def rebalance(self):
# Calculate average volatility across all symbols
historical_data = self.history(self.symbols, 20, Resolution.DAILY).close.unstack(0)
volatilities = historical_data.pct_change().std() # Standard deviation of daily returns for each symbol
avg_volatility = volatilities.mean() # Take the mean across symbols
self.dynamic_leverage = min(1.5, 1 / avg_volatility) # Cap leverage at 1.5 for risk management
# Calculate daily returns and optimize portfolio
ret = self.history(self.symbols, 253, Resolution.DAILY).close.unstack(0).pct_change().dropna()
x0 = [1 / ret.shape[1]] * ret.shape[1]
constraints = {"type": "eq", "fun": lambda w: np.sum(w) - 1}
bounds = [(0, 1)] * ret.shape[1]
opt = minimize(lambda w: 0.5 * (w.T @ ret.cov() @ w) - x0 @ w, x0=x0, constraints=constraints, bounds=bounds, tol=1e-8, method="SLSQP")
# Apply leverage and set holdings
targets = [PortfolioTarget(symbol, weight * self.dynamic_leverage) for symbol, weight in zip(ret.columns, opt.x)]
self.set_holdings(targets)
def on_data(self, data):
# Implement a stop-loss mechanism to limit losses
for symbol in self.symbols:
price = self.securities[symbol].price
if price < (1 - self.stop_loss_threshold) * self.portfolio[symbol].average_price:
self.liquidate(symbol) # Exit position if it falls below stop-loss threshold