Fix sidepane alignment with FSP charts
Call the resize method only after all FSP subcharts have rendered such that the main OHLC chart's final width is read. Further tweaks: - drop rsi by default - drop the stream drain stuff - fix failed-to-read shm loggingpy3.10_support
parent
56b65a1cde
commit
644ac6661c
|
@ -61,7 +61,10 @@ log = get_logger(__name__)
|
||||||
_quote_throttle_rate: int = 58 # Hz
|
_quote_throttle_rate: int = 58 # Hz
|
||||||
|
|
||||||
|
|
||||||
def try_read(array: np.ndarray) -> Optional[np.ndarray]:
|
def try_read(
|
||||||
|
array: np.ndarray
|
||||||
|
|
||||||
|
) -> Optional[np.ndarray]:
|
||||||
'''
|
'''
|
||||||
Try to read the last row from a shared mem array or ``None``
|
Try to read the last row from a shared mem array or ``None``
|
||||||
if the array read returns a zero-length array result.
|
if the array read returns a zero-length array result.
|
||||||
|
@ -85,10 +88,9 @@ def try_read(array: np.ndarray) -> Optional[np.ndarray]:
|
||||||
# something we need anyway, maybe there should be some kind of
|
# something we need anyway, maybe there should be some kind of
|
||||||
# signal that a prepend is taking place and this consumer can
|
# signal that a prepend is taking place and this consumer can
|
||||||
# respond (eg. redrawing graphics) accordingly.
|
# respond (eg. redrawing graphics) accordingly.
|
||||||
log.warning(f'Read-race on shm array: {graphics_name}@{shm.token}')
|
|
||||||
|
|
||||||
# the array read was emtpy
|
# the array read was emtpy
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def update_fsp_chart(
|
def update_fsp_chart(
|
||||||
|
@ -101,8 +103,10 @@ def update_fsp_chart(
|
||||||
|
|
||||||
array = shm.array
|
array = shm.array
|
||||||
last_row = try_read(array)
|
last_row = try_read(array)
|
||||||
|
|
||||||
# guard against unreadable case
|
# guard against unreadable case
|
||||||
if not last_row:
|
if not last_row:
|
||||||
|
log.warning(f'Read-race on shm array: {graphics_name}@{shm.token}')
|
||||||
return
|
return
|
||||||
|
|
||||||
# update graphics
|
# update graphics
|
||||||
|
@ -175,7 +179,6 @@ def chart_maxmin(
|
||||||
|
|
||||||
|
|
||||||
async def update_chart_from_quotes(
|
async def update_chart_from_quotes(
|
||||||
|
|
||||||
linked: LinkedSplits,
|
linked: LinkedSplits,
|
||||||
stream: tractor.MsgStream,
|
stream: tractor.MsgStream,
|
||||||
ohlcv: np.ndarray,
|
ohlcv: np.ndarray,
|
||||||
|
@ -247,17 +250,16 @@ async def update_chart_from_quotes(
|
||||||
chart.show()
|
chart.show()
|
||||||
last_quote = time.time()
|
last_quote = time.time()
|
||||||
|
|
||||||
# NOTE: all code below this loop is expected to be synchronous
|
|
||||||
# and thus draw instructions are not picked up jntil the next
|
|
||||||
# wait / iteration.
|
|
||||||
async for quotes in stream:
|
async for quotes in stream:
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
quote_period = now - last_quote
|
quote_period = time.time() - last_quote
|
||||||
quote_rate = round(1/quote_period, 1) if quote_period else float('inf')
|
quote_rate = round(
|
||||||
|
1/quote_period, 1) if quote_period > 0 else float('inf')
|
||||||
|
|
||||||
if (
|
if (
|
||||||
quote_period <= 1/_quote_throttle_rate
|
quote_period <= 1/_quote_throttle_rate
|
||||||
and quote_rate > _quote_throttle_rate + 2
|
and quote_rate > _quote_throttle_rate * 1.5
|
||||||
):
|
):
|
||||||
log.warning(f'High quote rate {symbol.key}: {quote_rate}')
|
log.warning(f'High quote rate {symbol.key}: {quote_rate}')
|
||||||
last_quote = now
|
last_quote = now
|
||||||
|
@ -454,7 +456,8 @@ def maybe_mk_fsp_shm(
|
||||||
readonly: bool = True,
|
readonly: bool = True,
|
||||||
|
|
||||||
) -> (ShmArray, bool):
|
) -> (ShmArray, bool):
|
||||||
'''Allocate a single row shm array for an symbol-fsp pair if none
|
'''
|
||||||
|
Allocate a single row shm array for an symbol-fsp pair if none
|
||||||
exists, otherwise load the shm already existing for that token.
|
exists, otherwise load the shm already existing for that token.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -481,7 +484,6 @@ def maybe_mk_fsp_shm(
|
||||||
|
|
||||||
@acm
|
@acm
|
||||||
async def open_fsp_sidepane(
|
async def open_fsp_sidepane(
|
||||||
|
|
||||||
linked: LinkedSplits,
|
linked: LinkedSplits,
|
||||||
conf: dict[str, dict[str, str]],
|
conf: dict[str, dict[str, str]],
|
||||||
|
|
||||||
|
@ -570,6 +572,7 @@ async def open_fsp_cluster(
|
||||||
async def maybe_open_fsp_cluster(
|
async def maybe_open_fsp_cluster(
|
||||||
workers: int = 2,
|
workers: int = 2,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
|
|
||||||
) -> AsyncGenerator[int, dict[str, tractor.Portal]]:
|
) -> AsyncGenerator[int, dict[str, tractor.Portal]]:
|
||||||
|
|
||||||
kwargs.update(
|
kwargs.update(
|
||||||
|
@ -589,7 +592,6 @@ async def maybe_open_fsp_cluster(
|
||||||
|
|
||||||
|
|
||||||
async def start_fsp_displays(
|
async def start_fsp_displays(
|
||||||
|
|
||||||
cluster_map: dict[str, tractor.Portal],
|
cluster_map: dict[str, tractor.Portal],
|
||||||
linkedsplits: LinkedSplits,
|
linkedsplits: LinkedSplits,
|
||||||
fsps: dict[str, str],
|
fsps: dict[str, str],
|
||||||
|
@ -603,7 +605,8 @@ async def start_fsp_displays(
|
||||||
display_in_own_task: bool = False,
|
display_in_own_task: bool = False,
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
'''Create sub-actors (under flat tree)
|
'''
|
||||||
|
Create sub-actors (under flat tree)
|
||||||
for each entry in config and attach to local graphics update tasks.
|
for each entry in config and attach to local graphics update tasks.
|
||||||
|
|
||||||
Pass target entrypoint and historical data.
|
Pass target entrypoint and historical data.
|
||||||
|
@ -668,9 +671,7 @@ async def start_fsp_displays(
|
||||||
|
|
||||||
|
|
||||||
async def update_chart_from_fsp(
|
async def update_chart_from_fsp(
|
||||||
|
|
||||||
portal: tractor.Portal,
|
portal: tractor.Portal,
|
||||||
|
|
||||||
linkedsplits: LinkedSplits,
|
linkedsplits: LinkedSplits,
|
||||||
brokermod: ModuleType,
|
brokermod: ModuleType,
|
||||||
sym: str,
|
sym: str,
|
||||||
|
@ -687,7 +688,8 @@ async def update_chart_from_fsp(
|
||||||
profiler: pg.debug.Profiler,
|
profiler: pg.debug.Profiler,
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
'''FSP stream chart update loop.
|
'''
|
||||||
|
FSP stream chart update loop.
|
||||||
|
|
||||||
This is called once for each entry in the fsp
|
This is called once for each entry in the fsp
|
||||||
config map.
|
config map.
|
||||||
|
@ -792,9 +794,7 @@ async def update_chart_from_fsp(
|
||||||
level_line(chart, 80, orient_v='top')
|
level_line(chart, 80, orient_v='top')
|
||||||
|
|
||||||
chart._set_yrange()
|
chart._set_yrange()
|
||||||
|
done() # status updates
|
||||||
done()
|
|
||||||
chart.linked.resize_sidepanes()
|
|
||||||
|
|
||||||
profiler(f'fsp:{func_name} starting update loop')
|
profiler(f'fsp:{func_name} starting update loop')
|
||||||
profiler.finish()
|
profiler.finish()
|
||||||
|
@ -912,7 +912,6 @@ def has_vlm(ohlcv: ShmArray) -> bool:
|
||||||
|
|
||||||
@acm
|
@acm
|
||||||
async def maybe_open_vlm_display(
|
async def maybe_open_vlm_display(
|
||||||
|
|
||||||
linked: LinkedSplits,
|
linked: LinkedSplits,
|
||||||
ohlcv: ShmArray,
|
ohlcv: ShmArray,
|
||||||
|
|
||||||
|
@ -992,20 +991,10 @@ async def maybe_open_vlm_display(
|
||||||
# size view to data once at outset
|
# size view to data once at outset
|
||||||
chart._set_yrange()
|
chart._set_yrange()
|
||||||
|
|
||||||
# size pain to parent chart
|
|
||||||
# TODO: this appears to nearly fix a bug where the vlm sidepane
|
|
||||||
# could be sized correctly nearly immediately (since the
|
|
||||||
# order pane is already sized), right now it doesn't seem to
|
|
||||||
# fully align until the VWAP fsp-actor comes up...
|
|
||||||
await trio.sleep(0)
|
|
||||||
chart.linked.resize_sidepanes()
|
|
||||||
await trio.sleep(0)
|
|
||||||
|
|
||||||
yield chart
|
yield chart
|
||||||
|
|
||||||
|
|
||||||
async def display_symbol_data(
|
async def display_symbol_data(
|
||||||
|
|
||||||
godwidget: GodWidget,
|
godwidget: GodWidget,
|
||||||
provider: str,
|
provider: str,
|
||||||
sym: str,
|
sym: str,
|
||||||
|
@ -1116,24 +1105,24 @@ async def display_symbol_data(
|
||||||
'chart_kwargs': {'style': 'step'}
|
'chart_kwargs': {'style': 'step'}
|
||||||
},
|
},
|
||||||
|
|
||||||
'rsi': {
|
# 'rsi': {
|
||||||
'func_name': 'rsi', # literal python func ref lookup name
|
# 'func_name': 'rsi', # literal python func ref lookup name
|
||||||
|
|
||||||
# map of parameters to place on the fsp sidepane widget
|
# # map of parameters to place on the fsp sidepane widget
|
||||||
# which should map to dynamic inputs available to the
|
# # which should map to dynamic inputs available to the
|
||||||
# fsp function at runtime.
|
# # fsp function at runtime.
|
||||||
'params': {
|
# 'params': {
|
||||||
'period': {
|
# 'period': {
|
||||||
'default_value': 14,
|
# 'default_value': 14,
|
||||||
'widget_kwargs': {'readonly': True},
|
# 'widget_kwargs': {'readonly': True},
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
|
|
||||||
# ``ChartPlotWidget`` options passthrough
|
# # ``ChartPlotWidget`` options passthrough
|
||||||
'chart_kwargs': {
|
# 'chart_kwargs': {
|
||||||
'static_yrange': (0, 100),
|
# 'static_yrange': (0, 100),
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_vlm(ohlcv): # and provider != 'binance':
|
if has_vlm(ohlcv): # and provider != 'binance':
|
||||||
|
@ -1201,4 +1190,10 @@ async def display_symbol_data(
|
||||||
order_mode_started
|
order_mode_started
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
|
# let Qt run to render all widgets and make sure the
|
||||||
|
# sidepanes line up vertically.
|
||||||
|
await trio.sleep(0)
|
||||||
|
linkedsplits.resize_sidepanes()
|
||||||
|
|
||||||
|
# let the app run.
|
||||||
await trio.sleep_forever()
|
await trio.sleep_forever()
|
||||||
|
|
Loading…
Reference in New Issue