The world’s leading publication for data science, AI, and ML professionals.

Cryptocurrency Analysis with Python – MACD

Apply a simple trading strategy to cryptocurrency data

Photo by Thought Catalog on Unsplash
Photo by Thought Catalog on Unsplash

I’ve decided to spend the weekend learning about Cryptocurrency analysis. I’ve hacked together the code to download daily Bitcoin prices and apply a simple trading strategy to it.

In case you’ve missed my other articles about this topic:

Stock Market Analysis in Python

Tradingeview

There already exist tools for performing this kind of analysis, eg. tradingview, but doing this analysis in Python enables more in-depth analysis.

Interactive plot showing Bitcoin price
Interactive plot showing Bitcoin price

Disclaimer

I am not a trader and this blog post is not financial advice. This is purely introductory knowledge. The conclusion here can be misleading as we analyze the time period with immense growth.

Requirements

Getting cryptocurrency data

We download daily Bitcoin data in USD on Bitstamp exchange. Other exchanges are also supported.

from_symbol = 'BTC'
to_symbol = 'USD'
exchange = 'Bitstamp'
datetime_interval = 'day'

The cryptocompare API returns the following columns:

  • open, the price at which the period opened,
  • high, the highest price reached during the period,
  • low, the lowest price reached during the period,
  • close, the price at which the period closed,
  • volumefrom, the volume in the base currency that things are traded into,
  • volumeto, the volume in the currency that is being traded.

We download the data and store it to a file.

import requests
from datetime import datetime
def get_filename(from_symbol, to_symbol, exchange, datetime_interval, download_date):
    return '%s_%s_%s_%s_%s.csv' % (from_symbol, to_symbol, exchange, datetime_interval, download_date)
def download_data(from_symbol, to_symbol, exchange, datetime_interval):
    supported_intervals = {'minute', 'hour', 'day'}
    assert datetime_interval in supported_intervals,
        'datetime_interval should be one of %s' % supported_intervals
    print('Downloading %s trading data for %s %s from %s' %
          (datetime_interval, from_symbol, to_symbol, exchange))
    base_url = 'https://min-api.cryptocompare.com/data/histo'
    url = '%s%s' % (base_url, datetime_interval)
    params = {'fsym': from_symbol, 'tsym': to_symbol,
              'limit': 2000, 'aggregate': 1,
              'e': exchange}
    request = requests.get(url, params=params)
    data = request.json()
    return data
def convert_to_dataframe(data):
    df = pd.io.json.json_normalize(data, ['Data'])
    df['datetime'] = pd.to_datetime(df.time, unit='s')
    df = df[['datetime', 'low', 'high', 'open',
             'close', 'volumefrom', 'volumeto']]
    return df
def filter_empty_datapoints(df):
    indices = df[df.sum(axis=1) == 0].index
    print('Filtering %d empty datapoints' % indices.shape[0])
    df = df.drop(indices)
    return df
data = download_data(from_symbol, to_symbol, exchange, datetime_interval)
df = convert_to_dataframe(data)
df = filter_empty_datapoints(df)
current_datetime = datetime.now().date().isoformat()
filename = get_filename(from_symbol, to_symbol, exchange, datetime_interval, current_datetime)
print('Saving data to %s' % filename)
df.to_csv(filename, index=False)

Read the data

We read the data from a file so we don’t need to download it again.

import pandas as pd
def read_dataset(filename):
    print('Reading data from %s' % filename)
    df = pd.read_csv(filename)
    # change type from object to datetime
    df.datetime = pd.to_datetime(df.datetime) 
    df = df.set_index('datetime') 
    df = df.sort_index() # sort by datetime
    print(df.shape)
    return df
df = read_dataset(filename)

Trading strategy

A trading strategy is a set of objective rules defining the conditions that must be met for trade entry and exit to occur.

We are going to apply Moving Average Convergence Divergence (MACD) trading strategy, which is a popular indicator used in technical analysis. MACD calculates two moving averages of varying lengths to identify trend direction and duration. Then, it takes the difference in values between those two moving averages (MACD line) and an exponential moving average (signal line) of those moving averages. Tradeview has a great blog post about MACD.

As we can see in the example below:

  • exit trade (sell) when MACD line crosses below the MACD signal line,
  • enter the trade (buy) when MACD line crosses above the MACD signal line.

Calculate the trading strategy

We use stockstats package to calculate MACD.

from stockstats import StockDataFrame
df = StockDataFrame.retype(df)
df['macd'] = df.get('macd') # calculate MACD

stockstats adds 5 columns to the dataset:

  • close_12_ema is fast 12 days exponential moving average,
  • close_26_ema is slow 26 days exponential moving average,
  • macd is MACD line,
  • macds is the signal line,
  • macdh is MACD histogram.
Few entries in the dataset.
Few entries in the dataset.

Visualizing trading strategy

We use bokeh interactive charts to plot the data.

The line graph shows daily closing prices with candlesticks (zoom in). A candlestick displays the high, low, opening and closing prices for a specific period. Tradeview has a great blog post about candlestick graph.

Below the line graph, we plot the MACD strategy with the MACD line (blue), a signal line (orange) and histogram (purple).

from math import pi
from bokeh.plotting import figure, show, output_notebook, output_file
output_notebook()
datetime_from = '2016-01-01 00:00'
datetime_to = '2017-12-10 00:00'
def get_candlestick_width(datetime_interval):
    if datetime_interval == 'minute':
        return 30 * 60 * 1000  # half minute in ms
    elif datetime_interval == 'hour':
        return 0.5 * 60 * 60 * 1000  # half hour in ms
    elif datetime_interval == 'day':
        return 12 * 60 * 60 * 1000  # half day in ms
df_limit = df[datetime_from: datetime_to].copy()
inc = df_limit.close > df_limit.open
dec = df_limit.open > df_limit.close
title = '%s datapoints from %s to %s for %s and %s from %s with MACD strategy' % (
    datetime_interval, datetime_from, datetime_to, from_symbol, to_symbol, exchange)
p = figure(x_axis_type="datetime",  plot_width=1000, title=title)
p.line(df_limit.index, df_limit.close, color='black')
# plot macd strategy
p.line(df_limit.index, 0, color='black')
p.line(df_limit.index, df_limit.macd, color='blue')
p.line(df_limit.index, df_limit.macds, color='orange')
p.vbar(x=df_limit.index, bottom=[
       0 for _ in df_limit.index], top=df_limit.macdh, width=4, color="purple")
# plot candlesticks
candlestick_width = get_candlestick_width(datetime_interval)
p.segment(df_limit.index, df_limit.high,
          df_limit.index, df_limit.low, color="black")
p.vbar(df_limit.index[inc], candlestick_width, df_limit.open[inc],
       df_limit.close[inc], fill_color="#D5E1DD", line_color="black")
p.vbar(df_limit.index[dec], candlestick_width, df_limit.open[dec],
       df_limit.close[dec], fill_color="#F2583E", line_color="black")
output_file("visualizing_trading_strategy.html", title="visualizing trading strategy")
show(p)

Let’s connect

Talk: Book a call Socials: YouTube 🎥 | LinkedIn | Twitter Code: GitHub


Related Articles