Does plotting a live/animated chart work?
-
If I
plot()
in a system with live data, should I expect to see an animated matplotlib chart?If so, anything special I need to provide in the call to
cerebro.plot()
? -
No, live plotting is not there.
-
I see that this post is a few years old, however, I've been trying to get live plotting to work. Cerebro is not the answer.
A programmer (sendex) has previously created live stock plotting, however, this is back in the day when Yahoo finance was available. Here is his post:
https://pythonprogramming.net/advanced-matplotlib-graphing-charting-tutorial/Does anyone have the skills to alter this code so that it draws data from stores like Interactive Brokers or OANDA, while still being able to leverage Backtrader for analysis?
As far as I can tell the following section needs editing...
def graphData(stock,MA1,MA2): #Use this to dynamically pull a stock: try: print('Currently Pulling',stock) urlToVisit = 'http://chartapi.finance.yahoo.com/instrument/1.0/'+stock+'/chartdata;type=quote;range=10y/csv' stockFile =[] try: sourceCode = urllib.request.urlopen(urlToVisit).read().decode() splitSource = sourceCode.split('\n') for eachLine in splitSource: splitLine = eachLine.split(',') if len(splitLine)==6: if 'values' not in eachLine: stockFile.append(eachLine) except Exception as e: print(str(e), 'failed to organize pulled data.') except Exception as e: print(str(e), 'failed to pull pricing data') try: date, closep, highp, lowp, openp, volume = np.loadtxt(stockFile,delimiter=',', unpack=True, converters={ 0: bytespdate2num('%Y%m%d')})
FULL CODE (BY SENDEX) HERE:
# THIS VERSION IS FOR PYTHON 3 # import urllib.request, urllib.error, urllib.parse import time import datetime import numpy as np import matplotlib.pyplot as plt import matplotlib.ticker as mticker import matplotlib.dates as mdates from matplotlib.finance import candlestick_ohlc import matplotlib import pylab matplotlib.rcParams.update({'font.size': 9}) def rsiFunc(prices, n=14): deltas = np.diff(prices) seed = deltas[:n+1] up = seed[seed>=0].sum()/n down = -seed[seed<0].sum()/n rs = up/down rsi = np.zeros_like(prices) rsi[:n] = 100. - 100./(1.+rs) for i in range(n, len(prices)): delta = deltas[i-1] # cause the diff is 1 shorter if delta>0: upval = delta downval = 0. else: upval = 0. downval = -delta up = (up*(n-1) + upval)/n down = (down*(n-1) + downval)/n rs = up/down rsi[i] = 100. - 100./(1.+rs) return rsi def movingaverage(values,window): weigths = np.repeat(1.0, window)/window smas = np.convolve(values, weigths, 'valid') return smas # as a numpy array def ExpMovingAverage(values, window): weights = np.exp(np.linspace(-1., 0., window)) weights /= weights.sum() a = np.convolve(values, weights, mode='full')[:len(values)] a[:window] = a[window] return a def computeMACD(x, slow=26, fast=12): """ compute the MACD (Moving Average Convergence/Divergence) using a fast and slow exponential moving avg' return value is emaslow, emafast, macd which are len(x) arrays """ emaslow = ExpMovingAverage(x, slow) emafast = ExpMovingAverage(x, fast) return emaslow, emafast, emafast - emaslow def bytespdate2num(fmt, encoding='utf-8'): strconverter = mdates.strpdate2num(fmt) def bytesconverter(b): s = b.decode(encoding) return strconverter(s) return bytesconverter def graphData(stock,MA1,MA2): ''' Use this to dynamically pull a stock: ''' try: print('Currently Pulling',stock) urlToVisit = 'http://chartapi.finance.yahoo.com/instrument/1.0/'+stock+'/chartdata;type=quote;range=10y/csv' stockFile =[] try: sourceCode = urllib.request.urlopen(urlToVisit).read().decode() splitSource = sourceCode.split('\n') for eachLine in splitSource: splitLine = eachLine.split(',') if len(splitLine)==6: if 'values' not in eachLine: stockFile.append(eachLine) except Exception as e: print(str(e), 'failed to organize pulled data.') except Exception as e: print(str(e), 'failed to pull pricing data') try: date, closep, highp, lowp, openp, volume = np.loadtxt(stockFile,delimiter=',', unpack=True, converters={ 0: bytespdate2num('%Y%m%d')}) x = 0 y = len(date) newAr = [] while x < y: appendLine = date[x],openp[x],highp[x],lowp[x],closep[x],volume[x] newAr.append(appendLine) x+=1 Av1 = movingaverage(closep, MA1) Av2 = movingaverage(closep, MA2) SP = len(date[MA2-1:]) fig = plt.figure(facecolor='#07000d') ax1 = plt.subplot2grid((6,4), (1,0), rowspan=4, colspan=4, axisbg='#07000d') candlestick_ohlc(ax1, newAr[-SP:], width=.6, colorup='#53c156', colordown='#ff1717') Label1 = str(MA1)+' SMA' Label2 = str(MA2)+' SMA' ax1.plot(date[-SP:],Av1[-SP:],'#e1edf9',label=Label1, linewidth=1.5) ax1.plot(date[-SP:],Av2[-SP:],'#4ee6fd',label=Label2, linewidth=1.5) ax1.grid(True, color='w') ax1.xaxis.set_major_locator(mticker.MaxNLocator(10)) ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) ax1.yaxis.label.set_color("w") ax1.spines['bottom'].set_color("#5998ff") ax1.spines['top'].set_color("#5998ff") ax1.spines['left'].set_color("#5998ff") ax1.spines['right'].set_color("#5998ff") ax1.tick_params(axis='y', colors='w') plt.gca().yaxis.set_major_locator(mticker.MaxNLocator(prune='upper')) ax1.tick_params(axis='x', colors='w') plt.ylabel('Stock price and Volume') maLeg = plt.legend(loc=9, ncol=2, prop={'size':7}, fancybox=True, borderaxespad=0.) maLeg.get_frame().set_alpha(0.4) textEd = pylab.gca().get_legend().get_texts() pylab.setp(textEd[0:5], color = 'w') volumeMin = 0 ax0 = plt.subplot2grid((6,4), (0,0), sharex=ax1, rowspan=1, colspan=4, axisbg='#07000d') rsi = rsiFunc(closep) rsiCol = '#c1f9f7' posCol = '#386d13' negCol = '#8f2020' ax0.plot(date[-SP:], rsi[-SP:], rsiCol, linewidth=1.5) ax0.axhline(70, color=negCol) ax0.axhline(30, color=posCol) ax0.fill_between(date[-SP:], rsi[-SP:], 70, where=(rsi[-SP:]>=70), facecolor=negCol, edgecolor=negCol, alpha=0.5) ax0.fill_between(date[-SP:], rsi[-SP:], 30, where=(rsi[-SP:]<=30), facecolor=posCol, edgecolor=posCol, alpha=0.5) ax0.set_yticks([30,70]) ax0.yaxis.label.set_color("w") ax0.spines['bottom'].set_color("#5998ff") ax0.spines['top'].set_color("#5998ff") ax0.spines['left'].set_color("#5998ff") ax0.spines['right'].set_color("#5998ff") ax0.tick_params(axis='y', colors='w') ax0.tick_params(axis='x', colors='w') plt.ylabel('RSI') ax1v = ax1.twinx() ax1v.fill_between(date[-SP:],volumeMin, volume[-SP:], facecolor='#00ffe8', alpha=.4) ax1v.axes.yaxis.set_ticklabels([]) ax1v.grid(False) ###Edit this to 3, so it's a bit larger ax1v.set_ylim(0, 3*volume.max()) ax1v.spines['bottom'].set_color("#5998ff") ax1v.spines['top'].set_color("#5998ff") ax1v.spines['left'].set_color("#5998ff") ax1v.spines['right'].set_color("#5998ff") ax1v.tick_params(axis='x', colors='w') ax1v.tick_params(axis='y', colors='w') ax2 = plt.subplot2grid((6,4), (5,0), sharex=ax1, rowspan=1, colspan=4, axisbg='#07000d') fillcolor = '#00ffe8' nslow = 26 nfast = 12 nema = 9 emaslow, emafast, macd = computeMACD(closep) ema9 = ExpMovingAverage(macd, nema) ax2.plot(date[-SP:], macd[-SP:], color='#4ee6fd', lw=2) ax2.plot(date[-SP:], ema9[-SP:], color='#e1edf9', lw=1) ax2.fill_between(date[-SP:], macd[-SP:]-ema9[-SP:], 0, alpha=0.5, facecolor=fillcolor, edgecolor=fillcolor) plt.gca().yaxis.set_major_locator(mticker.MaxNLocator(prune='upper')) ax2.spines['bottom'].set_color("#5998ff") ax2.spines['top'].set_color("#5998ff") ax2.spines['left'].set_color("#5998ff") ax2.spines['right'].set_color("#5998ff") ax2.tick_params(axis='x', colors='w') ax2.tick_params(axis='y', colors='w') plt.ylabel('MACD', color='w') ax2.yaxis.set_major_locator(mticker.MaxNLocator(nbins=5, prune='upper')) for label in ax2.xaxis.get_ticklabels(): label.set_rotation(45) plt.suptitle(stock.upper(),color='w') plt.setp(ax0.get_xticklabels(), visible=False) plt.setp(ax1.get_xticklabels(), visible=False) ax1.annotate('Big news!',(date[510],Av1[510]), xytext=(0.8, 0.9), textcoords='axes fraction', arrowprops=dict(facecolor='white', shrink=0.05), fontsize=14, color = 'w', horizontalalignment='right', verticalalignment='bottom') plt.subplots_adjust(left=.09, bottom=.14, right=.94, top=.95, wspace=.20, hspace=0) plt.show() fig.savefig('example.png',facecolor=fig.get_facecolor()) except Exception as e: print('main loop',str(e)) while True: stock = input('Stock to plot: ') graphData(stock,10,50)
-
Sentdex is the best! But you probably have the wrong video. Instead of using matplotlib, you should consider Plotly Dash (or Bokeh, but I don't know that library).
I was/am moving toward building a Dash dashboard but got busy with other things.
If you have a look at how Sentdex builds this live dashboard you will see how it can be done. Now all that needs doing is switching out the plots for stock charts. Live charts can be obtained using yfinance.
Make sure you report back and let us know how your project goes. Good luck.
-
@run-out
Brilliant! Thank you for the tips.Looks like this has opened up far greater opportunities. I'll be sure to report back once there is something successful to report.
Many thanks for the fast response.
M
-
@mics About a year ago I did create a plotly dash dashboard with a chart fed by yfinance/yahoo, but it was updated on a button. Switching that to automated updates should be trivial.