Merge pull request #145 from pikers/y_zoom

Y zoom
readme_bumpz
goodboy 2021-01-15 21:07:02 -05:00 committed by GitHub
commit 03074d4717
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 42 deletions

View File

@ -622,7 +622,8 @@ async def fill_bars(
sym: str,
first_bars: list,
shm: 'ShmArray', # type: ignore # noqa
count: int = 21, # NOTE: any more and we'll overrun the underlying buffer
# count: int = 20, # NOTE: any more and we'll overrun the underlying buffer
count: int = 2, # NOTE: any more and we'll overrun the underlying buffer
) -> None:
"""Fill historical bars into shared mem / storage afap.
@ -647,12 +648,24 @@ async def fill_bars(
next_dt = bars[0].date
except RequestError as err:
# TODO: retreive underlying ``ib_insync`` error~~
if err.code == 162:
log.exception(
"Data query rate reached: Press `ctrl-alt-f` in TWS")
# TODO: retreive underlying ``ib_insync`` error?
await tractor.breakpoint()
if err.code == 162:
if 'HMDS query returned no data' in err.message:
# means we hit some kind of historical "dead zone"
# and further requests seem to always cause
# throttling despite the rps being low
break
else:
log.exception(
"Data query rate reached: Press `ctrl-alt-f` in TWS")
# TODO: should probably create some alert on screen
# and then somehow get that to trigger an event here
# that restarts/resumes this task?
await tractor.breakpoint()
# TODO: figure out how to share quote feeds sanely despite

View File

@ -384,7 +384,6 @@ class ChartPlotWidget(pg.PlotWidget):
# self.setViewportMargins(0, 0, 0, 0)
self._ohlc = array # readonly view of ohlc data
self.default_view()
self._arrays = {} # readonly view of overlays
self._graphics = {} # registry of underlying graphics
@ -406,6 +405,8 @@ class ChartPlotWidget(pg.PlotWidget):
# show background grid
self.showGrid(x=True, y=True, alpha=0.5)
self.default_view()
# TODO: stick in config
# use cross-hair for cursor?
# self.setCursor(QtCore.Qt.CrossCursor)
@ -478,10 +479,13 @@ class ChartPlotWidget(pg.PlotWidget):
"""
xlast = self._ohlc[index]['index']
print(xlast)
begin = xlast - _bars_to_left_in_follow_mode
end = xlast + _bars_from_right_in_follow_mode
# remove any custom user yrange setttings
if self._static_yrange == 'axis':
self._static_yrange = None
self.plotItem.vb.setXRange(
min=begin,
max=end,
@ -697,7 +701,12 @@ class ChartPlotWidget(pg.PlotWidget):
data set.
"""
if self._static_yrange is not None:
set_range = True
if self._static_yrange == 'axis':
set_range = False
elif self._static_yrange is not None:
ylow, yhigh = self._static_yrange
elif yrange is not None:
@ -761,44 +770,46 @@ class ChartPlotWidget(pg.PlotWidget):
ylow = np.nanmin(bars)
yhigh = np.nanmax(bars)
# view margins: stay within a % of the "true range"
diff = yhigh - ylow
ylow = ylow - (diff * 0.04)
yhigh = yhigh + (diff * 0.04)
if set_range:
# view margins: stay within a % of the "true range"
diff = yhigh - ylow
ylow = ylow - (diff * 0.04)
yhigh = yhigh + (diff * 0.04)
# # compute contents label "height" in view terms
# # to avoid having data "contents" overlap with them
# if self._labels:
# label = self._labels[self.name][0]
self.setLimits(
yMin=ylow,
yMax=yhigh,
)
self.setYRange(ylow, yhigh)
# rect = label.itemRect()
# tl, br = rect.topLeft(), rect.bottomRight()
# vb = self.plotItem.vb
# def _label_h(self, yhigh: float, ylow: float) -> float:
# # compute contents label "height" in view terms
# # to avoid having data "contents" overlap with them
# if self._labels:
# label = self._labels[self.name][0]
# try:
# # on startup labels might not yet be rendered
# top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y())
# rect = label.itemRect()
# tl, br = rect.topLeft(), rect.bottomRight()
# vb = self.plotItem.vb
# # XXX: magic hack, how do we compute exactly?
# label_h = (top - bottom) * 0.42
# try:
# # on startup labels might not yet be rendered
# top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y())
# except np.linalg.LinAlgError:
# label_h = 0
# else:
# label_h = 0
# # XXX: magic hack, how do we compute exactly?
# label_h = (top - bottom) * 0.42
# # print(f'label height {self.name}: {label_h}')
# except np.linalg.LinAlgError:
# label_h = 0
# else:
# label_h = 0
# if label_h > yhigh - ylow:
# label_h = 0
# print(f"bounds (ylow, yhigh): {(ylow, yhigh)}")
label_h = 0
# # print(f'label height {self.name}: {label_h}')
self.setLimits(
yMin=ylow,
yMax=yhigh + label_h,
)
self.setYRange(ylow, yhigh + label_h)
# if label_h > yhigh - ylow:
# label_h = 0
# print(f"bounds (ylow, yhigh): {(ylow, yhigh)}")
def enterEvent(self, ev): # noqa
# pg.PlotWidget.enterEvent(self, ev)
@ -1137,7 +1148,7 @@ async def spawn_fsps(
"""Start an fsp subactor async.
"""
print(f'FSP NAME: {fsp_name}')
# print(f'FSP NAME: {fsp_name}')
portal = await n.run_in_actor(
# subactor entrypoint

View File

@ -17,6 +17,8 @@
"""
UX interaction customs.
"""
from typing import Optional
import pyqtgraph as pg
from pyqtgraph import ViewBox, Point, QtCore, QtGui
from pyqtgraph import functions as fn
@ -144,7 +146,7 @@ class SelectRect(QtGui.QGraphicsRectItem):
x1, x2 = start_pos.x(), end_pos.x()
# TODO: heh, could probably use a max-min streamin algo here too
ymn, xmn = min(y1, y2), min(x1, x2)
_, xmn = min(y1, y2), min(x1, x2)
ymx, xmx = max(y1, y2), max(x1, x2)
pchng = (y2 - y1) / y1 * 100
@ -277,7 +279,11 @@ class ChartView(ViewBox):
ev.accept()
self.sigRangeChangedManually.emit(mask)
def mouseDragEvent(self, ev, axis=None):
def mouseDragEvent(
self,
ev,
axis: Optional[int] = None,
) -> None:
# if axis is specified, event will only affect that axis.
ev.accept() # we accept all buttons
@ -295,6 +301,18 @@ class ChartView(ViewBox):
# Scale or translate based on mouse button
if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
# zoom only y-axis when click-n-drag on it
if axis == 1:
# set a static y range special value on chart widget to
# prevent sizing to data in view.
self._chart._static_yrange = 'axis'
scale_y = 1.3 ** (dif.y() * -1 / 20)
self.setLimits(yMin=None, yMax=None)
# print(scale_y)
self.scaleBy((0, scale_y))
if self.state['mouseMode'] == ViewBox.RectMode:
down_pos = ev.buttonDownPos()
@ -333,6 +351,7 @@ class ChartView(ViewBox):
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
elif ev.button() & QtCore.Qt.RightButton:
# print "vb.rightDrag"
if self.state['aspectLocked'] is not False:
mask[0] = 0