Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Does plotting a live/animated chart work?

    General Code/Help
    4
    6
    1095
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • RandyT
      RandyT last edited by

      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()?

      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

        No, live plotting is not there.

        1 Reply Last reply Reply Quote 0
        • mics
          mics last edited by

          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)
          1 Reply Last reply Reply Quote 0
          • run-out
            run-out last edited by

            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.

            mics 1 Reply Last reply Reply Quote 1
            • mics
              mics @run-out last edited by

              @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

              run-out 1 Reply Last reply Reply Quote 0
              • run-out
                run-out @mics last edited by

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

                1 Reply Last reply Reply Quote 0
                • 1 / 1
                • First post
                  Last post
                Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                $(document).ready(function () { app.coldLoad(); }); }