darusuna.com

Back-Testing a Crypto Trading Strategy Using Python

Written on

Overview of the Trading Strategy

This trading approach integrates three technical indicators: MACD (Moving Average Convergence Divergence), RSI (Relative Strength Index), and EMA (Exponential Moving Average). The goal is to pinpoint potential long and short trading opportunities based on the alignment of these indicators.

Components of the Strategy

Exponential Moving Average (EMA): - The EMA is a specific type of moving average that assigns more weight to recent price data. - For this strategy, we utilize a 200-day EMA to assess the overall trend. A price above the EMA indicates a bullish trend, while a price below suggests a bearish trend.

Relative Strength Index (RSI): - The RSI acts as a momentum oscillator, quantifying the speed and change of price movements. - It ranges from 0 to 100. Generally, an RSI over 70 indicates overbought conditions, whereas an RSI below 30 indicates oversold conditions. In this strategy, we use a threshold of 50 to gauge bullish or bearish momentum.

Moving Average Convergence Divergence (MACD): - The MACD is a trend-following momentum indicator that reflects the relationship between two moving averages of a security's price. - The MACD line is derived by subtracting the 26-period EMA from the 12-period EMA, while the signal line is the 9-period EMA of the MACD line. - Buy signals arise when the MACD line crosses above the signal line, and sell signals occur when it crosses below.

Trading Guidelines

Long Entry Conditions: - The MACD line crosses above the signal line. - The RSI is greater than 50. - The price exceeds the 200-day EMA.

Short Entry Conditions: - The MACD line crosses below the signal line. - The RSI is less than 50. - The price falls below the 200-day EMA.

Long Exit Conditions: - The MACD line crosses below the signal line. - The RSI drops below 50. - The price dips below the 200-day EMA.

Short Exit Conditions: - The MACD line crosses above the signal line. - The RSI rises above 50. - The price climbs above the 200-day EMA.

Implementation

This strategy is executed in Python, utilizing historical data sourced from Binance through the ccxt library. We compute the EMA, RSI, and MACD indicators using pandas and numpy.

Backtesting is performed on historical data to evaluate the strategy's performance. The code also incorporates various performance metrics and visualizations to assess its effectiveness.

Python Code for Implementation

Here’s the complete Python code for back-testing the strategy using Python 3.10 and Visual Studio Code:

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

# Retrieve historical data from Binance def fetch_binance_data(symbol, timeframe, since):

exchange = ccxt.binance()

ohlcv = exchange.fetch_ohlcv(symbol, timeframe, since=since)

data = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])

data['timestamp'] = pd.to_datetime(data['timestamp'], unit='ms')

data.set_index('timestamp', inplace=True)

return data

# Calculate EMA def ema(series, period):

return series.ewm(span=period, adjust=False).mean()

# Calculate RSI def rsi(series, period):

delta = series.diff()

gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()

loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()

rs = gain / loss

return 100 - (100 / (1 + rs))

# Calculate MACD def macd(series, fastperiod=12, slowperiod=26, signalperiod=9):

fast_ema = ema(series, fastperiod)

slow_ema = ema(series, slowperiod)

macd_line = fast_ema - slow_ema

signal_line = ema(macd_line, signalperiod)

return macd_line, signal_line

# Define parameters symbol = 'BTC/USDT' timeframe = '1d' since = ccxt.binance().parse8601('2020-01-01T00:00:00Z')

# Fetch data data = fetch_binance_data(symbol, timeframe, since)

# Compute indicators data['EMA'] = ema(data['close'], period=200) data['RSI'] = rsi(data['close'], period=14) data['MACD'], data['MACDSignal'] = macd(data['close'])

# Trading signals data['LongEntry'] = ((data['MACD'] > data['MACDSignal']) &

(data['RSI'] > 50) &

(data['close'] > data['EMA']))

data['ShortEntry'] = ((data['MACD'] < data['MACDSignal']) &

(data['RSI'] < 50) &

(data['close'] < data['EMA']))

data['LongExit'] = ((data['MACD'] < data['MACDSignal']) |

(data['RSI'] < 50) |

(data['close'] < data['EMA']))

