Skip to content

Instantly share code, notes, and snippets.

@bretton
Last active August 8, 2020 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bretton/b81b33fe9aefb9549baec25af462631d to your computer and use it in GitHub Desktop.
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
#!/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()
#!/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"))
@bretton
Copy link
Author

bretton commented Aug 8, 2020

newer file is Bitmex price chart using UDF datasource, with Python and Plotly for chart, with 4H bbands, but no volume charts yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment