Real-Time Plotting
-
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)
-
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()
-
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 -
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.
-
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
-
@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.
-
@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.
-
you can configure tick data to not be plotted. for the debugging messages, i am not sure what you mean.
-
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.
-
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 :DThanks in advance and thanks for your work