commit
03074d4717
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue