Bitcoin – Trading Moving Averages or HODL? A Python Script Uncovers the Answer!

4/5 - (2 votes)

I’ve always wondered if a slow and high-level trading strategy focusing on long-term trends could outperform a buy-and-hold strategy.

To answer this question, I created a Python script that would utilize a momentum-based strategy to tell me when to buy and when to sell Bitcoin.

Despite my busy life and doubts that day trading would be a successful venture, I was eager to find out if this simple program could beat the market. I can run the Python code daily to decide whether to buy or sell BTC.

What would have happened if I had used the following strategy between the turbulent years 2020 and 2022 in Bitcoin? Read on to find out! πŸ‘‡

General Idea

The idea of this algorithm is to allow traders to automate their Bitcoin trading decisions using two moving averages.

πŸ‘‰ Finxter Academy: Complete Python Trading Course (Binance) — Simple Moving Average

The algorithm will enter buy positions when the shorter-term moving average (MA1) is higher than the longer-term moving average (MA2) indicating a positive momentum of the Bitcoin price, and enter sell positions when the shorter-term moving average is lower than the longer-term moving average indicating a negative momentum of the Bitcoin price.

When the moving averages cross, the algorithm will close any existing positions and reverse the trading direction.

Algorithm Steps

My strategy follows these simple steps:

  1. Initialize two moving averages, MA1 and MA2, with different lookback periods.
  2. Calculate the current value of each moving average.
  3. If MA1 > MA2, enter a buy position in the Bitcoin market.
  4. If MA1 < MA2, enter a sell position in the Bitcoin market.
  5. Monitor the market for any changes in the moving averages.
  6. When the moving averages cross, close any existing positions and reverse the trading direction (buy if previously selling, sell if previously buying).
  7. Repeat steps 2 to 6.

Python Program to Automate It

The following program implements these steps in practice by pulling the Bitcoin price data from an online API, calculating the moving averages (short- and long-term), and trading based on whether the short-term MA is below or above the long-term MA.

I’ll explain the code in a minute!

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests 

# Get Bitcoin Price Data
URL = ''
response = requests.get(URL) 
data = response.json()

daily_data = data["Time Series (Digital Currency Daily)"]

# Convert JSON to DataFrame
df = pd.DataFrame(daily_data)
df = df.T

# Create two Moving Averages
MA1 = 20
MA2 = 50
df['MA1'] = df['1a. open (USD)'].rolling(MA1).mean()
df['MA2'] = df['1a. open (USD)'].rolling(MA2).mean()

# Initialize variables
position = 0
my_usd = 10000
my_btc = 0

print('Initial balance:', str(my_usd), 'USD')

# Backtest Algorithm
for i in range(len(df)):

    # Get price
    price = float(df['1a. open (USD)'].iloc[i])
    # Buy position
    if df['MA1'].iloc[i] > df['MA2'].iloc[i] and position == 0:
        position = 1
        my_btc = price / my_usd
        my_usd = 0
        print('Buying at', price, 'on', df.index[i])
    # Sell position
    elif df['MA1'].iloc[i] < df['MA2'].iloc[i] and position == 1:
        position = 0
        my_usd = price * my_btc
        my_btc = 0
        print('Selling at', price, 'on', df.index[i])

print('Final balance:', str(my_usd + my_btc * price))

initial_btc = float(df['1a. open (USD)'].iloc[0]) / 10000
value_today = initial_btc * float(df['1a. open (USD)'].iloc[-1])
print('Final balance (buy and hold):', str(value_today))

Code Explanation

This code implements the algorithm described above.

The first portion of the code is getting the daily Bitcoin price data from the API and converting it into a DataFrame.

Next, the code creates two moving averages, MA1 and MA2, based on the open price of Bitcoin. Then, the code initializes the position variable to 0.

The backtest algorithm then runs a loop to iterate through the DataFrame to identify when conditions are met to buy or sell. If the shorter-term MA1 is higher than the longer-term MA2, the code will enter a buy position.

Similarly, if the shorter-term MA1 is lower than the longer-term MA2, the code will enter a sell position. We don’t assume short selling so “selling” on an empty position just means waiting for the next buy opportunity.

Finally, if the MA1 and MA2 cross, the code will close any existing position and reverse the trading direction.

Backtesting the Strategy

Let’s have a look at an example run — note to read this from bottom to top! πŸ‘‡

Initial balance: 10000 USD
Buying at 20905.58 on 2022-11-07
Selling at 18809.13 on 2022-09-26
Buying at 21826.87 on 2022-09-12
Selling at 19331.28 on 2022-07-13
Buying at 28424.71 on 2022-06-12
Selling at 41941.7 on 2022-03-10
Buying at 42380.87 on 2022-02-07
Selling at 36660.35 on 2022-01-25
Buying at 41566.48 on 2022-01-08
Selling at 57471.35 on 2021-10-12
Buying at 47674.01 on 2021-08-25
Selling at 44572.54 on 2021-08-08
Buying at 40516.28 on 2021-06-15
Selling at 57351.56 on 2021-03-22
Buying at 57641.0 on 2021-03-19
Selling at 56900.74 on 2021-03-17
Buying at 11318.42 on 2020-08-26
Selling at 9538.1 on 2020-07-25
Buying at 9772.44 on 2020-06-10
Selling at 9315.96 on 2020-05-16
Final balance: 14806.674822101442
Final balance (buy and hold): 15095.029852800002

So, you see, in the period between May 2020 and November 2022, trading wouldn’t have been more profitable than simply buying and holding Bitcoin — even when ignoring trading fees and higher tax burden.

And ignoring the fact that Bitcoin has had huge up and down volatility, which should be great for trading. That is — in theory.


Buy and HODL!