Creating The Leveraged Trend Following Stock Trading Algorithm Using Lumibot

Share This Post

Introduction

Welcome to this tutorial on how to use the lumibot Python library to create a leveraged trend-following bot. The lumibot library is a powerful tool that allows you to automate your trading strategies and manage your portfolio. This tutorial will guide you through setting up a leveraged trend-following bot using the lumibot library.

Prerequisites

Before you can get started with this tutorial, you will need to have the following prerequisites:

  1. A computer with Python 3.7 or higher installed.
  2. A working knowledge of Python programming.
  3. A brokerage account with Alpaca.
  4. The lumibot library installed on your computer. You can install it using the following command:
pip install lumibot

Step 1: Import Required Libraries

The first step in building your leveraged trend-following bot is to import the necessary libraries. This can be done using the following

import datetime

from lumibot.backtesting import YahooDataBacktesting
from lumibot.brokers import Alpaca
from lumibot.entities import Asset, TradingFee
from lumibot.strategies.strategy import Strategy
from lumibot.traders import Trader

Step 2: Create the StockLeverageTrendFollowing Strategy Class

Next, you will need to create a class for your strategy. This class should inherit from the Strategy class provided by the lumibot library. You can do this using the following code:

class StockLeverageTrendFollowing(Strategy):
    parameters = {
        "symbol": "SPY",
        "leverage_symbol": "UPRO",
        "period_length": 17,
    }

In this code, we define the StockLeverageTrendFollowing class as a subclass of Strategy. We also define three parameters: symbol, leverage_symbol, and period_length. These parameters will be used to customize the behavior of our strategy.

Step 3: Define the initialize Method

The initialize method is called when our strategy is first initialized. This is where you can set up any necessary data structures or perform any other setup tasks. In this case, we simply define a sleeptime variable that determines how often our strategy will be run. You can do this using the following code:

def initialize(self):
        self.sleeptime = "1D"

Step 4: Define the on_trading_iteration Method

The on_trading_iteration method is called every time our strategy is run. This is where we will define the main logic of our strategy.

First, we need to retrieve the historical prices for our asset and leverage asset. We can do this using the get_historical_prices method provided by the Strategy class. We also need to calculate the mean and exponential moving average (EMA) of the asset’s close price over the specified period length. You can do this using the following code:

def on_trading_iteration(self):
        period_length = self.parameters["period_length"]
        symbol = self.parameters["symbol"]
        leverage_symbol = self.parameters["leverage_symbol"]

        asset = Asset(symbol=symbol, asset_type="stock")
        leverage_asset = Asset(symbol=leverage_symbol, asset_type="stock")

        historical_prices = self.get_historical_prices(
            asset,
            period_length + 1,
            "day",
            quote=self.quote_asset,
        )
        df = historical_prices.df
        ema = df["close"].ewm(span=period_length).mean().iloc[-1]

Step 5: Check If the Current Price Is Above the EMA

Now that we have calculated the mean and EMA of the asset’s close price, we can use this information to determine whether the current price is above the EMA. If it is, we will buy the leverage asset. If it is not, we will buy the asset itself.

First, we retrieve the current price of the asset using the get_last_price method provided by the Strategy class. Then, we check if the current price is greater than or equal to the EMA. If it is, we proceed to the next step. Otherwise, we skip to step 7.

cur_price = self.get_last_price(asset, quote=self.quote_asset)

if cur_price >= ema:
    # Buy leverage asset

Step 6: Check the Current Positions and Buy the Leverage Asset

If the current price is above the EMA, we need to check what positions we currently have and decide whether to buy more of the leveraged asset.

First, we retrieve the current position of the leveraged asset using the get_position method provided by the Strategy class. Then, we calculate the number of shares we can buy using our available cash and the current price of the leveraged asset.

If we don’t have any position in the leveraged asset, or if our current position is smaller than the number of shares we can buy, we sell all of our current positions using the sell_all method. Then, we create a buy order for the leveraged asset using the create_order method and submit it using the submit_order method.

# Check what positions we have
position = self.get_position(leverage_asset)
price = self.get_last_price(leverage_asset, quote=self.quote_asset)
quantity = self.cash // price

