Diversified Portfolio of Leveraged ETFs with Periodic Rebalancing
Summary
This strategy allocates a portfolio across leveraged funds tied to US stock indexes, Treasury bonds, gold, and oil and gas companies. It assigns each holding a target weight, checks the portfolio daily, and rebalances every four days by comparing each target share count with the current position. Orders buy or sell the difference, using whole shares based on the latest price and portfolio value. The example also includes a historical backtest setup against an S&P 500 fund and applies trading fees.
The document provides implementation details but no backtest results or evidence that the allocation is profitable. Leveraged funds can magnify losses and may behave differently from their stated daily leverage over longer periods. The rebalance interval, fixed weights, price data, and trading costs all affect outcomes. The code does not describe broader risk controls such as drawdown limits or volatility-based sizing, so the example should be treated as a basic allocation and rebalancing template rather than a validated strategy.
Key ideas
- The portfolio spreads target weights across leveraged equity, bond, gold, and energy funds.
- It checks positions daily and rebalances on a four-day cycle.
- Target share quantities are calculated from portfolio value, asset weight, and latest price.
- The example backtest includes trading fees and uses an S&P 500 fund as its benchmark.
- The document reports no performance results and gives no dedicated loss-control rules.
Tags
Full text
# stock_diversified_leverage.py
```py
from lumibot.strategies.strategy import Strategy
"""
Strategy Description
This strategy will buy a few symbols that have 2x or 3x returns (have leverage), but will
also diversify and rebalance the portfolio often.
"""
class DiversifiedLeverage(Strategy):
# =====Overloading lifecycle methods=============
parameters = {
"portfolio": [
{
"symbol": "TQQQ", # 3x Leveraged Nasdaq
"weight": 0.20,
},
{
"symbol": "UPRO", # 3x Leveraged S&P 500
"weight": 0.20,
},
{
"symbol": "UDOW", # 3x Leveraged Dow Jones
"weight": 0.10,
},
{
"symbol": "TMF", # 3x Leveraged Treasury Bonds
"weight": 0.25,
},
{
"symbol": "UGL", # 3x Leveraged Gold
"weight": 0.10,
},
{
"symbol": "DIG", # 2x Leveraged Oil and Gas Companies (Commodities)
"weight": 0.15,
},
],
"rebalance_period": 4,
}
def initialize(self):
# Setting the waiting period (in days) and the counter
self.counter = None
# There is only one trading operation per day
# no need to sleep between iterations
self.sleeptime = "1D"
# Initializing the portfolio variable with the assets and proportions we want to own
self.initialized = False
self.minutes_before_closing = 1
def on_trading_iteration(self):
rebalance_period = self.parameters["rebalance_period"]
# If the target number of days (period) has passed, rebalance the portfolio
if self.counter == rebalance_period or self.counter == None:
self.counter = 0
self.rebalance_portfolio()
self.log_message(
f"Next portfolio rebalancing will be in {rebalance_period} day(s)"
)
self.log_message("Sleeping until next trading day")
self.counter += 1
# =============Helper methods====================
def rebalance_portfolio(self):
"""Rebalance the portfolio and create orders"""
orders = []
for asset in self.parameters["portfolio"]:
# Get all of our variables from portfolio
symbol = asset.get("symbol")
weight = asset.get("weight")
last_price = self.get_last_price(symbol)
# Get how many shares we already own
# (including orders that haven't been executed yet)
position = self.get_position(symbol)
quantity = 0
if position is not None:
quantity = float(position.quantity)
# Calculate how many shares we need to buy or sell
portfolio_value = self.get_portfolio_value()
shares_value = portfolio_value * weight
self.log_message(
f"The current portfolio value is {portfolio_value} and the weight needed is {weight}, "
f"so we should buy {shares_value}"
)
new_quantity = shares_value // last_price
quantity_difference = new_quantity - quantity
self.log_message(
f"Currently own {quantity} shares of {symbol} but need {new_quantity}, so the difference is "
f"{quantity_difference}"
)
# If quantity is positive then buy, if it's negative then sell
side = ""
if quantity_difference > 0:
side = "buy"
elif quantity_difference < 0:
side = "sell"
# Execute the order if necessary
if side:
order = self.create_order(symbol, abs(quantity_difference), side)
orders.append(order)
self.submit_orders(orders)
if __name__ == "__main__":
is_live = False
if is_live:
####
# Run the strategy live
####
from credentials import ALPACA_CONFIG
from lumibot.brokers import Alpaca
broker = Alpaca(ALPACA_CONFIG)
strategy = DiversifiedLeverage(broker=broker)
strategy.run_live()
else:
####
# Backtest the strategy
####
# Choose the time from and to which you want to backtest
from datetime import datetime
backtesting_start = datetime(2010, 6, 1)
backtesting_end = datetime(2023, 7, 31)
# 0.01% trading/slippage fee
from lumibot.backtesting import YahooDataBacktesting
from lumibot.entities import TradingFee
trading_fee = TradingFee(percent_fee=0.005)
# Initialize the backtesting object
print("Starting Backtest...")
result = DiversifiedLeverage.backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
benchmark_asset="SPY",
parameters={},
buy_trading_fees=[trading_fee],
sell_trading_fees=[trading_fee],
)
print("Backtest result: ", result)
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.