data['ShortExit'] = ((data['MACD'] > data['MACDSignal']) |

(data['RSI'] > 50) |

(data['close'] > data['EMA']))

# Initialize position and portfolio value data['Position'] = 0 data['PortfolioValue'] = 100000 # Starting value

# Execute the strategy position = 0 # 1 for long, -1 for short, 0 for no position entry_price = 0 num_trades = 0

for i in range(1, len(data)):

if position == 0:

if data['LongEntry'].iloc[i]:

position = 1

entry_price = data['close'].iloc[i]

data['Position'].iloc[i] = 1

num_trades += 1

elif data['ShortEntry'].iloc[i]:

position = -1

entry_price = data['close'].iloc[i]

data['Position'].iloc[i] = -1

num_trades += 1

elif position == 1:

if data['LongExit'].iloc[i]:

position = 0

entry_price = 0

data['Position'].iloc[i] = 1

elif position == -1:

if data['ShortExit'].iloc[i]:

position = 0

entry_price = 0

data['Position'].iloc[i] = -1

# Calculate portfolio value data['DailyReturn'] = data['close'].pct_change() data['StrategyReturn'] = data['Position'].shift(1) * data['DailyReturn'] data['PortfolioValue'] = (1 + data['StrategyReturn']).cumprod() * 100000

# Performance metrics total_return = data['PortfolioValue'].iloc[-1] - 100000 annualized_return = (data['PortfolioValue'].iloc[-1] / 100000) ** (252 / len(data)) - 1 cagr = ((data['PortfolioValue'].iloc[-1] / 100000) ** (1 / (len(data) / 252)) - 1) max_drawdown = ((data['PortfolioValue'].cummax() - data['PortfolioValue']) / data['PortfolioValue'].cummax()).max() sharpe_ratio = data['StrategyReturn'].mean() / data['StrategyReturn'].std() * np.sqrt(252) volatility = data['StrategyReturn'].std() * np.sqrt(252)

print(f"Total Return: {total_return:.2f}") print(f"Annualized Return: {annualized_return:.2%}") print(f"CAGR: {cagr:.2%}") print(f"Max Drawdown: {max_drawdown:.2%}") print(f"Sharpe Ratio: {sharpe_ratio:.2f}") print(f"Volatility: {volatility:.2%}") print(f"Number of Trades: {num_trades}")

# Visualization of results plt.figure(figsize=(14, 7))

# Close Price and EMA plt.subplot(3, 1, 1) plt.plot(data['close'], label='Close Price') plt.plot(data['EMA'], label='200-day EMA', color='blue') plt.scatter(data.index[data['LongEntry']], data['close'][data['LongEntry']], marker='^', color='green', label='Long Entry') plt.scatter(data.index[data['ShortEntry']], data['close'][data['ShortEntry']], marker='v', color='red', label='Short Entry') plt.scatter(data.index[data['LongExit']], data['close'][data['LongExit']], marker='o', color='green', label='Long Exit') plt.scatter(data.index[data['ShortExit']], data['close'][data['ShortExit']], marker='o', color='red', label='Short Exit') plt.title('Close Price and EMA with Entries and Exits') plt.legend()

# MACD and Signal Line plt.subplot(3, 1, 2) plt.plot(data['MACD'], label='MACD', color='green') plt.plot(data['MACDSignal'], label='MACD Signal', color='red') plt.title('MACD and Signal Line') plt.legend()

# RSI plt.subplot(3, 1, 3) plt.plot(data['RSI'], label='RSI', color='purple') plt.axhline(y=50, color='gray', linestyle='--') plt.title('RSI') plt.legend()

plt.tight_layout() plt.show()

# Portfolio Value over Time plt.figure(figsize=(14, 7)) plt.plot(data['PortfolioValue'], label='Portfolio Value') plt.title('Portfolio Value Over Time') plt.legend() plt.show()

# Drawdown over Time data['Drawdown'] = (data['PortfolioValue'].cummax() - data['PortfolioValue']) / data['PortfolioValue'].cummax() plt.figure(figsize=(14, 7)) plt.plot(data['Drawdown'], label='Drawdown') plt.title('Drawdown Over Time') plt.legend() plt.show()

# Equity curve plt.figure(figsize=(14, 7)) plt.plot(data['PortfolioValue'], label='Portfolio Value') plt.scatter(data.index[data['LongEntry']], data['PortfolioValue'][data['LongEntry']], marker='^', color='green', label='Long Entry') plt.scatter(data.index[data['ShortEntry']], data['PortfolioValue'][data['ShortEntry']], marker='v', color='red', label='Short Entry') plt.scatter(data.index[data['LongExit']], data['PortfolioValue'][data['LongExit']], marker='o', color='green', label='Long Exit') plt.scatter(data.index[data['ShortExit']], data['PortfolioValue'][data['ShortExit']], marker='o', color='red', label='Short Exit') plt.title('Equity Curve with Entries and Exits') plt.legend() plt.show()

Explanation of the Enhanced Code

Data Retrieval: - The ccxt library is employed to obtain historical OHLCV (Open, High, Low, Close, Volume) data from Binance. This data is converted into a pandas DataFrame and indexed by timestamp.

Indicator Calculation: - EMA: Computed using the ewm method from pandas with a span of 200. - RSI: Calculated using rolling windows for gains and losses, followed by applying the RSI formula. - MACD: Determined by subtracting the 26-period EMA from the 12-period EMA, with the signal line being the 9-period EMA of the MACD line.

Trading Signals: - LongEntry: True when the MACD exceeds the signal line, the RSI is above 50, and the price surpasses the 200-day EMA. - ShortEntry: True when the MACD is below the signal line, the RSI is under 50, and the price is below the 200-day EMA. - LongExit: True when any long entry conditions are no longer satisfied. - ShortExit: True when any short entry conditions are no longer satisfied.

Strategy Implementation: - Positions and portfolio values are initialized, and the data is iterated through to implement trading rules. The portfolio value is adjusted based on returns linked to the position and daily returns.

Performance Metrics: - Total Return: Final portfolio value minus the initial investment. - Annualized Return: Calculated by annualizing the total return over the specified period. - CAGR: Compound Annual Growth Rate. - Max Drawdown: Maximum observed loss from peak to trough. - Sharpe Ratio: A measure of risk-adjusted return. - Volatility: Standard deviation of the strategy’s returns, annualized.

Visualization: - Various plots are generated, including close price with EMA and trading signals, MACD with its signal line, RSI, portfolio value, drawdown, and equity curve with entry and exit points.

This thorough implementation not only executes the trading strategy but also provides extensive analysis and visualizations to assist traders in understanding its performance and effectiveness.

Results:

Total Return: 287555.10 Annualized Return: 97.93% CAGR: 97.93% Max Drawdown: 34.64% Sharpe Ratio: 1.55 Volatility: 52.76% Number of Trades: 21

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

The Future of Aviation: Heart Aerospace's Game-Changing ES-19

Heart Aerospace's ES-19 electric plane could revolutionize short and medium-haul flights, significantly reducing aviation's carbon footprint.

The Impending Climate Catastrophe: A Call to Action

A dire warning about climate tipping points and the need for urgent action to mitigate irreversible damage to our planet.

# Crafting a Comprehensive Competitor Analysis Framework

Explore the importance of competitor market mapping for product managers, including insights into revenue, funding, and more.

Navigating His Thoughts: Understanding His Mind Post-Breakup

Learn how a man's thoughts about you change over time after a breakup, from initial distancing to eventual moving on.

The Enigmatic Creation of the Great Sphinx: Unraveling History

Discover the mysteries surrounding the Great Sphinx of Giza, its origins, and its historical significance.

Mastering Stock Trading as a Programmer: A Comprehensive Guide

Learn how to leverage your programming skills to excel in stock trading and automate your processes for success.

How Breathing Influences Our Mind, Body, and Consciousness

Discover how breathing patterns affect mental states, memory, and emotional well-being, and the significance of conscious breathing.

The Misguided Notions of Writing Guidance: Avoiding Bad Advice

Discover the pitfalls of common writing advice and explore better alternatives for aspiring authors.