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