if position is None or position.quantity < quantity:
    self.sell_all()
    # Buy
    if quantity > 0:
        order = self.create_order(
            leverage_asset,
            quantity,
            "buy",
        )
        self.submit_order(order)

Step 7: Check the Current Positions and Buy the Asset

If the current price is below the EMA, we need to check what positions we currently have and decide whether to buy more of the asset.

First, we retrieve the current position of the asset using the get_position method provided by the Strategy class. Then, we calculate the number of shares we can buy using our available cash and the current price of the asset.

If we don’t have any position in the asset, or if our current position is smaller than the number of shares we can buy, we sell all of our current positions using the sell_all method. Then, we create a buy order for the asset using the create_order method and submit it using the submit_order method.

else:
  # Check what positions we have
  position = self.get_position(asset)
  price = self.get_last_price(asset, quote=self.quote_asset)
  quantity = self.cash // price

  if position is None or position.quantity < quantity:
      self.sell_all()
      # Buy
      if quantity > 0:
          order = self.create_order(
              asset,
              quantity,
              "buy",
          )
          self.submit_order(order)

Step 8: Test Your Strategy in Backtesting Mode

Now that you have defined your StockLeverageTrendFollowing strategy class, you can test it in backtesting mode. To do this, you will need to define a main function and set the is_live variable to False.

In the main function, you will need to specify the start and end dates for your backtest, as well as the trading fees and the period length for your strategy. You can then create an instance of the StockLeverageTrendFollowing class and pass it to the backtest method of the YahooDataBacktesting class.

Here’s an example of how you can do this:

if __name__ == "__main__":
    is_live = False

    if is_live:
        # Run in live mode
        pass
    else:
        # Backtest this strategy
        backtesting_start = datetime.datetime(2011, 1, 1)
        backtesting_end = datetime.datetime(2022, 11, 10)

        # 0.01% trading/slippage fee
        trading_fee = TradingFee(percent_fee=0.0001)

        min_period_length = 17
        max_period_length = 17
        period_length = min_period_length

        while period_length <= max_period_length:
            StockLeverageTrendFollowing.backtest(
                YahooDataBacktesting,
                backtesting_start,
                backtesting_end,
                benchmark_asset="SPY",
                buy_trading_fees=[trading_fee],
                sell_trading_fees=[trading_fee],
                parameters={
                    "symbol": "SPY",
                    "leverage_symbol": "UPRO",
                    "period_length": period_length,
                },
            )
            period_length += 1

This will run your strategy in backtesting mode using historical data from Yahoo Finance. You can then analyze the results to see how your strategy performed.

Step 9: Run Your Strategy in Live Mode

If you want to run your strategy in live mode, you will need to set the is_live variable to True and provide your Alpaca API keys. You can then create an instance of the Alpaca class, passing your API keys as arguments.

Next, create an instance of the StockLeverageTrendFollowing class and pass the Alpaca instance as the broker argument. Finally, create an instance of the Trader class and add your strategy to it using the add_strategy method. You can then run your strategy using the run_all method.

Here’s an example of how you can do this:

if __name__ == "__main__":
    is_live = True

    if is_live:
        ALPACA_CONFIG_PAPER = {
            # Put your own Alpaca key here:
            "API_KEY": "XXXXXXXXXXXXXXXXXXXX",
            # Put your own Alpaca secret here:
            "API_SECRET": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            # If you want to go live, you must change this
            "ENDPOINT": "https://paper-api.alpaca.markets",
        }

        trader = Trader()
        broker = Alpaca(ALPACA_CONFIG_PAPER)

        strategy = StockLeverageTrendFollowing(
            broker=broker,
        )

        trader.add_strategy(strategy)
        strategy_executors = trader.run_all()

    else:
        # Backtest this strategy
        pass

Conclusion

In this tutorial, you learned how to use the lumibot Python library to create a leveraged trend following bot. You saw how to import the necessary libraries, create a StockLeverageTrendFollowing strategy class, and define the initialize and on_trading_iteration methods. You also learned how to test your strategy in backtesting mode and run it in live mode using Alpaca.

I hope you found this tutorial helpful. If you have any questions or need further assistance, please don’t hesitate to ask.

