Snap y-axis crosshair to min tick(s)
parent
50d2d8517b
commit
f072e2551b
|
@ -1,5 +1,5 @@
|
||||||
# piker: trading gear for hackers
|
# piker: trading gear for hackers
|
||||||
# Copyright (C) 2018-present Tyler Goodlet (in stewardship of piker0)
|
# Copyright (C) Tyler Goodlet (in stewardship for piker0)
|
||||||
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -138,7 +138,10 @@ class ChartSpace(QtGui.QWidget):
|
||||||
Expects a ``numpy`` structured array containing all the ohlcv fields.
|
Expects a ``numpy`` structured array containing all the ohlcv fields.
|
||||||
"""
|
"""
|
||||||
# XXX: let's see if this causes mem problems
|
# XXX: let's see if this causes mem problems
|
||||||
self.window.setWindowTitle(f'piker chart {symbol}')
|
self.window.setWindowTitle(
|
||||||
|
f'piker chart {symbol.key}@{symbol.brokers} '
|
||||||
|
f'tick:{symbol.min_tick}'
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: symbol search
|
# TODO: symbol search
|
||||||
# # of course this doesn't work :eyeroll:
|
# # of course this doesn't work :eyeroll:
|
||||||
|
@ -192,6 +195,7 @@ class LinkedSplitCharts(QtGui.QWidget):
|
||||||
self._cursor: Cursor = None # crosshair graphics
|
self._cursor: Cursor = None # crosshair graphics
|
||||||
self.chart: ChartPlotWidget = None # main (ohlc) chart
|
self.chart: ChartPlotWidget = None # main (ohlc) chart
|
||||||
self.subplots: Dict[Tuple[str, ...], ChartPlotWidget] = {}
|
self.subplots: Dict[Tuple[str, ...], ChartPlotWidget] = {}
|
||||||
|
self.digits: int = 2
|
||||||
|
|
||||||
self.xaxis = DynamicDateAxis(
|
self.xaxis = DynamicDateAxis(
|
||||||
orientation='bottom',
|
orientation='bottom',
|
||||||
|
@ -241,6 +245,7 @@ class LinkedSplitCharts(QtGui.QWidget):
|
||||||
|
|
||||||
The data input struct array must include OHLC fields.
|
The data input struct array must include OHLC fields.
|
||||||
"""
|
"""
|
||||||
|
self.min_tick = symbol.min_tick
|
||||||
self.digits = symbol.digits()
|
self.digits = symbol.digits()
|
||||||
|
|
||||||
# add crosshairs
|
# add crosshairs
|
||||||
|
@ -652,7 +657,7 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
chart=self,
|
chart=self,
|
||||||
parent=self.getAxis('right'),
|
parent=self.getAxis('right'),
|
||||||
# TODO: pass this from symbol data
|
# TODO: pass this from symbol data
|
||||||
# digits=0,
|
digits=self._lc._symbol.digits(),
|
||||||
opacity=1,
|
opacity=1,
|
||||||
bg_color=bg_color,
|
bg_color=bg_color,
|
||||||
)
|
)
|
||||||
|
@ -854,8 +859,6 @@ async def _async_main(
|
||||||
# historical data fetch
|
# historical data fetch
|
||||||
brokermod = brokers.get_brokermod(brokername)
|
brokermod = brokers.get_brokermod(brokername)
|
||||||
|
|
||||||
symbol = Symbol(sym, [brokername])
|
|
||||||
|
|
||||||
async with data.open_feed(
|
async with data.open_feed(
|
||||||
brokername,
|
brokername,
|
||||||
[sym],
|
[sym],
|
||||||
|
@ -864,6 +867,7 @@ async def _async_main(
|
||||||
|
|
||||||
ohlcv = feed.shm
|
ohlcv = feed.shm
|
||||||
bars = ohlcv.array
|
bars = ohlcv.array
|
||||||
|
symbol = feed.symbols[sym]
|
||||||
|
|
||||||
# load in symbol's ohlc data
|
# load in symbol's ohlc data
|
||||||
linked_charts, chart = chart_app.load_symbol(symbol, bars)
|
linked_charts, chart = chart_app.load_symbol(symbol, bars)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# piker: trading gear for hackers
|
# piker: trading gear for hackers
|
||||||
# Copyright (C) 2018-present Tyler Goodlet (in stewardship of piker0)
|
# Copyright (C) Tyler Goodlet (in stewardship for piker0)
|
||||||
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -226,6 +226,10 @@ class Cursor(pg.GraphicsObject):
|
||||||
self._hovered: Set[pg.GraphicsObject] = set()
|
self._hovered: Set[pg.GraphicsObject] = set()
|
||||||
self._trackers: Set[pg.GraphicsObject] = set()
|
self._trackers: Set[pg.GraphicsObject] = set()
|
||||||
|
|
||||||
|
# value used for rounding y-axis discreet tick steps
|
||||||
|
# computing once, up front, here cuz why not
|
||||||
|
self._y_incr_mult = 1 / self.lsc._symbol.min_tick
|
||||||
|
|
||||||
def add_hovered(
|
def add_hovered(
|
||||||
self,
|
self,
|
||||||
item: pg.GraphicsObject,
|
item: pg.GraphicsObject,
|
||||||
|
@ -347,25 +351,31 @@ class Cursor(pg.GraphicsObject):
|
||||||
x, y = mouse_point.x(), mouse_point.y()
|
x, y = mouse_point.x(), mouse_point.y()
|
||||||
plot = self.active_plot
|
plot = self.active_plot
|
||||||
|
|
||||||
# update y-range items
|
|
||||||
self.graphics[plot]['hl'].setY(y)
|
|
||||||
|
|
||||||
|
|
||||||
self.graphics[self.active_plot]['yl'].update_label(
|
|
||||||
abs_pos=pos, value=y
|
|
||||||
)
|
|
||||||
|
|
||||||
# Update x if cursor changed after discretization calc
|
# Update x if cursor changed after discretization calc
|
||||||
# (this saves draw cycles on small mouse moves)
|
# (this saves draw cycles on small mouse moves)
|
||||||
lastx, lasty = self._datum_xy
|
last_ix, last_iy = self._datum_xy
|
||||||
|
|
||||||
ix = round(x) # since bars are centered around index
|
ix = round(x) # since bars are centered around index
|
||||||
|
|
||||||
# update all trackers
|
# round y value to nearest tick step
|
||||||
for item in self._trackers:
|
m = self._y_incr_mult
|
||||||
# print(f'setting {item} with {(ix, y)}')
|
iy = round(y * m) / m
|
||||||
item.on_tracked_source(ix, y)
|
|
||||||
|
|
||||||
if ix != lastx:
|
if iy != last_iy:
|
||||||
|
|
||||||
|
# update y-range items
|
||||||
|
self.graphics[plot]['hl'].setY(iy)
|
||||||
|
|
||||||
|
self.graphics[self.active_plot]['yl'].update_label(
|
||||||
|
abs_pos=pos, value=iy
|
||||||
|
)
|
||||||
|
|
||||||
|
# update all trackers
|
||||||
|
for item in self._trackers:
|
||||||
|
# print(f'setting {item} with {(ix, y)}')
|
||||||
|
item.on_tracked_source(ix, iy)
|
||||||
|
|
||||||
|
if ix != last_ix:
|
||||||
for plot, opts in self.graphics.items():
|
for plot, opts in self.graphics.items():
|
||||||
|
|
||||||
# move the vertical line to the current "center of bar"
|
# move the vertical line to the current "center of bar"
|
||||||
|
@ -390,7 +400,7 @@ class Cursor(pg.GraphicsObject):
|
||||||
value=x,
|
value=x,
|
||||||
)
|
)
|
||||||
|
|
||||||
self._datum_xy = ix, y
|
self._datum_xy = ix, iy
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in New Issue