Skip to content

Instantly share code, notes, and snippets.

@whittlem
Last active November 17, 2020 16:54
Show Gist options
  • Save whittlem/78ddbe8b0153bcdab4a67e66a524858f to your computer and use it in GitHub Desktop.
Save whittlem/78ddbe8b0153bcdab4a67e66a524858f to your computer and use it in GitHub Desktop.
Trading using Python — Exponential Moving Average (EMA)
# https://levelup.gitconnected.com/trading-using-python-exponential-moving-average-ema-f38ed3211a44?source=your_stories_page-------------------------------------
import re
import requests
from datetime import datetime
def cbpGetHistoricRates(market='BTC-GBP', granularity=86400, iso8601start='', iso8601end=''):
if not isinstance(market, str):
raise Exception('Market string input expected')
if not isinstance(granularity, int):
raise Exception('Granularity integer input expected')
granularity_options = [60, 300, 900, 3600, 21600, 86400]
if not granularity in granularity_options:
raise Exception(
'Invalid granularity: 60, 300, 900, 3600, 21600, 86400')
if not isinstance(iso8601start, str):
raise Exception('ISO8601 date string input expected')
if not isinstance(iso8601end, str):
raise Exception('ISO8601 date string input expected')
# iso8601 regex
regex = r'^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$'
if len(iso8601start) < 0:
match_iso8601 = re.compile(regex).match
if match_iso8601(iso8601start) is None:
raise Exception('iso8601 start date is invalid')
if len(iso8601end) < 0:
match_iso8601 = re.compile(regex).match
if match_iso8601(iso8601end) is None:
raise Exception('iso8601 end date is invalid')
api = 'https://api.pro.coinbase.com/products/' + market + '/candles?granularity=' + \
str(granularity) + '&start=' + iso8601start + '&end=' + iso8601end
resp = requests.get(api)
if resp.status_code != 200:
raise Exception('GET ' + api + ' {}'.format(resp.status_code))
data = {}
for price in reversed(resp.json()):
# time, low, high, open, close, volume
iso8601 = datetime.fromtimestamp(price[0])
timestamp = datetime.strftime(iso8601, "%d/%m/%Y %H:%M:%S")
data[timestamp] = price[4]
return data
# data: dictionary { 'dd/mm/yyy': price, 'dd/mm/yyyy': price, ... }
# num: range in the average calculation, normally 9 to 26
def exponentialMovingAverage(data, num):
if not isinstance(data, dict):
raise Exception('Dictionary input expected')
if not isinstance(num, int):
raise Exception('Integer input expected')
if num < 9 or num > 26:
raise Exception('Unusual numeric input detected')
if (num > len(data)):
raise Exception('Insufficient data for calculation')
data_keys = list(data.keys())
data_list = list(data.values())
last_sma = -1
result = {}
for x in range(len(data_list) - num + 1):
series = data_list[x:x + num]
if (last_sma == -1):
result[data_keys[x + num - 1]] = round((sum(series) / num), 2)
else:
current_price = data[data_keys[x + num - 1]]
result[data_keys[x + num - 1]] = round(
current_price * 2 / (num + 1) + last_sma * (1 - 2 / (num + 1)), 2)
last_sma = result[data_keys[x + num - 1]]
return result
data = cbpGetHistoricRates('BTC-GBP', 86400)
ema12 = exponentialMovingAverage(data, 12)
ema26 = exponentialMovingAverage(data, 26)
def csvResults():
print('date,price,ema12,ema26')
data_keys = list(data.keys())
for key in data_keys:
price = 0
if key in data:
price = data[key]
ema12r = 0
if key in ema12:
ema12r = ema12[key]
ema26r = 0
if key in ema26:
ema26r = ema26[key]
if ema26r != 0:
print(key + ',' + str(price) + ',' +
str(ema12r) + ',' + str(ema26r))
csvResults()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment