Cryptocurrency Analysis with Python — MACD

Cryptocurrency Analysis with Python — MACDRoman OracBlockedUnblockFollowFollowingFeb 24I’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.

Note that there already exists tools for performing this kind of analysis, eg.

tradeview, but this way enables more in-depth analysis.

DisclaimerI 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.

RequirementsPython 3Jupyter NotebookPandas Data Analysis LibraryBokeh interactive visualization librarystock Statistics/Indicators Calculation HelperGetting cryptocurrency dataWe 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 requestsfrom datetime import datetimedef 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 datadef 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 dfdef filter_empty_datapoints(df): indices = df[df.

sum(axis=1) == 0].

index print('Filtering %d empty datapoints' % indices.

shape) df = df.

drop(indices) return dfdata = 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 dataWe read the data from a file so we don’t need to download it again.

import pandas as pddef 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 dfdf = read_dataset(filename)Trading strategyA 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 strategyWe use stockstats package to calculate MACD.

from stockstats import StockDataFramedf = StockDataFrame.

retype(df)df['macd'] = df.

get('macd') # calculate MACDstockstats 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.

Visualizing trading strategyWe 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 pifrom bokeh.

plotting import figure, show, output_notebook, output_fileoutput_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 msdf_limit = df[datetime_from: datetime_to].

copy()inc = df_limit.

close > df_limit.

opendec = df_limit.

open > df_limit.

closetitle = '%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 strategyp.

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 candlestickscandlestick_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.