Simplify L1 labels for multicharts

Instead of having the l1 lines be inside the view space, move them to be
inside their respective axis (with only a 16 unit portion inside the
view) such that the clear price label can overlay with them nicely
without obscuring; this is much better suited to multiple adjacent
y-axes and in general is simpler and less noisy.

Further `L1Labels` + `LevelLabel` style tweaks:
- adjust `.rect` positioning to be "right" (i.e. inside the parent
  y-axis) with a slight 16 unit shift toward the viewbox (using the new
  `._x_br_offset`) to allow seeing each level label's line even when the
  clearing price label is positioned at that same level.
- add a newline's worth of vertical space to each of the bid/ask labels
  so that L1 labels' text content isn't ever obscured by the clear price
  label.
- set a low (10) z-value to ensure l1 labels are always placed
  underneath the clear price label.
- always fill the label rect with the chosen background color.
- make labels fully opaque so as to always make them hide the parent
  axes' `.tickStrings()` contents.
- make default color the "default" from the global scheme.
- drop the "price" part from the l1 label text contents, just show the
  book-queue's amount (in dst asset's units, aka the potential clearing vlm).
l1_compaction
Tyler Goodlet 2022-12-23 14:22:44 -05:00
parent 97b03bbfbb
commit b2bb7f4923
1 changed files with 46 additions and 25 deletions

View File

@ -30,19 +30,20 @@ from ._pg_overrides import PlotItem
class LevelLabel(YAxisLabel): class LevelLabel(YAxisLabel):
"""Y-axis (vertically) oriented, horizontal label that sticks to '''
Y-axis (vertically) oriented, horizontal label that sticks to
where it's placed despite chart resizing and supports displaying where it's placed despite chart resizing and supports displaying
multiple fields. multiple fields.
TODO: replace the rectangle-text part with our new ``Label`` type. TODO: replace the rectangle-text part with our new ``Label`` type.
""" '''
_x_margin = 0 _x_br_offset: float = -16
_y_margin = 0 _x_txt_h_scaling: float = 2
# adjustment "further away from" anchor point # adjustment "further away from" anchor point
_x_offset = 9 _x_offset = 0
_y_offset = 0 _y_offset = 0
# fields to be displayed in the label string # fields to be displayed in the label string
@ -58,12 +59,12 @@ class LevelLabel(YAxisLabel):
chart, chart,
parent, parent,
color: str = 'bracket', color: str = 'default_light',
orient_v: str = 'bottom', orient_v: str = 'bottom',
orient_h: str = 'left', orient_h: str = 'right',
opacity: float = 0, opacity: float = 1,
# makes order line labels offset from their parent axis # makes order line labels offset from their parent axis
# such that they don't collide with the L1/L2 lines/prices # such that they don't collide with the L1/L2 lines/prices
@ -99,13 +100,15 @@ class LevelLabel(YAxisLabel):
self._h_shift = { self._h_shift = {
'left': -1., 'left': -1.,
'right': 0. 'right': 0.,
}[orient_h] }[orient_h]
self.fields = self._fields.copy() self.fields = self._fields.copy()
# ensure default format fields are in correct # ensure default format fields are in correct
self.set_fmt_str(self._fmt_str, self.fields) self.set_fmt_str(self._fmt_str, self.fields)
self.setZValue(10)
@property @property
def color(self): def color(self):
return self._hcolor return self._hcolor
@ -113,7 +116,10 @@ class LevelLabel(YAxisLabel):
@color.setter @color.setter
def color(self, color: str) -> None: def color(self, color: str) -> None:
self._hcolor = color self._hcolor = color
self._pen = self.pen = pg.mkPen(hcolor(color)) self._pen = self.pen = pg.mkPen(
hcolor(color),
width=3,
)
def update_on_resize(self, vr, r): def update_on_resize(self, vr, r):
"""Tiis is a ``.sigRangeChanged()`` handler. """Tiis is a ``.sigRangeChanged()`` handler.
@ -125,10 +131,11 @@ class LevelLabel(YAxisLabel):
self, self,
fields: dict = None, fields: dict = None,
) -> None: ) -> None:
"""Update the label's text contents **and** position from '''
Update the label's text contents **and** position from
a view box coordinate datum. a view box coordinate datum.
""" '''
self.fields.update(fields) self.fields.update(fields)
level = self.fields['level'] level = self.fields['level']
@ -175,7 +182,8 @@ class LevelLabel(YAxisLabel):
fields: dict, fields: dict,
): ):
# use space as e3 delim # use space as e3 delim
self.label_str = self._fmt_str.format(**fields).replace(',', ' ') self.label_str = self._fmt_str.format(
**fields).replace(',', ' ')
br = self.boundingRect() br = self.boundingRect()
h, w = br.height(), br.width() h, w = br.height(), br.width()
@ -188,14 +196,14 @@ class LevelLabel(YAxisLabel):
self, self,
p: QtGui.QPainter, p: QtGui.QPainter,
rect: QtCore.QRectF rect: QtCore.QRectF
) -> None:
p.setPen(self._pen)
) -> None:
p.setPen(self._pen)
rect = self.rect rect = self.rect
if self._orient_v == 'bottom': if self._orient_v == 'bottom':
lp, rp = rect.topLeft(), rect.topRight() lp, rp = rect.topLeft(), rect.topRight()
# p.drawLine(rect.topLeft(), rect.topRight())
elif self._orient_v == 'top': elif self._orient_v == 'top':
lp, rp = rect.bottomLeft(), rect.bottomRight() lp, rp = rect.bottomLeft(), rect.bottomRight()
@ -209,6 +217,11 @@ class LevelLabel(YAxisLabel):
]) ])
) )
p.fillRect(
self.rect,
self.bg_color,
)
def highlight(self, pen) -> None: def highlight(self, pen) -> None:
self._pen = pen self._pen = pen
self.update() self.update()
@ -247,9 +260,10 @@ class L1Label(LevelLabel):
class L1Labels: class L1Labels:
"""Level 1 bid ask labels for dynamic update on price-axis. '''
Level 1 bid ask labels for dynamic update on price-axis.
""" '''
def __init__( def __init__(
self, self,
plotitem: PlotItem, plotitem: PlotItem,
@ -265,15 +279,17 @@ class L1Labels:
'chart': plotitem, 'chart': plotitem,
'parent': raxis, 'parent': raxis,
'opacity': 1, 'opacity': .9,
'font_size': font_size, 'font_size': font_size,
'fg_color': chart.pen_color, 'fg_color': 'default_light',
'bg_color': chart.view_color, 'bg_color': chart.view_color, # normally 'papas_special'
} }
# TODO: add humanized source-asset
# info format.
fmt_str = ( fmt_str = (
' {size:.{size_digits}f} x ' ' {size:.{size_digits}f} u'
'{level:,.{level_digits}f} ' # '{level:,.{level_digits}f} '
) )
fields = { fields = {
'level': 0, 'level': 0,
@ -286,12 +302,17 @@ class L1Labels:
orient_v='bottom', orient_v='bottom',
**kwargs, **kwargs,
) )
bid.set_fmt_str(fmt_str=fmt_str, fields=fields) bid.set_fmt_str(
fmt_str='\n' + fmt_str,
fields=fields,
)
bid.show() bid.show()
ask = self.ask_label = L1Label( ask = self.ask_label = L1Label(
orient_v='top', orient_v='top',
**kwargs, **kwargs,
) )
ask.set_fmt_str(fmt_str=fmt_str, fields=fields) ask.set_fmt_str(
fmt_str=fmt_str,
fields=fields)
ask.show() ask.show()