Last active
August 8, 2020 17:53
-
-
Save bretton/b81b33fe9aefb9549baec25af462631d to your computer and use it in GitHub Desktop.
Bitmex price and volume chart using UDF datasource, with Python and Bokeh for chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# coding=utf-8 | |
# | |
# Dev Log | |
# bitmex-plotinit-plotly.py | |
# ======= | |
# 2020-07-19 - setup script to pull data from Bitmex UDF and create candles and highlights | |
# - intent is for a base script I can re-run to highlight specific things | |
# 2020-08-08 - switching to a different chart library | |
# | |
########################## | |
import os | |
import sys | |
import time | |
import datetime as dt | |
import json | |
import requests | |
import pandas as df | |
import numpy as np | |
import matplotlib.pyplot as plt | |
from plotly.subplots import make_subplots | |
import plotly.graph_objects as go | |
# debug to true or false | |
debug = "true" | |
showchart = "true" | |
# we need today to determine yesterday because we need to get OHLC until yesterday | |
today = dt.date.today() | |
yesterday = today - dt.timedelta(days=1) | |
# need start and end date in YYYY-MM-DD format | |
myStartDate = dt.datetime(2020, 1, 1, 0, 0).strftime('%Y-%m-%d') | |
#myEndDate = dt.datetime(2020, 8, 8, 0, 0).strftime('%Y-%m-%d') | |
myEndDate = today.strftime('%Y-%m-%d') | |
# price range, set to relevant figures for range being displayed | |
priceLow = 2000 | |
priceHigh = 14000 | |
# the Bitmex UDF response with OHLC is limited to 10080 replies and won't accept resolution of 1d, only 60, | |
# we'll create epochs and call in the data for each year, appending to the data frame each time | |
# earliest record for an hourly candle appears to be epoch datetime 1443182400 | |
# this is GMT: Friday, September 25, 2015 12:00:00 PM | |
# period2015 will return ~30k rows from 25 Sept to 31 December 2015 | |
# 2015 | |
period2015Start = dt.datetime(2015, 9, 25, 0, 0).strftime('%s') | |
period2015End = dt.datetime(2015, 12, 31, 11, 59).strftime('%s') | |
period2015Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2015Start+"&to="+period2015End).json() | |
period2015Array = df.DataFrame(period2015Request) | |
# 2016 | |
period2016Start = dt.datetime(2016, 1, 1, 0, 0).strftime('%s') | |
period2016End = dt.datetime(2016, 12, 31, 11, 59).strftime('%s') | |
period2016Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2016Start+"&to="+period2016End).json() | |
period2016Array = df.DataFrame(period2016Request) | |
# 2017 | |
period2017Start = dt.datetime(2017, 1, 1, 0, 0).strftime('%s') | |
period2017End = dt.datetime(2017, 12, 31, 11, 59).strftime('%s') | |
period2017Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2017Start+"&to="+period2017End).json() | |
period2017Array = df.DataFrame(period2017Request) | |
# 2018 | |
period2018Start = dt.datetime(2018, 1, 1, 0, 0).strftime('%s') | |
period2018End = dt.datetime(2018, 12, 31, 11, 59).strftime('%s') | |
period2018Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2018Start+"&to="+period2018End).json() | |
period2018Array = df.DataFrame(period2018Request) | |
# 2019 | |
period2019Start = dt.datetime(2019, 1, 1, 0, 0).strftime('%s') | |
period2019End = dt.datetime(2019, 12, 31, 11, 59).strftime('%s') | |
period2019Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2019Start+"&to="+period2019End).json() | |
period2019Array = df.DataFrame(period2019Request) | |
# 2020 | |
period2020Start = dt.datetime(2020, 1, 1, 0, 0).strftime('%s') | |
# set to yesterday date, keeping manual for history purposes | |
#period2020End = dt.datetime(2020, 7, 17, 11, 59).strftime('%s') | |
#period2020End = yesterday.strftime('%s') | |
# 2020-08-08: setting to today | |
period2020End = today.strftime('%s') | |
period2020Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2020Start+"&to="+period2020End).json() | |
period2020Array = df.DataFrame(period2020Request) | |
# 2021 prep | |
#period2021Start = dt.datetime(2021, 1, 1, 0, 0).strftime('%s') | |
# set to yesterday date, keeping manual for history purposes | |
#period2021End = yesterday.strftime('%s') | |
#period2021Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2021Start+"&to="+period2021End).json() | |
#period2021Array = df.DataFrame(period2021Request) | |
# then we combined all the dataframes into an array of annual dataframes | |
##2021 prep, add period2021Array | |
myBigArray = [period2015Array, period2016Array, period2017Array, period2018Array, period2019Array, period2020Array] | |
# concat the dataframes, with ignore_index=True, so we get all rows | |
myCombinedResult = df.concat(myBigArray, axis=0, join='outer', ignore_index=True, keys=None, levels=None, names=None, verify_integrity=False, copy=True) | |
# remove the http ok 200 status column | |
del myCombinedResult['s'] | |
# set the column headings | |
myCombinedResult.columns = ["datetime", "close", "open", "high", "low", "volume"] | |
myCombinedResult = myCombinedResult[["datetime", "open", "high", "low", "close", "volume"]] | |
# convert the datetime column into a datetime dtype | |
myCombinedResult["datetime"] = df.to_datetime(myCombinedResult["datetime"], errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit='s', infer_datetime_format=False, origin='unix', cache=True) | |
# set the datetime to an index | |
myCombinedResult.set_index(["datetime"], drop=True, append=False, inplace=True, verify_integrity=False) | |
# resample hourly to daily | |
# myCombinedResult = myCombinedResult.resample('1440Min', axis=0).bfill() | |
# resample to 4 hours | |
myFourHourResult = myCombinedResult.resample('240Min', axis=0).bfill() | |
# Calculate Bollinger Bands | |
# https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands | |
# Middle Band = 20-day simple moving average (SMA) | |
# Upper Band = 20-day SMA + (20-day standard deviation of price x 2) | |
# Lower Band = 20-day SMA - (20-day standard deviation of price x 2) | |
myFourHourResult["BBSMA"] = myFourHourResult["close"].rolling(window=20).mean() | |
myFourHourResult["BBSTD"] = myFourHourResult["close"].rolling(window=20).std() | |
myFourHourResult["BBUPPER"] = myFourHourResult["BBSMA"] + (myFourHourResult["BBSTD"] * 2) | |
myFourHourResult["BBLOWER"] = myFourHourResult["BBSMA"] - (myFourHourResult["BBSTD"] * 2) | |
# if the debug variable is true, print out some debug info | |
if debug == "true": | |
print(myCombinedResult) | |
print(myFourHourResult) | |
print(myStartDate) | |
print(myEndDate) | |
# if the showchart variable is true, plot a chart and open in browser | |
if showchart == "true": | |
fig = go.Figure() | |
fig.add_trace(go.Candlestick(x=myCombinedResult.index, | |
open=myCombinedResult["open"], | |
high=myCombinedResult["high"], | |
low=myCombinedResult["low"], | |
close=myCombinedResult["close"])) | |
fig.add_trace(go.Scatter( | |
x=myFourHourResult.index, | |
y=myFourHourResult["BBUPPER"], | |
name="upper bband", | |
line_color='red', | |
opacity=0.5)) | |
fig.update_layout(xaxis_rangeslider_visible=False) | |
fig.update_layout(xaxis_range=[myStartDate,myEndDate],title_text="Bitmex price versus 4h upper bband with date range limited to selected time period") | |
fig.update_layout(yaxis_range=[priceLow,priceHigh]) | |
fig.show() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# coding=utf-8 | |
# | |
# Dev Log | |
# plotinit.py | |
# ======= | |
# 2020-07-19 - setup script to pull data from Bitmex UDF and create candles and highlights | |
# - intent is for a base script I can re-run to highlight specific things | |
# | |
########################## | |
import os | |
import sys | |
import time | |
import datetime as dt | |
import json | |
import requests | |
import pandas as df | |
from bokeh.layouts import column | |
from bokeh.plotting import figure, show, output_file | |
# debug to true or false | |
debug = "true" | |
showchart = "true" | |
# we need today to determine yesterday because we need to get OHLC until yesterday | |
today = dt.date.today() | |
yesterday = today - dt.timedelta(days=1) | |
# the Bitmex UDF response with OHLC is limited to 10080 replies and won't accept resolution of 1d, only 60, | |
# we'll create epochs and call in the data for each year, appending to the data frame each time | |
# earliest record for an hourly candle appears to be epoch datetime 1443182400 | |
# this is GMT: Friday, September 25, 2015 12:00:00 PM | |
# period2015 will return ~30k rows from 25 Sept to 31 December 2015 | |
# 2015 | |
period2015Start = dt.datetime(2015, 9, 25, 0, 0).strftime('%s') | |
period2015End = dt.datetime(2015, 12, 31, 11, 59).strftime('%s') | |
period2015Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2015Start+"&to="+period2015End).json() | |
period2015Array = df.DataFrame(period2015Request) | |
# 2016 | |
period2016Start = dt.datetime(2016, 1, 1, 0, 0).strftime('%s') | |
period2016End = dt.datetime(2016, 12, 31, 11, 59).strftime('%s') | |
period2016Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2016Start+"&to="+period2016End).json() | |
period2016Array = df.DataFrame(period2016Request) | |
# 2017 | |
period2017Start = dt.datetime(2017, 1, 1, 0, 0).strftime('%s') | |
period2017End = dt.datetime(2017, 12, 31, 11, 59).strftime('%s') | |
period2017Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2017Start+"&to="+period2017End).json() | |
period2017Array = df.DataFrame(period2017Request) | |
# 2018 | |
period2018Start = dt.datetime(2018, 1, 1, 0, 0).strftime('%s') | |
period2018End = dt.datetime(2018, 12, 31, 11, 59).strftime('%s') | |
period2018Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2018Start+"&to="+period2018End).json() | |
period2018Array = df.DataFrame(period2018Request) | |
# 2019 | |
period2019Start = dt.datetime(2019, 1, 1, 0, 0).strftime('%s') | |
period2019End = dt.datetime(2019, 12, 31, 11, 59).strftime('%s') | |
period2019Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2019Start+"&to="+period2019End).json() | |
period2019Array = df.DataFrame(period2019Request) | |
# 2020 | |
period2020Start = dt.datetime(2020, 1, 1, 0, 0).strftime('%s') | |
# set to yesterday date, keeping manual for history purposes | |
#period2020End = dt.datetime(2020, 7, 17, 11, 59).strftime('%s') | |
period2020End = yesterday.strftime('%s') | |
period2020Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2020Start+"&to="+period2020End).json() | |
period2020Array = df.DataFrame(period2020Request) | |
# 2021 prep | |
#period2021Start = dt.datetime(2021, 1, 1, 0, 0).strftime('%s') | |
# set to yesterday date, keeping manual for history purposes | |
#period2021End = yesterday.strftime('%s') | |
#period2021Request = requests.get("https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=60&from="+period2021Start+"&to="+period2021End).json() | |
#period2021Array = df.DataFrame(period2021Request) | |
# then we combined all the dataframes into an array of annual dataframes | |
##2021 prep, add period2021Array | |
myBigArray = [period2015Array, period2016Array, period2017Array, period2018Array, period2019Array, period2020Array] | |
# concat the dataframes, with ignore_index=True, so we get all rows | |
myCombinedResult = df.concat(myBigArray, axis=0, join='outer', ignore_index=True, keys=None, levels=None, names=None, verify_integrity=False, copy=True) | |
# remove the http ok 200 status column | |
del myCombinedResult['s'] | |
# set the column headings | |
myCombinedResult.columns = ["datetime", "close", "open", "high", "low", "volume"] | |
myCombinedResult = myCombinedResult[["datetime", "open", "high", "low", "close", "volume"]] | |
# convert the datetime column into a datetime dtype | |
myCombinedResult["datetime"] = df.to_datetime(myCombinedResult["datetime"], errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit='s', infer_datetime_format=False, origin='unix', cache=True) | |
# set the datetime to an index | |
myCombinedResult.set_index(["datetime"], drop=True, append=False, inplace=True, verify_integrity=False) | |
# resample hourly to daily | |
# myCombinedResult = myCombinedResult.resample('1440Min', axis=0).bfill() | |
# resample to 4 hours | |
# myCombinedResult = myCombinedResult.resample('240Min', axis=0).bfill() | |
# if the debug variable is true, print out some debug info | |
if debug == "true": | |
print(myCombinedResult) | |
# is the shotchart variable is true, plot a chart and open in browser | |
if showchart == "true": | |
# plot results | |
# w = 1*60*60*1000 # 1h in ms | |
w = 24*60*60*1000 # 1d in ms | |
chartTools = "pan,wheel_zoom,box_zoom,reset,save" | |
# price chart | |
pricechart = figure(x_axis_type="datetime", tools=chartTools, plot_width=1400, title = "Bitmex XBTUSD - Title Goes Here", output_backend="webgl", sizing_mode="fixed") | |
pricechart.grid.grid_line_alpha=0.3 | |
# add price line from close | |
pricechart.line(x = 'datetime', y = 'close', source = myCombinedResult, color = 'black', line_width = 1) | |
# configure visual properties on a plot's title attribute | |
pricechart.title.align = "center" | |
pricechart.title.text_color = "black" | |
pricechart.title.text_font_size = "30px" | |
# volume chart - use a bar chart to show volume | |
volchart = figure(x_axis_type="datetime", tools=chartTools, plot_height=100, title = "Bitmex XBTUSD daily trade volumes", output_backend="webgl", sizing_mode="scale_width") | |
volchart.vbar(x = 'datetime', top = 'volume', source = myCombinedResult, width = w, color = "pink") | |
volchart.grid.grid_line_alpha=0.3 | |
volchart.title.align = "center" | |
volchart.title.text_color = "black" | |
volchart.title.text_font_size = "18px" | |
# save to file | |
output_file("report.html", title="Title Goes Here") | |
# open a browser | |
show(column(pricechart,volchart,sizing_mode="scale_height")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
newer file is Bitmex price chart using UDF datasource, with Python and Plotly for chart, with 4H bbands, but no volume charts yet.