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..history_view
parent
9846396df2
commit
bb4dc448b3
|
@ -29,7 +29,7 @@ from typing import Optional, Any, Callable
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
import pendulum
|
# import pendulum
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
|
|
||||||
# from .. import brokers
|
# from .. import brokers
|
||||||
|
@ -720,12 +720,15 @@ async def display_symbol_data(
|
||||||
|
|
||||||
) as feed:
|
) as feed:
|
||||||
ohlcv: ShmArray = feed.rt_shm
|
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]
|
symbol = feed.symbols[sym]
|
||||||
fqsn = symbol.front_fqsn()
|
fqsn = symbol.front_fqsn()
|
||||||
|
|
||||||
times = feed.hist_shm.array['time']
|
# times = feed.hist_shm.array['time']
|
||||||
end = pendulum.from_timestamp(times[-1])
|
# end = pendulum.from_timestamp(times[-1])
|
||||||
# start = pendulum.from_timestamp(times[times != times[-1]][-1])
|
# start = pendulum.from_timestamp(times[times != times[-1]][-1])
|
||||||
# step_size_s = (end - start).seconds
|
# step_size_s = (end - start).seconds
|
||||||
|
|
||||||
|
@ -739,7 +742,7 @@ async def display_symbol_data(
|
||||||
f'step:{tf_key} '
|
f'step:{tf_key} '
|
||||||
)
|
)
|
||||||
|
|
||||||
linked = godwidget.linkedsplits
|
linked = godwidget.rt_linked
|
||||||
linked._symbol = symbol
|
linked._symbol = symbol
|
||||||
|
|
||||||
# generate order mode side-pane UI
|
# generate order mode side-pane UI
|
||||||
|
@ -749,10 +752,27 @@ async def display_symbol_data(
|
||||||
# add as next-to-y-axis singleton pane
|
# add as next-to-y-axis singleton pane
|
||||||
godwidget.pp_pane = pp_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
|
# create main OHLC chart
|
||||||
chart = linked.plot_ohlc_main(
|
chart = linked.plot_ohlc_main(
|
||||||
symbol,
|
symbol,
|
||||||
ohlcv,
|
ohlcv,
|
||||||
|
# in the case of history chart we explicitly set `False`
|
||||||
|
# to avoid internal pane creation.
|
||||||
sidepane=pp_pane,
|
sidepane=pp_pane,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -760,54 +780,66 @@ async def display_symbol_data(
|
||||||
chart._feeds[symbol.key] = feed
|
chart._feeds[symbol.key] = feed
|
||||||
chart.setFocus()
|
chart.setFocus()
|
||||||
|
|
||||||
|
# XXX: FOR SOME REASON THIS IS CAUSING HANGZ!?!
|
||||||
# plot historical vwap if available
|
# plot historical vwap if available
|
||||||
wap_in_history = False
|
wap_in_history = False
|
||||||
|
# if (
|
||||||
# XXX: FOR SOME REASON THIS IS CAUSING HANGZ!?!
|
# brokermod._show_wap_in_history
|
||||||
# if brokermod._show_wap_in_history:
|
# and 'bar_wap' in bars.dtype.fields
|
||||||
|
# ):
|
||||||
# if 'bar_wap' in bars.dtype.fields:
|
# wap_in_history = True
|
||||||
# wap_in_history = True
|
# chart.draw_curve(
|
||||||
# chart.draw_curve(
|
# name='bar_wap',
|
||||||
# name='bar_wap',
|
# shm=ohlcv,
|
||||||
# shm=ohlcv,
|
# color='default_light',
|
||||||
# color='default_light',
|
# add_label=False,
|
||||||
# add_label=False,
|
# )
|
||||||
# )
|
|
||||||
|
|
||||||
# size view to data once at outset
|
|
||||||
# chart.cv._set_yrange()
|
|
||||||
|
|
||||||
# Add the LinearRegionItem to the ViewBox, but tell the ViewBox
|
# Add the LinearRegionItem to the ViewBox, but tell the ViewBox
|
||||||
# to exclude this item when doing auto-range calculations.
|
# 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 = pg.LinearRegionItem()
|
||||||
region.setZValue(10)
|
region.setZValue(10)
|
||||||
# hist_pi.addItem(region, ignoreBounds=True)
|
hist_pi.addItem(region, ignoreBounds=True)
|
||||||
flow = chart._flows[chart.name]
|
flow = chart._flows[hist_chart.name]
|
||||||
region.setClipItem(flow.graphics)
|
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():
|
def update():
|
||||||
region.setZValue(10)
|
region.setZValue(10)
|
||||||
minX, maxX = region.getRegion()
|
mn, mx = region.getRegion()
|
||||||
# p1.setXRange(minX, maxX, padding=0)
|
# 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)
|
region.sigRegionChanged.connect(update)
|
||||||
|
|
||||||
def update_region_from_pi(
|
def update_region_from_pi(
|
||||||
window,
|
window,
|
||||||
viewRange: tuple[tuple, tuple],
|
viewRange: tuple[tuple, tuple],
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
# set the region on the history chart
|
# set the region on the history chart
|
||||||
# to the range currently viewed in the
|
# to the range currently viewed in the
|
||||||
# HFT/real-time chart.
|
# HFT/real-time chart.
|
||||||
rgn = viewRange[0]
|
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.
|
# connect region to be updated on plotitem interaction.
|
||||||
hist_pi.sigRangeChanged.connect(update_region_from_pi)
|
rt_pi.sigRangeChanged.connect(update_region_from_pi)
|
||||||
# causes recursion error right now!?..
|
|
||||||
# region.setRegion([l, r])
|
|
||||||
|
|
||||||
# NOTE: we must immediately tell Qt to show the OHLC chart
|
# NOTE: we must immediately tell Qt to show the OHLC chart
|
||||||
# to avoid a race where the subplots get added/shown to
|
# to avoid a race where the subplots get added/shown to
|
||||||
|
@ -816,6 +848,11 @@ async def display_symbol_data(
|
||||||
linked.focus()
|
linked.focus()
|
||||||
await trio.sleep(0)
|
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
|
vlm_chart: Optional[ChartPlotWidget] = None
|
||||||
async with trio.open_nursery() as ln:
|
async with trio.open_nursery() as ln:
|
||||||
|
|
||||||
|
@ -851,8 +888,9 @@ async def display_symbol_data(
|
||||||
)
|
)
|
||||||
|
|
||||||
await trio.sleep(0)
|
await trio.sleep(0)
|
||||||
|
|
||||||
|
# size view to data prior to order mode init
|
||||||
chart.default_view()
|
chart.default_view()
|
||||||
l, lbar, rbar, r = chart.bars_range()
|
|
||||||
|
|
||||||
async with (
|
async with (
|
||||||
open_order_mode(
|
open_order_mode(
|
||||||
|
@ -863,12 +901,14 @@ async def display_symbol_data(
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
if not vlm_chart:
|
if not vlm_chart:
|
||||||
|
# trigger another view reset if no sub-chart
|
||||||
chart.default_view()
|
chart.default_view()
|
||||||
|
|
||||||
# let Qt run to render all widgets and make sure the
|
# let Qt run to render all widgets and make sure the
|
||||||
# sidepanes line up vertically.
|
# sidepanes line up vertically.
|
||||||
await trio.sleep(0)
|
await trio.sleep(0)
|
||||||
linked.resize_sidepanes()
|
linked.resize_sidepanes()
|
||||||
|
linked.set_split_sizes()
|
||||||
|
|
||||||
# NOTE: we pop the volume chart from the subplots set so
|
# NOTE: we pop the volume chart from the subplots set so
|
||||||
# that it isn't double rendered in the display loop
|
# that it isn't double rendered in the display loop
|
||||||
|
|
Loading…
Reference in New Issue