From bb4dc448b38d649bd1ba810d491dbbe60dd7bd19 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 30 Aug 2022 20:15:31 -0400 Subject: [PATCH] Add history chart and "linear region" for syncing Add a first draft of a working `pyqtgraph.LinearRegionItem` link between a history view chart (+ data set) and the normal real-time "HFT" chart set. Add the history view (aka more downsampled data view) chart set to the rt/hft set's splitter as it's "first widget". Hook up linear region callbacks to enable syncing between charts including compenstating for the downsampling rate ration (in this case hardcoded 60 since 1s to 1M, but we'll actually compute it going forward obvs). More to come dawgys.. --- piker/ui/_display.py | 102 ++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 31 deletions(-) diff --git a/piker/ui/_display.py b/piker/ui/_display.py index 0a540778..b9066847 100644 --- a/piker/ui/_display.py +++ b/piker/ui/_display.py @@ -29,7 +29,7 @@ from typing import Optional, Any, Callable import numpy as np import tractor import trio -import pendulum +# import pendulum import pyqtgraph as pg # from .. import brokers @@ -720,12 +720,15 @@ async def display_symbol_data( ) as feed: ohlcv: ShmArray = feed.rt_shm - bars = ohlcv.array + hist_ohlcv: ShmArray = feed.hist_shm + end_index = hist_ohlcv.index + + # bars = ohlcv.array symbol = feed.symbols[sym] fqsn = symbol.front_fqsn() - times = feed.hist_shm.array['time'] - end = pendulum.from_timestamp(times[-1]) + # times = feed.hist_shm.array['time'] + # end = pendulum.from_timestamp(times[-1]) # start = pendulum.from_timestamp(times[times != times[-1]][-1]) # step_size_s = (end - start).seconds @@ -739,7 +742,7 @@ async def display_symbol_data( f'step:{tf_key} ' ) - linked = godwidget.linkedsplits + linked = godwidget.rt_linked linked._symbol = symbol # generate order mode side-pane UI @@ -749,10 +752,27 @@ async def display_symbol_data( # add as next-to-y-axis singleton pane godwidget.pp_pane = pp_pane + # create top history view chart above the "main rt chart". + hist_linked = godwidget.hist_linked + hist_linked._symbol = symbol + hist_chart = hist_linked.plot_ohlc_main( + symbol, + feed.hist_shm, + # in the case of history chart we explicitly set `False` + # to avoid internal pane creation. + sidepane=False, + ) + hist_chart.default_view( + bars_from_y=int(len(hist_ohlcv.array)), # size to data + y_offset=6116*2, # push it a little away from the y-axis + ) + # create main OHLC chart chart = linked.plot_ohlc_main( symbol, ohlcv, + # in the case of history chart we explicitly set `False` + # to avoid internal pane creation. sidepane=pp_pane, ) @@ -760,54 +780,66 @@ async def display_symbol_data( chart._feeds[symbol.key] = feed chart.setFocus() + # XXX: FOR SOME REASON THIS IS CAUSING HANGZ!?! # plot historical vwap if available wap_in_history = False - - # XXX: FOR SOME REASON THIS IS CAUSING HANGZ!?! - # if brokermod._show_wap_in_history: - - # if 'bar_wap' in bars.dtype.fields: - # wap_in_history = True - # chart.draw_curve( - # name='bar_wap', - # shm=ohlcv, - # color='default_light', - # add_label=False, - # ) - - # size view to data once at outset - # chart.cv._set_yrange() + # if ( + # brokermod._show_wap_in_history + # and 'bar_wap' in bars.dtype.fields + # ): + # wap_in_history = True + # chart.draw_curve( + # name='bar_wap', + # shm=ohlcv, + # color='default_light', + # add_label=False, + # ) # Add the LinearRegionItem to the ViewBox, but tell the ViewBox # to exclude this item when doing auto-range calculations. - hist_pi = chart.plotItem + rt_pi = chart.plotItem + hist_pi = hist_chart.plotItem region = pg.LinearRegionItem() region.setZValue(10) - # hist_pi.addItem(region, ignoreBounds=True) - flow = chart._flows[chart.name] - region.setClipItem(flow.graphics) + hist_pi.addItem(region, ignoreBounds=True) + flow = chart._flows[hist_chart.name] + assert flow + # XXX: no idea why this doesn't work but it's causing + # a weird placement of the region on the way-far-left.. + # region.setClipItem(flow.graphics) def update(): region.setZValue(10) - minX, maxX = region.getRegion() - # p1.setXRange(minX, maxX, padding=0) + mn, mx = region.getRegion() + # print(f'region_x: {(mn, mx)}') + + # XXX: seems to cause a real perf hit? + rt_pi.setXRange( + (mn - end_index) * 60, + (mx - end_index) * 60, + padding=0, + ) region.sigRegionChanged.connect(update) def update_region_from_pi( window, viewRange: tuple[tuple, tuple], + ) -> None: # set the region on the history chart # to the range currently viewed in the # HFT/real-time chart. rgn = viewRange[0] - # region.setRegion(rgn) + # print(f'rt_view_range: {rgn}') + mn, mx = rgn + region.setRegion(( + mn/60 + end_index, + mx/60 + end_index, + )) # connect region to be updated on plotitem interaction. - hist_pi.sigRangeChanged.connect(update_region_from_pi) - # causes recursion error right now!?.. - # region.setRegion([l, r]) + rt_pi.sigRangeChanged.connect(update_region_from_pi) # NOTE: we must immediately tell Qt to show the OHLC chart # to avoid a race where the subplots get added/shown to @@ -816,6 +848,11 @@ async def display_symbol_data( linked.focus() await trio.sleep(0) + linked.splitter.insertWidget(0, hist_linked) + # XXX: if we wanted it at the bottom? + # linked.splitter.addWidget(hist_linked) + linked.focus() + vlm_chart: Optional[ChartPlotWidget] = None async with trio.open_nursery() as ln: @@ -851,8 +888,9 @@ async def display_symbol_data( ) await trio.sleep(0) + + # size view to data prior to order mode init chart.default_view() - l, lbar, rbar, r = chart.bars_range() async with ( open_order_mode( @@ -863,12 +901,14 @@ async def display_symbol_data( ) ): if not vlm_chart: + # trigger another view reset if no sub-chart chart.default_view() # let Qt run to render all widgets and make sure the # sidepanes line up vertically. await trio.sleep(0) linked.resize_sidepanes() + linked.set_split_sizes() # NOTE: we pop the volume chart from the subplots set so # that it isn't double rendered in the display loop