Additionally, if you’re interested in learning more about algorithmic trading, be sure to check out our free class on the subject at the following link:

This class covers the basics of algorithmic trading and will give you a solid foundation to build upon as you continue to learn and develop your trading skills.

The Full Code

Here is the full code for you to copy/paste:

import datetime

from lumibot.backtesting import YahooDataBacktesting
from lumibot.brokers import Alpaca
from lumibot.entities import Asset, TradingFee
from lumibot.strategies.strategy import Strategy
from lumibot.traders import Trader


class StockLeverageTrendFollowing(Strategy):
    parameters = {
        "symbol": "SPY",
        "leverage_symbol": "UPRO",
        "period_length": 17,
    }

    def initialize(self):
        self.sleeptime = "1D"

    def on_trading_iteration(self):
        period_length = self.parameters["period_length"]
        symbol = self.parameters["symbol"]
        leverage_symbol = self.parameters["leverage_symbol"]

        asset = Asset(symbol=symbol, asset_type="stock")
        leverage_asset = Asset(symbol=leverage_symbol, asset_type="stock")

        historical_prices = self.get_historical_prices(
            asset,
            period_length + 1,
            "day",
            quote=self.quote_asset,
        )
        df = historical_prices.df
        ema = df["close"].ewm(span=period_length).mean().iloc[-1]
        cur_price = self.get_last_price(asset, quote=self.quote_asset)

        if cur_price >= ema:
            # Check what positions we have
            position = self.get_position(leverage_asset)
            price = self.get_last_price(leverage_asset, quote=self.quote_asset)
            quantity = self.cash // price

            if position is None or position.quantity < quantity:
                self.sell_all()
                # Buy
                if quantity > 0:
                    order = self.create_order(
                        leverage_asset,
                        quantity,
                        "buy",
                    )
                    self.submit_order(order)

        else:
            # Check what positions we have
            position = self.get_position(asset)
            price = self.get_last_price(asset, quote=self.quote_asset)
            quantity = self.cash // price

            if position is None or position.quantity < quantity:
                self.sell_all()
                # Buy
                if quantity > 0:
                    order = self.create_order(
                        asset,
                        quantity,
                        "buy",
                    )
                    self.submit_order(order)


if __name__ == "__main__":
    is_live = False

    if is_live:
        ALPACA_CONFIG_PAPER = {
            # Put your own Alpaca key here:
            "API_KEY": "XXXXXXXXXXXXXXXXXXXX",
            # Put your own Alpaca secret here:
            "API_SECRET": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            # If you want to go live, you must change this
            "ENDPOINT": "https://paper-api.alpaca.markets",
        }

        trader = Trader()
        broker = Alpaca(ALPACA_CONFIG_PAPER)

        strategy = StockLeverageTrendFollowing(
            broker=broker,
        )

        trader.add_strategy(strategy)
        strategy_executors = trader.run_all()

    else:
        # Backtest this strategy
        backtesting_start = datetime.datetime(2011, 1, 1)
        backtesting_end = datetime.datetime(2022, 11, 10)

        # 0.01% trading/slippage fee
        trading_fee = TradingFee(percent_fee=0.0001)

        min = 17
        max = 17
        period_length = min

        while period_length <= max:
            StockLeverageTrendFollowing.backtest(
                YahooDataBacktesting,
                backtesting_start,
                backtesting_end,
                benchmark_asset="SPY",
                buy_trading_fees=[trading_fee],
                sell_trading_fees=[trading_fee],
                parameters={"period_length": period_length},
                name=f"stock-leverage-trend-following-{period_length}",
            )

            period_length += 1

The Backtesting Results

Here are the results from backtesting this algorithm, as you can see it significantly outperforms the SPY (S&P 500) benchmark

Bonus

Did you enjoy this article? If yes then you’ll probably also love our courses. We teach people how to use software code to improve their stock, options, crypto, futures, and FOREX trading. It’s really easy (and free) to get started, just enter your name, email, and phone number into the form below:

Become A Master Of Trading By Creating Your Own High-Performing Trading Bots

Want to learn how to use Python to create your own algorithmic trading bots? Then sign up below to get access to our free class!


More To Explore

Want to learn more?

Book a free call with one of our experts