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/

    Real-Time Plotting

    General Discussion
    live data
    5
    10
    2360
    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.
    • mics
      mics last edited by

      Has anyone had success in creating real-time plotting. Cerebro does not appear to be the solution here, however, it appears others have found a way that might leave clues on how to accomplish this.

      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?

      FYI - I would replace the def rsiFunc, def movingaverage, def ExpMovingAverage and def computeMACD with the Backtrader, but before commencing this it would be good to know how to leverage IB or OANDA as the data source.

      Can anyone help?

      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 -1
      • mics
        mics last edited by

        For reference, here is my runstrategy() module that I want to integrate with 'real-time' plotting. It's a modified/integrated version of ibtest.py and iboandav20.py to suit my needs. Works fine with live and historical.

        How could I place real-time plotting into this module, based on the sample code above, or by other means?

        Thank in advance!!

        #!/usr/local/bin/python
        # -*- coding: utf-8 -*-
        from __future__ import (absolute_import, division, print_function,
                                unicode_literals)
        
        #----- IMPORT PACKAGES -----#
        import argparse
        import datetime
        import backtrader as bt
        import backtrader.indicators as btind
        import pytz
        from backtrader import Observer
        from backtrader.utils import flushfile  # win32 quick stdout flushing
        from twilio.rest import Client
        import logging
        from tabulate import tabulate
        import time
        #import numpy as np
        #import matplotlib.pyplot as pyplot
        #----- END -----#
        
        #----- FOLDER DIRECTORY FOR MODULES -----#
        from __modules__.coremodules import __directory__ as directory
        import sys
        sys.path.append(directory.parentfolder)
        #----- END -----#
        
        #----- IMPORT CUSTOM INDICATORS -----#
        from coremodules.start import startcode
        #from indicators.klingerosc import KlingerOSC
        #from indicators.swing import SwingInd
        from args.args import parse_args
        from coremodules.tradeanalysis import TradeAnalysis
        from coremodules.sqn import SQN
        from coremodules.printstrategy import printstrategy
        from observers.buysellplot import BuySellPlot
        from coremodules.plotscheme import PlotScheme
        import actions.sendsms
        
        #----- END -----#
        
        
        #----- OANDA STORE -----#
        args = parse_args()
        
        if args.oanda:
            import btoandav20
            from information.broker_oanda import oandakeys
            
            StoreCls = btoandav20.stores.OandaV20Store
            DataCls = btoandav20.feeds.OandaV20Data
            # BrokerCls = btoandav20.brokers.OandaV20Broker
        
            # available timeframes for oanda
            TIMEFRAMES = [bt.TimeFrame.Names[bt.TimeFrame.Seconds],
                     bt.TimeFrame.Names[bt.TimeFrame.Minutes],
                     bt.TimeFrame.Names[bt.TimeFrame.Days],
                     bt.TimeFrame.Names[bt.TimeFrame.Weeks],
                     bt.TimeFrame.Names[bt.TimeFrame.Months]]
                     
        elif args.ib is not None:
            from information.broker_ib import IBhost
        
            #----- END -----#
        
        def runstrategy():
            args = parse_args()
            
            if args.ib and args.oanda is None:
                print('ERROR: Please select broker: args.oanda or args.ib')
                
        #----- CEREBRO START -----#
            
            if args.optimise:
                cerebro = bt.Cerebro(optreturn=False)
            else:
                cerebro = bt.Cerebro()
            
        #----- PLOT INFO -----#
            
            plotinfo = dict(plot=True,
                 subplot=True,
                 plotname='',
                 plotskip=False,
                 plotabove=False,
                 plotlinelabels=True,
                 plotlinevalues=True,
                 plotvaluetags=True,
                 plotymargin=0.0,
                 plotyhlines=[],
                 plotyticks=[],
                 plothlines=[],
                 plotforce=False,
                 plotmaster=None,
                 plotylimited=True,
            )
        
        #----- SELECT STRATEGY -----#
        
            if args.strategy == 'reversal':
               from strategies.strategy_reversal import TheStrategy as TheStrategy
            elif args.strategy == '3_bar_stack':
               from strategies.strategy_3_bar_stack import TheStrategy as TheStrategy
            elif args.strategy == 'pivotpoint':
               from strategies.strategy_pivotpoint import TheStrategy as TheStrategy
            elif args.strategy == 'bom':
               from strategies.strategy_bom import TheStrategy as TheStrategy
            elif args.strategy == 'bband':
               from strategies.strategy_bband import TheStrategy as TheStrategy
            elif args.strategy == '2wave':
               from strategies.strategy_secondwave import TheStrategy as TheStrategy
        
        #----- LOAD MODULES -----#
        
            def printTradeAnalysis(analyzer):
                return TradeAnalysis(analyzer)
                
            def printSQN(analyzer):          
                return SQN(analyzer)
        
        #----- STORE & BROKER -----#
        
            if args.ib is not None:
                
                if args.usestore:
                    ibstore = bt.stores.IBStore(**IBhost.storekwargs)
        
                if args.broker:
                    if args.usestore:
                        broker = ibstore.getbroker()
                    else:
                        broker = bt.brokers.IBBroker(**IBhost.storekwargs)
        
                    cerebro.setbroker(broker)
                    
                else:
                    startcash = 1000000
                    cerebro.broker.setcash(startcash)
                    
            elif args.oanda:
        
                storekwargs = dict(
                    token=args.token,
                    account=args.account,
                    practice=not args.live
                )
        
                if not args.no_store:
                    store = StoreCls(**storekwargs)
        
                if args.broker:
                    if args.no_store:
                        broker = BrokerCls(**storekwargs)
                    else:
                        broker = store.getbroker()
        
                    cerebro.setbroker(broker)
                    
                else:
                    startcash = 1000000
                    cerebro.broker.setcash(startcash)
        
        #----- TIMEFRAME AND COMPRESSION -----#
            if args.ib is not None:
            
                timeframe = args.timeframe
                # Manage data1 parameters
                tf1 = args.timeframe1
                #tf1 = bt.TimeFrame.TFrame(tf1) if tf1 is not None else timeframe
                cp1 = args.compression1
                cp1 = cp1 if cp1 is not None else args.compression
                '''
                if args.resample or args.replay:
                    datatf = datatf1 = bt.Timeframe.Minutes
                    datacomp = datacomp1 = args.compression
                else
                    datatf = timeframe
                    datacomp = args.compression
                    datatf1 = tf1
                    datacomp1 = cp1'''
        
                if args.resample or args.replay:
                    datatf1 = datatf = args.timeframe
                    datacomp1 = datacomp = 1
                else:
                    datatf = timeframe
                    datacomp = args.compression
                    datatf1 = tf1
                    datacomp1 = cp1
        
                if not args.historical:
                    fromdate = datetime.datetime.now() - datetime.timedelta(days=4)
                    todate = None
                else:
                    dtformat = '%Y-%m-%d' + ('T%H:%M:%S' * ('T' in args.fromdate))
                    fromdate = datetime.datetime.strptime(args.fromdate, dtformat)
                    if args.now:
                        todate = datetime.datetime.now()
                    else:
                        dtformat = '%Y-%m-%d' + ('T%H:%M:%S' * ('T' in args.todate))
                        todate = datetime.datetime.strptime(args.todate, dtformat)
        
                if args.now:
                    todate = datetime.datetime.now()
            
            elif args.oanda:
                timeframe = bt.TimeFrame.TFrame(args.timeframe)
                # Manage data1 parameters
                tf1 = args.timeframe1
                #tf1 = bt.TimeFrame.TFrame(tf1) if tf1 is not None else timeframe
                cp1 = args.compression1
                cp1 = cp1 if cp1 is not None else args.compression
                
                if args.resample or args.replay:
                    datatf = datatf1 = bt.TimeFrame.Ticks
                    datacomp = datacomp1 = 1
                else:
                    datatf = timeframe
                    datacomp = args.compression
                    datatf1 = tf1
                    datacomp1 = cp1
        
                fromdate = None
                if args.fromdate:
                    dtformat = '%Y-%m-%d' + ('T%H:%M:%S' * ('T' in args.fromdate))
                    fromdate = datetime.datetime.strptime(args.fromdate, dtformat)
        
        #----- STORE AND DATAS - INTERACTIVE BROKERS -----#
        
            if args.ib is not None:
            
                IBDataFactory = ibstore.getdata if args.usestore else bt.feeds.IBData
        
                datakwargs = dict(
                    timeframe=datatf,
                    compression=datacomp,
                    historical=args.historical,
                    fromdate=fromdate,
                    todate=todate,
                    rtbar=args.rtbar,
                    qcheck=args.qcheck,
                    what=args.what,
                    backfill_start=True,
                    backfill=True,
                    #backfill_start=not args.no_backfill_start,
                    #backfill=not args.no_backfill,
                    latethrough=args.latethrough,
                    tz=args.timezone
                )
        
                if not args.usestore and not args.broker:   # neither store nor broker
                    datakwargs.update(IBhost.storekwargs)  # pass the store args over the data
        
        #----- STORE AND DATAS - OANDA -----#
        
            elif args.oanda:
                
                DataFactory = DataCls if args.no_store else store.getdata
        
                datakwargs = dict(
                    timeframe=datatf, compression=datacomp,
                    qcheck=args.qcheck,
                    historical=args.historical,
                    fromdate=fromdate,
                    bidask=args.bidask,
                    useask=args.useask,
                    backfill_start=not args.no_backfill_start,
                    backfill=not args.no_backfill,
                    tz=args.timezone
                )
        
                if args.no_store and not args.broker:   # neither store nor broker
                    datakwargs.update(storekwargs)  # pass the store args over the data
        
        
        #--- DATAS - CSV FILE ---#
            
            if args.csv:
                
                datapath = '../data/csv/commodities/XAUUSD/XAUUSD_m1_Ask_2012-2016.csv'
                data0 = bt.feeds.GenericCSVData(
                    timeframe=bt.TimeFrame.Minutes,
                    compression=1,
                    dataname=datapath,
                    nullvalue=0.0,
                    dtformat=('%m/%d/%Y'),
                    tmformat=('%H:%M:%S'),
                    fromdate=fromdate,
                    todate=todate,
                    datetime=0,
                    time=1,
                    high=3,
                    low=4,
                    open=2,
                    close=5,
                    volume=6,
                    openinterest=-1 #-1 means not used
                    )
        
        #--- DATA 0 - INTERACTIVE BROKERS & OANDA  ---#
            else:
                if args.ib is not None:
                    data0 = IBDataFactory(dataname=args.data0, **datakwargs)
                elif args.oanda:
                    data0 = DataFactory(dataname=args.data0, **datakwargs)
        
        #--- DATA 1 - BOTH INTERACTIVE BROKERS & OANDA  ---#
        
                data1 = None
                
                if args.data1 is not None:
                    if args.data1 != args.data0:
                        datakwargs['timeframe'] = datatf1
                        datakwargs['compression'] = datacomp1
                        data1 = IBDataFactory(dataname=args.data1, **datakwargs)
                    else:
                        data1 = data0
        
                rekwargs = dict(
                    timeframe=timeframe, compression=args.compression,
                    bar2edge=not args.no_bar2edge,
                    adjbartime=not args.no_adjbartime,
                    rightedge=not args.no_rightedge,
                    takelate=not args.no_takelate,
                )
            
        #----- LOAD DATA -----#
            
            if args.replay:
                cerebro.replaydata(data0, **rekwargs)
        
                if data1 is not None:
                    rekwargs['timeframe'] = tf1
                    rekwargs['compression'] = cp1
                    cerebro.replaydata(data1, **rekwargs)
        
            elif args.resample:
                cerebro.resampledata(data0, **rekwargs)
        
                if data1 is not None:
                    rekwargs['timeframe'] = tf1
                    rekwargs['compression'] = cp1
                    cerebro.resampledata(data1, **rekwargs)
        
            else:
                cerebro.adddata(data0)
                if data1 is not None:
                    cerebro.adddata(data1)
        
            if args.valid is None:
                valid = None
            else:
                valid = datetime.timedelta(seconds=args.valid)
        
        
            #--- PROCESSING LOAD TIME ---#
            cerebro.dtcerebro = dt0 = datetime.datetime.now()
            print('Cerebro Start Time:          {}'.format(dt0))
            
        #----- CEREBRO RUN - OPTIMISE -----#
        # https://www.backtrader.com/blog/posts/2015-07-23-multicore-optimization/multicore-optimization/
        
            if args.optimise:
            
                #cerebro.addstrategy(TheStrategy, bomperiod_0=100)
                cerebro.optstrategy(TheStrategy, bomperiod_0=(50,100,300))
                #cerebro.adddata(data0)
                # Run over everything
                opt_runs = cerebro.run(maxcpus=1)
                
                # Generate results list
                final_results_list = []
                for run in opt_runs:
                    for strategy in run:
                        value = round(strategy.broker.getvalue(),2)
                        pnl = round(value - startcash,2)
                        period = strategy.params.bomperiod_0
                        final_results_list.append([period,pnl])
                                
                #Sort Results List
                by_period = sorted(final_results_list, key=lambda x: x[0])
                by_PnL = sorted(final_results_list, key=lambda x: x[1], reverse=True)
        
                #Print results
                print('')
                print('Results: Ordered by period:')
                for result in by_period:
                    print('Period: {}, PnL: {:5,.5f}'.format(result[0], result[1]))
                print('')
                print('Results: Ordered by Profit:')
                for result in by_PnL:
                    print('Period: {}, PnL: {:5,.5f}'.format(result[0], result[1]))
                print('')
            
            
        #----- CEREBRO RUN - LIVE -----# ... avoid long data accumulation by switching to "exactbars"
            elif args.historical is None:
            
                if args.ib is not None:
                    cerebro.addstrategy(TheStrategy,
                                        trade=args.trade,
                                        exectype=bt.Order.ExecType(args.exectype),
                                        stake=args.stake,
                                        stopafter=args.stopafter,
                                        valid=valid,
                                        cancel=args.cancel,
                                        donotsell=args.donotsell,
                                        stoptrail=args.stoptrail,
                                        stoptraillimit=args.traillimit,
                                        trailamount=args.trailamount,
                                        trailpercent=args.trailpercent,
                                        limitoffset=args.limitoffset,
                                        oca=args.oca,
                                        bracket=args.bracket)
                elif args.oanda:
                    cerebro.addstrategy(TheStrategy,
                                        trade=args.trade,
                                        exectype=bt.Order.ExecType(args.exectype),
                                        stake=args.stake,
                                        stopafter=args.stopafter,
                                        valid=valid,
                                        cancel=args.cancel,
                                        donotcounter=args.donotcounter,
                                        sell=args.sell,
                                        usebracket=args.usebracket)
                                        
                cerebro.addobserver(bt.observers.Trades)
                cerebro.addobserver(bt.observers.BuySell)
                cerebro.run(exactbars=args.exactbars)
                
        #----- CEREBRO RUN - HISTORICAL -----#
            
            else:
        
                cerebro.addstrategy(TheStrategy)
                
                if args.writer:
                    cerebro.addwriter(bt.WriterFile, csv=True, out=(args.data0 + "-from-" + args.fromdate + "-to-" + args.todate + ".csv"))
                cerebro.addobserver(bt.observers.Trades)
                cerebro.addobserver(bt.observers.BuySell)
                cerebro.addobserver(bt.observers.Value, barplot=True)
                cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='ta')
                cerebro.addanalyzer(bt.analyzers.SQN, _name='sqn')
                
                if data1 is not None:
                    strategies = cerebro.run(stdstats=False, runonce=False) #runonce=False (for coupling of mixed tiemframes to work).
                    firstStrat = strategies[0]
                else:
                    strategies = cerebro.run(stdstats=False, runonce=True)
                    firstStrat = strategies[0]
                
                #printstrategy()
                printTradeAnalysis(firstStrat.analyzers.ta.get_analysis())
                printSQN(firstStrat.analyzers.sqn.get_analysis())
                print('1.6 – 1.9 Below average, 2.0 – 2.4 Average, 2.5 – 2.9 Good, 3.0 – 5.0 Excellent, 5.1 – 6.9 Superb, 7.0 – Holy Grail')
        
                #portvalue = round(cerebro.broker.getvalue(), 2)
                portvalue = cerebro.broker.getvalue()
                #pnl = round(portvalue - startcash, 2)
                pnl = (portvalue - startcash)
                print('Final Portfolio Value: ${0:,.5f}'.format(portvalue))
                print('P/L: ${0:.5f}'.format(pnl))
                print('{0:.2f}%'.format((pnl / startcash * 100)))
        
                #pyplot.plot(data0) # TESTING DIFFERENT TYPE OF PLOTTING
                
                cerebro.plot(
                    #plotter = None,
                    #plotname=args.data0,
                    #subplot=True,
                    #plotlinelabels=True,
                    style='candlestick',
                    barup='green',
                    bardown='red',
                    volume=args.volume,
                    )
        
        if __name__ == '__main__':
            runstrategy()
        
        1 Reply Last reply Reply Quote 0
        • Z
          zkl last edited by

          Hello mics,

          a few days ago I started to look into this subject.

          This:

          from matplotlib.finance import candlestick_ohlc
          

          seems to be substituted through:

          import mplfinance as mpf
          

          mplfinance

          matplotlib utilities for the visualization, and visual analysis, of financial data
          https://github.com/matplotlib/mplfinance

          1 Reply Last reply Reply Quote 0
          • D
            dasch last edited by

            backtrader_plotting is able to plot live data. I created a new project based on backtrader_plotting with live plotting in mind. You can find it here:

            https://github.com/happydasch/btplotting

            There are a few issues with generating/displaying data but it mostly works.

            1 Reply Last reply Reply Quote 1
            • D
              dasch last edited by

              with btplotting you don't need a modified version of backtrader, you start it with this:

              from btplotting import BacktraderPlottingLive
              from btplotting.schemes import Tradimo
              
              # black skin
              cerebro.addanalyzer(BacktraderPlottingLive)
              
              or
              
              # white skin
              cerebro.addanalyzer(BacktraderPlottingLive, scheme=Tradimo())
              

              after this you can access the live plot at http://localhost:80

              1 Reply Last reply Reply Quote 1
              • R
                rajanprabu last edited by

                @dasch This is wonderful, thank you so much. I just tested and it works just out of the box. Just one small comment. Please increase the default port number, otherwise one need supervisor credentials to make it run.

                I have couple of questions. How does it handle resample data ? I just tried with ibstore and I can see the ticks but not resampled data.. any suggestions ? How does one disable the DEBUG aka logger messages ?

                Once again thanks for sharing.

                1 Reply Last reply Reply Quote 0
                • D
                  dasch last edited by

                  @rajanprabu said in Real-Time Plotting:

                  I have couple of questions. How does it handle resample data ? I just tried with ibstore and I can see the ticks but not resampled data.. any suggestions ? How does one disable the DEBUG aka logger messages ?

                  it should handle resampled data, but with ticks, the gaps are wide, depending on the resampled timeframe. for example, if you resample to 1 min from ticks, then they will not be that visible. In live plotting, you can configure what is being shown.

                  1 Reply Last reply Reply Quote 0
                  • D
                    dasch last edited by

                    you can configure tick data to not be plotted. for the debugging messages, i am not sure what you mean.

                    1 Reply Last reply Reply Quote 0
                    • R
                      rajanprabu last edited by

                      By DEBUG lines I meant these lines in the output

                      DEBUG:bokeh.server.tornado:[pid 72891] 0 clients connected
                      DEBUG:bokeh.server.tornado:[pid 72891]   / has 1 sessions with 1 unused
                      13-Oct-20 19:24:18 DEBUG     Sending patch for figurepage: defaultdict(<class 'list'>, {'datetime': [(0, Timestamp('2020-10-13 17:24:17.222988'))]})
                      13-Oct-20 19:24:18 DEBUG     Sending patch for figure: defaultdict(<class 'list'>, {'datetime': [(0, Timestamp('2020-10-13 17:24:17.222988'))]})
                      13-Oct-20 19:24:18 DEBUG     Sending patch for figure: defaultdict(<class 'list'>, {'140360762382800': [(0, 'NaN')], '140360762382992': [(0, 'NaN')], '140360762383184': [(0, 'NaN')], 'datetime': [(0, Timestamp('2020-10-13 17:24:17.222988'))]})
                      13-Oct-20 19:24:18 DEBUG     Sending patch for figure: defaultdict(<class 'list'>, {'140360474604560open': [(0, 'NaN')], '140360474604560high': [(0, 'NaN')], '140360474604560low': [(0, 'NaN')], '140360474604560close': [(0, 'NaN')], '140360474604560volume': [(0, 'NaN')], '140360762380368': [(0, 'NaN')], '140360762380560': [(0, 'NaN')], 'datetime': [(0, Timestamp('2020-10-13 17:24:17.222988'))]})
                      DEBUG:bokeh.server.contexts:Scheduling 1 sessions to discard
                      DEBUG:bokeh.server.contexts:Discarding session 'DsZV4Kgrj4zubFpXMK4MFTgQd3AyalCksvFAFmN5ItYq' last in use 26883.637406999987 milliseconds ago
                      DEBUG:bokeh.document.document:Deleting 0 modules for <bokeh.document.document.Document object at 0x7fa7e8e04c10>
                      

                      @dasch said in Real-Time Plotting:

                      @rajanprabu said in Real-Time Plotting:

                      it should handle resampled data, but with ticks, the gaps are wide, depending on the resampled timeframe. for example, if you resample to 1 min from ticks, then they will not be that visible. In live plotting, you can configure what is being shown.

                      Understood, Thanks for your time and effort. Very much appreciate it.

                      1 Reply Last reply Reply Quote 0
                      • C
                        censorship last edited by

                        Hello,

                        I'm exactly looking for something like this, i must say it looks surprising.
                        I merge historical data with livedata from a websocket to another dataframe.
                        This dataframe should then be displayed in a live chart.

                        However i wonder how to get started on this.
                        A little bit more information on how to use this would be very nice :D

                        Thanks in advance and thanks for your work

                        1 Reply Last reply Reply Quote 0
                        • 1 / 1
                        • First post
                          Last post
                        Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors