Don't Trade Blindly: Backtest Your Crypto Strategy with Python

 Introduction

Most traders lose money because they guess. Pro traders test.

Before you risk a single Dollar on Bitcoin, wouldn't you want to know how your strategy performed during the 2022 crash or the 2024 rally? That is the power of backtesting—simulating a trading strategy on historical data to see if it actually holds water.

Python Backtesting Crypto Strategy Tutorial

In this tutorial, we are going to build a backtesting engine from scratch. We will test one of the most famous indicators in crypto: the SMA Crossover (Golden Cross).

Note: In our previous Data Visualization Guide, we learned how to fetch Bitcoin data and plot price charts. Now, let's use that data to find profitable signals.


Prerequisites

To follow along, you’ll need Python installed and the following libraries. If you haven't installed them yet, run this in your terminal:

pip install pandas numpy yfinance matplotlib

The Strategy: The Golden Cross

For this backtest, we will use a classic trend-following strategy:

  1. The Indicators: We use two Simple Moving Averages (SMA).

    • Fast SMA (50-day): Reacts quickly to price changes.

    • Slow SMA (200-day): Reacts slowly, showing the long-term trend.

  2. The Buy Signal (Golden Cross): When the SMA-50 crosses above the SMA-200, it indicates a bullish trend. We buy (Long).

  3. The Sell Signal (Death Cross): When the SMA-50 crosses below the SMA-200, the trend is bearish. We sell (move to Cash).


The Code: Building the Backtester

Create a new Python file (e.g., backtest_btc.py) and follow these four steps.

Step 1: Fetch BTC-USD Data

We will grab the last 3 years of Bitcoin data using yfinance.

import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt

# 1. Fetch Data
# We download daily Bitcoin data for the last 3 years
ticker = "BTC-USD"
data = yf.download(ticker, period="3y", interval="1d")

# Clean up the dataframe (handle multi-level columns if present)
if isinstance(data.columns, pd.MultiIndex):
    data.columns = data.columns.get_level_values(0)

# We only need the 'Close' price for this strategy
df = data[['Close']].copy()

Step 2: Calculate Indicators

Now, we use pandas to calculate the rolling averages.

# 2. Calculate SMAs
# Calculate the 50-day and 200-day Simple Moving Averages
df['SMA_50'] = df['Close'].rolling(window=50).mean()
df['SMA_200'] = df['Close'].rolling(window=200).mean()

# Drop NaN values (the first 200 days won't have an SMA_200)
df.dropna(inplace=True)

Step 3: Generate Signals

Here is where the magic happens. We create a logic that tells the computer when to be "in" the market and when to be "out".

# 3. Generate Signals
# If SMA_50 > SMA_200, Signal = 1 (Buy/Hold)
# If SMA_50 < SMA_200, Signal = 0 (Sell/Cash)
df['Signal'] = np.where(df['SMA_50'] > df['SMA_200'], 1, 0)

# IMPORTANT: Shift the signal by 1 day!
# Why? We calculate the signal based on today's CLOSING price. 
# We can only execute the trade the NEXT day. 
# Without .shift(1), we introduce "look-ahead bias" (cheating).
df['Position'] = df['Signal'].shift(1)

Step 4: Calculate Returns

We compare the strategy against a simple "Buy and Hold" approach.

# 4. Calculate Returns
# Calculate daily percent change (returns) of Bitcoin
df['Market_Returns'] = df['Close'].pct_change()

# Calculate Strategy Returns: Position (1 or 0) * Market Returns
# If Position is 0 (Cash), our return for that day is 0.
df['Strategy_Returns'] = df['Position'] * df['Market_Returns']

# Calculate Cumulative Returns (Growth of $1 investment)
df['Cumulative_Market'] = (1 + df['Market_Returns']).cumprod()
df['Cumulative_Strategy'] = (1 + df['Strategy_Returns']).cumprod()

# Print the final result
print(f"Buy & Hold Return: {(df['Cumulative_Market'].iloc[-1] - 1)*100:.2f}%")
print(f"Strategy Return:   {(df['Cumulative_Strategy'].iloc[-1] - 1)*100:.2f}%")

Visuals: Plotting the Performance

Use matplotlib to verify your signals visually.

# Plotting
plt.figure(figsize=(12, 6))

# Plot cumulative returns to compare performance
plt.plot(df['Cumulative_Market'], label='Buy & Hold (BTC)', color='gray', alpha=0.5)
plt.plot(df['Cumulative_Strategy'], label='SMA Crossover Strategy', color='green')

plt.title('Bitcoin: SMA Crossover vs. Buy & Hold')
plt.legend()
plt.show()

What you will see: When you run this code, a chart will pop up showing two lines. The Gray line is the price of Bitcoin if you just bought it 3 years ago and didn't touch it. The Green line is your strategy.

  • Flat Lines: Notice how the Green line sometimes goes flat? That is when the SMA-50 dropped below the SMA-200. The code sold your Bitcoin for cash, protecting you from further crashes.

  • Rising Lines: This is when the Golden Cross is active, and your money is riding the trend.


The Results

If you run this on recent Bitcoin data, you might notice something interesting. While "Buy & Hold" captures the massive rallies, it also suffers the massive 70% drops.

The SMA Crossover strategy often underperforms in a choppy, sideways market (because it buys and sells too late), but it shines by avoiding major bear markets.

  • High Volatility: Buy & Hold is a rollercoaster.

  • Managed Risk: The SMA Strategy cuts losses, leading to a smoother equity curve.


Conclusion

Backtesting proves if your idea works before you risk real capital. In this case, we built a simple trend-following bot that keeps us in the market during bull runs and moves us to cash during bear markets.

However, this is just a simulation. Real trading involves fees, slippage, and emotion.

Ready to run this strategy live? Check out our DCA Bot Tutorial to automate these trades using Python and a crypto exchange API.

SEO Keywords: python backtesting tutorial, SMA crossover strategy, crypto algorithmic trading, pandas finance.


Disclaimer: The information provided in this article is for educational purposes only. Past performance is not indicative of future results. Trading cryptocurrencies involves significant risk.

Comments

Popular posts from this blog

Automate Your Bitcoin Buys: The Ultimate Python DCA Bot Tutorial

TradingView vs Python: The Ultimate Battle for Crypto Automation

Python for Finance: Visualize Bitcoin Volatility in 5 Minutes