Change over the UI layer to use `MktPair`
Including changing to `LinkedSplits.mkt: MktPair` and adding an explicit setter method for setting it and being sure that nothing breaks in the display system init! For this commit we leave in warning access to `LinkedSplits.symbol` but will remove in following commit.master
parent
39af215d61
commit
1b577eebf6
|
@ -907,7 +907,7 @@ async def open_feed(
|
|||
|
||||
for fqme, flume_msg in flumes_msg_dict.items():
|
||||
flume = Flume.from_msg(flume_msg)
|
||||
# assert flume.symbol.fqme == fqme
|
||||
# assert flume.mkt.fqme == fqme
|
||||
feed.flumes[fqme] = flume
|
||||
|
||||
# TODO: do we need this?
|
||||
|
|
|
@ -68,7 +68,10 @@ from ..data.feed import (
|
|||
Feed,
|
||||
Flume,
|
||||
)
|
||||
from ..accounting._mktinfo import Symbol
|
||||
from ..accounting import (
|
||||
MktPair,
|
||||
Symbol,
|
||||
)
|
||||
from ..log import get_logger
|
||||
from ._interaction import ChartView
|
||||
from ._forms import FieldsForm
|
||||
|
@ -287,7 +290,7 @@ class GodWidget(QWidget):
|
|||
pp_nav.hide()
|
||||
|
||||
# set window titlebar info
|
||||
symbol = self.rt_linked.symbol
|
||||
symbol = self.rt_linked.mkt
|
||||
if symbol is not None:
|
||||
self.window.setWindowTitle(
|
||||
f'{symbol.fqme} '
|
||||
|
@ -452,7 +455,7 @@ class LinkedSplits(QWidget):
|
|||
# update the UI for a given "chart instance".
|
||||
self.display_state: DisplayState | None = None
|
||||
|
||||
self._symbol: Symbol = None
|
||||
self._mkt: MktPair | Symbol = None
|
||||
|
||||
def on_splitter_adjust(
|
||||
self,
|
||||
|
@ -474,9 +477,20 @@ class LinkedSplits(QWidget):
|
|||
**kwargs,
|
||||
)
|
||||
|
||||
def set_mkt_info(
|
||||
self,
|
||||
mkt: MktPair,
|
||||
) -> None:
|
||||
self._mkt = mkt
|
||||
|
||||
@property
|
||||
def symbol(self) -> Symbol:
|
||||
return self._symbol
|
||||
def mkt(self) -> MktPair:
|
||||
return self._mkt
|
||||
|
||||
@property
|
||||
def symbol(self) -> Symbol | MktPair:
|
||||
log.warning(f'{type(self)}.symbol is now deprecated use .mkt!')
|
||||
return self.mkt
|
||||
|
||||
def set_split_sizes(
|
||||
self,
|
||||
|
@ -521,7 +535,7 @@ class LinkedSplits(QWidget):
|
|||
def plot_ohlc_main(
|
||||
self,
|
||||
|
||||
symbol: Symbol,
|
||||
mkt: MktPair,
|
||||
shm: ShmArray,
|
||||
flume: Flume,
|
||||
sidepane: FieldsForm,
|
||||
|
@ -540,7 +554,7 @@ class LinkedSplits(QWidget):
|
|||
# add crosshairs
|
||||
self.cursor = Cursor(
|
||||
linkedsplits=self,
|
||||
digits=symbol.tick_size_digits,
|
||||
digits=mkt.price_tick_digits,
|
||||
)
|
||||
|
||||
# NOTE: atm the first (and only) OHLC price chart for the symbol
|
||||
|
@ -548,7 +562,7 @@ class LinkedSplits(QWidget):
|
|||
# be no distinction since we will have multiple symbols per
|
||||
# view as part of "aggregate feeds".
|
||||
self.chart = self.add_plot(
|
||||
name=symbol.fqme,
|
||||
name=mkt.fqme,
|
||||
shm=shm,
|
||||
flume=flume,
|
||||
style=style,
|
||||
|
@ -1030,7 +1044,7 @@ class ChartPlotWidget(pg.PlotWidget):
|
|||
'''
|
||||
view = vb or self.view
|
||||
viz = self.main_viz
|
||||
l, r = viz.view_range()
|
||||
left, right = viz.view_range()
|
||||
x_shift = viz.index_step() * datums
|
||||
|
||||
if datums >= 300:
|
||||
|
@ -1040,8 +1054,8 @@ class ChartPlotWidget(pg.PlotWidget):
|
|||
|
||||
# should trigger broadcast on all overlays right?
|
||||
view.setXRange(
|
||||
min=l + x_shift,
|
||||
max=r + x_shift,
|
||||
min=left + x_shift,
|
||||
max=right + x_shift,
|
||||
|
||||
# TODO: holy shit, wtf dude... why tf would this not be 0 by
|
||||
# default... speechless.
|
||||
|
@ -1227,7 +1241,7 @@ class ChartPlotWidget(pg.PlotWidget):
|
|||
# if the sticky is for our symbol
|
||||
# use the tick size precision for display
|
||||
name = name or pi.name
|
||||
sym = self.linked.symbol
|
||||
sym = self.linked.mkt
|
||||
digits = None
|
||||
if name == sym.key:
|
||||
digits = sym.tick_size_digits
|
||||
|
|
|
@ -228,7 +228,7 @@ class ContentsLabel(pg.LabelItem):
|
|||
'bar_wap',
|
||||
]
|
||||
],
|
||||
name=name,
|
||||
# name=name,
|
||||
index=ix,
|
||||
)
|
||||
)
|
||||
|
@ -363,7 +363,7 @@ class Cursor(pg.GraphicsObject):
|
|||
|
||||
# value used for rounding y-axis discreet tick steps
|
||||
# computing once, up front, here cuz why not
|
||||
mkt = self.linked._symbol
|
||||
mkt = self.linked.mkt
|
||||
self._y_tick_mult = 1/float(mkt.price_tick)
|
||||
|
||||
# line width in view coordinates
|
||||
|
|
|
@ -436,12 +436,12 @@ class Viz(Struct):
|
|||
else:
|
||||
if x_range is None:
|
||||
(
|
||||
l,
|
||||
xl,
|
||||
_,
|
||||
lbar,
|
||||
rbar,
|
||||
_,
|
||||
r,
|
||||
xr,
|
||||
) = self.datums_range()
|
||||
|
||||
profiler(f'{self.name} got bars range')
|
||||
|
@ -585,12 +585,12 @@ class Viz(Struct):
|
|||
Return a range tuple for the datums present in view.
|
||||
|
||||
'''
|
||||
l, r = view_range or self.view_range()
|
||||
xl, xr = view_range or self.view_range()
|
||||
|
||||
index_field: str = index_field or self.index_field
|
||||
if index_field == 'index':
|
||||
l: int = round(l)
|
||||
r: int = round(r)
|
||||
xl: int = round(xl)
|
||||
xr: int = round(xr)
|
||||
|
||||
if array is None:
|
||||
array = self.shm.array
|
||||
|
@ -601,12 +601,12 @@ class Viz(Struct):
|
|||
|
||||
# invalid view state
|
||||
if (
|
||||
r < l
|
||||
or l < 0
|
||||
or r < 0
|
||||
xr < xl
|
||||
or xl < 0
|
||||
or xr < 0
|
||||
or (
|
||||
l > last
|
||||
and r > last
|
||||
xl > last
|
||||
and xr > last
|
||||
)
|
||||
):
|
||||
leftmost: int = first
|
||||
|
@ -616,12 +616,12 @@ class Viz(Struct):
|
|||
# determine first and last datums in view determined by
|
||||
# l -> r view range.
|
||||
rightmost = max(
|
||||
min(last, ceil(r)),
|
||||
min(last, ceil(xr)),
|
||||
first,
|
||||
)
|
||||
|
||||
leftmost = min(
|
||||
max(first, floor(l)),
|
||||
max(first, floor(xl)),
|
||||
last,
|
||||
rightmost - 1,
|
||||
)
|
||||
|
@ -632,12 +632,12 @@ class Viz(Struct):
|
|||
self.vs.xrange = leftmost, rightmost
|
||||
|
||||
return (
|
||||
l, # left x-in-view
|
||||
xl, # left x-in-view
|
||||
first, # first datum
|
||||
leftmost,
|
||||
rightmost,
|
||||
last, # last_datum
|
||||
r, # right-x-in-view
|
||||
xr, # right-x-in-view
|
||||
)
|
||||
|
||||
def read(
|
||||
|
@ -665,12 +665,12 @@ class Viz(Struct):
|
|||
profiler('self.shm.array READ')
|
||||
|
||||
(
|
||||
l,
|
||||
xl,
|
||||
ifirst,
|
||||
lbar,
|
||||
rbar,
|
||||
ilast,
|
||||
r,
|
||||
xr,
|
||||
) = self.datums_range(
|
||||
index_field=index_field,
|
||||
array=array,
|
||||
|
@ -715,8 +715,8 @@ class Viz(Struct):
|
|||
# a uniform time stamp step size?
|
||||
else:
|
||||
# get read-relative indices adjusting for master shm index.
|
||||
lbar_i = max(l, ifirst) - ifirst
|
||||
rbar_i = min(r, ilast) - ifirst
|
||||
lbar_i = max(xl, ifirst) - ifirst
|
||||
rbar_i = min(xr, ilast) - ifirst
|
||||
|
||||
# NOTE: the slice here does NOT include the extra ``+ 1``
|
||||
# BUT the ``in_view`` slice DOES..
|
||||
|
@ -1244,18 +1244,25 @@ class Viz(Struct):
|
|||
|
||||
'''
|
||||
# get most recent right datum index in-view
|
||||
l, start, datum_start, datum_stop, stop, r = self.datums_range()
|
||||
(
|
||||
xl,
|
||||
start,
|
||||
datum_start,
|
||||
datum_stop,
|
||||
stop,
|
||||
xr,
|
||||
) = self.datums_range()
|
||||
lasts = self.shm.array[-1]
|
||||
i_step = lasts['index'] # last index-specific step.
|
||||
i_step_t = lasts['time'] # last time step.
|
||||
|
||||
# fqme = self.flume.symbol.fqme
|
||||
# fqme = self.flume.mkt.fqme
|
||||
|
||||
# check if "last (is) in view" -> is a real-time update necessary?
|
||||
if self.index_field == 'index':
|
||||
liv = (r >= i_step)
|
||||
liv = (xr >= i_step)
|
||||
else:
|
||||
liv = (r >= i_step_t)
|
||||
liv = (xr >= i_step_t)
|
||||
|
||||
# compute the first available graphic obj's x-units-per-pixel
|
||||
# TODO: make this not loop through all vizs each time!
|
||||
|
|
|
@ -37,6 +37,9 @@ import pyqtgraph as pg
|
|||
from msgspec import field
|
||||
|
||||
# from .. import brokers
|
||||
from ..accounting import (
|
||||
MktPair,
|
||||
)
|
||||
from ..data.feed import (
|
||||
open_feed,
|
||||
Feed,
|
||||
|
@ -319,8 +322,8 @@ async def graphics_update_loop(
|
|||
for fqme, flume in feed.flumes.items():
|
||||
ohlcv = flume.rt_shm
|
||||
hist_ohlcv = flume.hist_shm
|
||||
symbol = flume.mkt
|
||||
fqme = symbol.fqme
|
||||
mkt = flume.mkt
|
||||
fqme = mkt.fqme
|
||||
|
||||
# update last price sticky
|
||||
fast_viz = fast_chart._vizs[fqme]
|
||||
|
@ -360,13 +363,13 @@ async def graphics_update_loop(
|
|||
|
||||
last, volume = ohlcv.array[-1][['close', 'volume']]
|
||||
|
||||
symbol = flume.mkt
|
||||
mkt = flume.mkt
|
||||
|
||||
l1 = L1Labels(
|
||||
fast_pi,
|
||||
# determine precision/decimal lengths
|
||||
digits=symbol.tick_size_digits,
|
||||
size_digits=symbol.lot_size_digits,
|
||||
digits=mkt.price_tick_digits,
|
||||
size_digits=mkt.size_tick_digits,
|
||||
)
|
||||
|
||||
# TODO:
|
||||
|
@ -449,7 +452,7 @@ async def graphics_update_loop(
|
|||
and quote_rate >= display_rate
|
||||
):
|
||||
pass
|
||||
# log.warning(f'High quote rate {symbol.key}: {quote_rate}')
|
||||
# log.warning(f'High quote rate {mkt.fqme}: {quote_rate}')
|
||||
|
||||
last_quote_s = time.time()
|
||||
|
||||
|
@ -1224,7 +1227,7 @@ async def display_symbol_data(
|
|||
# tf_key = tf_in_1s[step_size_s]
|
||||
godwidget.window.setWindowTitle(
|
||||
f'{fqmes} '
|
||||
# f'tick:{symbol.tick_size} '
|
||||
# f'tick:{mkt.tick_size} '
|
||||
# f'step:{tf_key} '
|
||||
)
|
||||
# generate order mode side-pane UI
|
||||
|
@ -1234,8 +1237,8 @@ async def display_symbol_data(
|
|||
godwidget.pp_pane = pp_pane
|
||||
|
||||
# create top history view chart above the "main rt chart".
|
||||
rt_linked = godwidget.rt_linked
|
||||
hist_linked = godwidget.hist_linked
|
||||
rt_linked: LinkedSplits = godwidget.rt_linked
|
||||
hist_linked: LinkedSplits = godwidget.hist_linked
|
||||
|
||||
# NOTE: here we insert the slow-history chart set into
|
||||
# the fast chart's splitter -> so it's a splitter of charts
|
||||
|
@ -1279,17 +1282,17 @@ async def display_symbol_data(
|
|||
|
||||
# TODO NOTE: THIS CONTROLS WHAT SYMBOL IS USED FOR ORDER MODE
|
||||
# SUBMISSIONS, we need to make this switch based on selection.
|
||||
rt_linked._symbol = flume.mkt
|
||||
hist_linked._symbol = flume.mkt
|
||||
rt_linked.set_mkt_info(flume.mkt)
|
||||
hist_linked.set_mkt_info(flume.mkt)
|
||||
|
||||
ohlcv: ShmArray = flume.rt_shm
|
||||
hist_ohlcv: ShmArray = flume.hist_shm
|
||||
|
||||
symbol = flume.mkt
|
||||
fqme = symbol.fqme
|
||||
mkt: MktPair = flume.mkt
|
||||
fqme = mkt.fqme
|
||||
|
||||
hist_chart = hist_linked.plot_ohlc_main(
|
||||
symbol,
|
||||
mkt,
|
||||
hist_ohlcv,
|
||||
flume,
|
||||
# in the case of history chart we explicitly set `False`
|
||||
|
@ -1311,7 +1314,7 @@ async def display_symbol_data(
|
|||
hist_linked.cursor.always_show_xlabel = False
|
||||
|
||||
rt_chart = rt_linked.plot_ohlc_main(
|
||||
symbol,
|
||||
mkt,
|
||||
ohlcv,
|
||||
flume,
|
||||
# in the case of history chart we explicitly set `False`
|
||||
|
@ -1378,8 +1381,8 @@ async def display_symbol_data(
|
|||
ohlcv: ShmArray = flume.rt_shm
|
||||
hist_ohlcv: ShmArray = flume.hist_shm
|
||||
|
||||
symbol = flume.mkt
|
||||
fqme = symbol.fqme
|
||||
mkt = flume.mkt
|
||||
fqme = mkt.fqme
|
||||
|
||||
hist_pi = hist_chart.overlay_plotitem(
|
||||
name=fqme,
|
||||
|
|
|
@ -29,7 +29,6 @@ from typing import (
|
|||
Any,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import msgspec
|
||||
import tractor
|
||||
import pyqtgraph as pg
|
||||
|
@ -428,7 +427,7 @@ class FspAdmin:
|
|||
in self._flow_registry.items()
|
||||
],
|
||||
|
||||
) as (ctx, last_index),
|
||||
) as (ctx, _),
|
||||
ctx.open_stream() as stream,
|
||||
):
|
||||
|
||||
|
@ -486,8 +485,10 @@ class FspAdmin:
|
|||
readonly=True,
|
||||
)
|
||||
|
||||
portal = self.cluster.get(worker_name) or self.rr_next_portal()
|
||||
provider_tag = portal.channel.uid
|
||||
portal: tractor.Portal = (
|
||||
self.cluster.get(worker_name)
|
||||
or self.rr_next_portal()
|
||||
)
|
||||
|
||||
# TODO: this should probably be turned into a
|
||||
# ``Cascade`` type which describes the routing
|
||||
|
|
|
@ -45,7 +45,10 @@ from ..calc import (
|
|||
pnl,
|
||||
puterize,
|
||||
)
|
||||
from ..accounting._allocate import Allocator
|
||||
from ..accounting import (
|
||||
Allocator,
|
||||
MktPair,
|
||||
)
|
||||
from ..accounting import (
|
||||
Position,
|
||||
)
|
||||
|
@ -244,7 +247,7 @@ class SettingsPane:
|
|||
# a ``brokerd`) then error and switch back to the last
|
||||
# selection.
|
||||
if tracker is None:
|
||||
sym = old_tracker.charts[0].linked.symbol.key
|
||||
sym: str = old_tracker.charts[0].linked.mkt.fqme
|
||||
log.error(
|
||||
f'Account `{account_name}` can not be set for {sym}'
|
||||
)
|
||||
|
@ -415,9 +418,10 @@ class SettingsPane:
|
|||
|
||||
'''
|
||||
mode = self.order_mode
|
||||
sym = mode.chart.linked.symbol
|
||||
mkt: MktPair = mode.chart.linked.mkt
|
||||
size = tracker.live_pp.size
|
||||
flume: Feed = mode.feed.flumes[sym.fqme]
|
||||
fqme: str = mkt.fqme
|
||||
flume: Feed = mode.feed.flumes[fqme]
|
||||
pnl_value = 0
|
||||
|
||||
if size:
|
||||
|
@ -430,7 +434,6 @@ class SettingsPane:
|
|||
|
||||
# maybe start update task
|
||||
global _pnl_tasks
|
||||
fqme = sym.fqme
|
||||
if fqme not in _pnl_tasks:
|
||||
_pnl_tasks[fqme] = True
|
||||
self.order_mode.nursery.start_soon(
|
||||
|
@ -555,7 +558,7 @@ class Nav(Struct):
|
|||
|
||||
'''
|
||||
for key, chart in self.charts.items():
|
||||
size_digits = size_digits or chart.linked.symbol.lot_size_digits
|
||||
size_digits = size_digits or chart.linked.mkt.size_tick_digits
|
||||
line = self.lines.get(key)
|
||||
level_marker = self.level_markers[key]
|
||||
pp_label = self.pp_labels[key]
|
||||
|
|
|
@ -23,7 +23,10 @@ WARNING: this code likely doesn't work at all (yet)
|
|||
"""
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5 import (
|
||||
QtCore,
|
||||
QtWidgets,
|
||||
)
|
||||
|
||||
from .quantdom.charts import CenteredTextItem
|
||||
from .quantdom.base import Quotes
|
||||
|
|
|
@ -36,17 +36,18 @@ import trio
|
|||
from PyQt5.QtCore import Qt
|
||||
|
||||
from .. import config
|
||||
from ..accounting import Position
|
||||
from ..accounting._allocate import (
|
||||
from ..accounting import (
|
||||
Allocator,
|
||||
Position,
|
||||
mk_allocator,
|
||||
MktPair,
|
||||
Symbol,
|
||||
)
|
||||
from ..clearing._client import (
|
||||
open_ems,
|
||||
OrderClient,
|
||||
)
|
||||
from ._style import _font
|
||||
from ..accounting._mktinfo import Symbol
|
||||
from ..accounting import MktPair
|
||||
from ..data.feed import (
|
||||
Feed,
|
||||
Flume,
|
||||
|
@ -93,7 +94,7 @@ class Dialog(Struct):
|
|||
order: Order
|
||||
symbol: str
|
||||
lines: list[LevelLine]
|
||||
last_status_close: Callable = lambda: None
|
||||
last_status_close: Callable | None = None
|
||||
msgs: dict[str, dict] = {}
|
||||
fills: dict[str, Any] = {}
|
||||
|
||||
|
@ -288,10 +289,10 @@ class OrderMode:
|
|||
# since that's illogical / a no-op.
|
||||
return
|
||||
|
||||
symbol = self.chart.linked.symbol
|
||||
mkt: MktPair = self.chart.linked.mkt
|
||||
|
||||
# NOTE : we could also use instead,
|
||||
# symbol.quantize(price, quantity_type='price')
|
||||
# mkt.quantize(price, quantity_type='price')
|
||||
# but it returns a Decimal and it's probably gonna
|
||||
# be slower?
|
||||
# TODO: should we be enforcing this precision
|
||||
|
@ -301,7 +302,7 @@ class OrderMode:
|
|||
|
||||
price = round(
|
||||
price,
|
||||
ndigits=symbol.tick_size_digits,
|
||||
ndigits=mkt.size_tick_digits,
|
||||
)
|
||||
|
||||
order = self._staged_order = Order(
|
||||
|
@ -309,8 +310,8 @@ class OrderMode:
|
|||
price=price,
|
||||
account=self.current_pp.alloc.account,
|
||||
size=0,
|
||||
symbol=symbol,
|
||||
brokers=[symbol.broker],
|
||||
symbol=mkt.fqme,
|
||||
brokers=[mkt.broker],
|
||||
oid='', # filled in on submit
|
||||
exec_mode=trigger_type, # dark or live
|
||||
)
|
||||
|
@ -457,10 +458,10 @@ class OrderMode:
|
|||
the EMS, adjust mirrored level line on secondary chart.
|
||||
|
||||
'''
|
||||
mktinfo = self.chart.linked.symbol
|
||||
mktinfo: MktPair = self.chart.linked.mkt
|
||||
level = round(
|
||||
line.value(),
|
||||
ndigits=mktinfo.tick_size_digits,
|
||||
ndigits=mktinfo.size_tick_digits,
|
||||
)
|
||||
# updated by level change callback set in ``.new_line_from_order()``
|
||||
dialog = line.dialog
|
||||
|
@ -497,7 +498,9 @@ class OrderMode:
|
|||
# a submission is the start of a new order dialog
|
||||
dialog = self.dialogs[uuid]
|
||||
dialog.lines = lines
|
||||
dialog.last_status_close()
|
||||
cls: Callable | None = dialog.last_status_close
|
||||
if cls:
|
||||
cls()
|
||||
|
||||
for line in lines:
|
||||
|
||||
|
@ -549,7 +552,7 @@ class OrderMode:
|
|||
# XXX: seems to fail on certain types of races?
|
||||
# assert len(lines) == 2
|
||||
if lines:
|
||||
flume: Flume = self.feed.flumes[chart.linked.symbol.fqme]
|
||||
flume: Flume = self.feed.flumes[chart.linked.mkt.fqme]
|
||||
_, _, ratio = flume.get_ds_info()
|
||||
|
||||
for chart, shm in [
|
||||
|
@ -740,15 +743,15 @@ async def open_order_mode(
|
|||
lines = LineEditor(godw=godw)
|
||||
arrows = ArrowEditor(godw=godw)
|
||||
|
||||
# symbol id
|
||||
symbol = chart.linked.symbol
|
||||
# market endpoint info
|
||||
mkt: MktPair = chart.linked.mkt
|
||||
|
||||
# map of per-provider account keys to position tracker instances
|
||||
trackers: dict[str, PositionTracker] = {}
|
||||
|
||||
# load account names from ``brokers.toml``
|
||||
accounts_def = config.load_accounts(
|
||||
providers=[symbol.broker],
|
||||
providers=[mkt.broker],
|
||||
)
|
||||
|
||||
# XXX: ``brokerd`` delivers a set of account names that it
|
||||
|
@ -771,17 +774,17 @@ async def open_order_mode(
|
|||
|
||||
# net-zero pp
|
||||
startup_pp = Position(
|
||||
mkt=symbol,
|
||||
mkt=mkt,
|
||||
size=0,
|
||||
ppu=0,
|
||||
|
||||
# XXX: BLEH, do we care about this on the client side?
|
||||
bs_mktid=symbol.key,
|
||||
bs_mktid=mkt.key,
|
||||
)
|
||||
|
||||
# allocator config
|
||||
alloc = mk_allocator(
|
||||
symbol=symbol,
|
||||
alloc: Allocator = mk_allocator(
|
||||
mkt=mkt,
|
||||
account=account_name,
|
||||
|
||||
# if this startup size is greater the allocator limit,
|
||||
|
|
Loading…
Reference in New Issue