用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

547 lines
19 KiB

10 months ago
from .ui_basic import CandlestickItem, VolumeItem
from ..common.constant import Interval
from ..data import database_manager
from ..common.utility import extract_full_symbol
from ..common.datastruct import Event
from ..data.data_board import BarGenerator
import sys
import numpy as np
from PyQt5 import QtCore, QtWidgets, QtGui
from datetime import timedelta, datetime
import pyqtgraph as pg
sys.path.insert(0, "../..")
class MarketDataView(QtWidgets.QWidget):
tick_signal = QtCore.pyqtSignal(Event)
symbol_signal = QtCore.pyqtSignal(str)
def __init__(self, sym: str = ""):
""""""
super().__init__()
self.full_symbol = ""
self.init_ui()
self.register_event()
def init_ui(self):
self.datachart = QuotesChart(self.full_symbol)
self.orderbook = OrderBookWidget()
self.scroll = QtWidgets.QScrollArea()
self.scroll.setWidget(self.datachart)
self.scroll.setWidgetResizable(True)
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self.scroll)
hbox.addWidget(self.orderbook)
self.setLayout(hbox)
def register_event(self):
""""""
self.tick_signal.connect(self.orderbook.tick_signal.emit)
self.tick_signal.connect(self.datachart.on_tick)
self.symbol_signal.connect(self.orderbook.symbol_signal.emit)
self.orderbook.symbol_signal.connect(self.datachart.reset)
self.orderbook.day_signal.connect(self.datachart.reload)
# self.symbol_signal.connect(self.datachart.reset)
class DateAxis(pg.AxisItem):
"""Axis for showing date data"""
def __init__(self, dates: dict, *args, **kwargs):
""""""
super().__init__(*args, **kwargs)
self.dates = dates
def tickStrings(self, values, scale, spacing):
""""""
strings = []
for v in values:
dt = self.dates.get(v, "")
strings.append(str(dt))
return strings
class DateAxis2(pg.AxisItem):
"""Axis for showing date data"""
def __init__(self, datalist: list, *args, **kwargs):
""""""
super().__init__(*args, **kwargs)
self.data = datalist
def tickStrings(self, values, scale, spacing):
""""""
strings = []
# 60*(self.data[0].datetime.hour - 9) + self.data[0].datetime.minute
xstart = 0
for value in values:
v = value - xstart
if v > len(self.data) - 1 or v < 0:
return strings
dt = self.data[int(v)].datetime
strings.append(dt.strftime('%H:%M\n %b-%d '))
return strings
class PriceAxis(pg.AxisItem):
def __init__(self):
super().__init__(orientation='right')
self.style.update({'textFillLimits': [(0, 0.8)]})
def tickStrings(self, vals, scale, spacing):
digts = max(0, np.ceil(-np.log10(spacing * scale)))
return [
('{:<8,.%df}' % digts).format(v).replace(',', ' ') for v in vals
]
class VolumeAxis(pg.AxisItem):
def __init__(self):
super().__init__(orientation='right')
self.style.update({'textFillLimits': [(0, 0.8)]})
def tickStrings(self, vals, scale, spacing):
digts = max(0, np.ceil(-np.log10(spacing * scale)))
return [
('{:<8,.%df}' % digts).format(v).replace(',', ' ') for v in vals
]
class OpenInterestAxis(pg.AxisItem):
def __init__(self):
super().__init__(orientation='left')
self.style.update({'textFillLimits': [(0, 0.8)]})
def tickStrings(self, vals, scale, spacing):
digts = max(0, np.ceil(-np.log10(spacing * scale)))
return [
('{:<8,.%df}' % digts).format(v).replace(',', ' ') for v in vals
]
CHART_MARGINS = (0, 0, 20, 10)
class QuotesChart(QtGui.QWidget):
signal = QtCore.pyqtSignal(Event)
long_pen = pg.mkPen('#006000')
long_brush = pg.mkBrush('#00ff00')
short_pen = pg.mkPen('#600000')
short_brush = pg.mkBrush('#ff0000')
zoomIsDisabled = QtCore.pyqtSignal(bool)
def __init__(self, symbol: str = ""):
super().__init__()
self.full_symbol = symbol
self.data = []
self.bg = BarGenerator(self.on_bar)
self.layout = QtGui.QVBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.chart = None
self.charv = None
self.load_bar()
self.plot()
def reset(self, symbol: str):
# if not self.layout.isEmpty():
# self.layout.removeWidget(self.splitter)
# self.splitter.deleteLater()
# self.full_symbol = symbol
# self.bg = BarGenerator(self.on_bar)
# self.load_bar()
# self.plot()
self.full_symbol = symbol
self.bg = BarGenerator(self.on_bar)
self.load_bar()
self.klineitem.generatePicture()
self.volumeitem.generatePicture()
self.oicurve.setData([bar.open_interest for bar in self.data])
def plot(self):
self.xaxis = DateAxis2(self.data, orientation='bottom')
self.xaxis.setStyle(
tickTextOffset=7, textFillLimits=[(0, 0.80)], showValues=True
)
self.klineitem = CandlestickItem(self.data)
self.volumeitem = VolumeItem(self.data)
self.oicurve = pg.PlotCurveItem(
[bar.open_interest for bar in self.data], pen='w')
self.init_chart()
self.init_chart_item()
def load_bar(self, days: int = 1, interval: Interval = Interval.MINUTE):
symbol, exchange = extract_full_symbol(self.full_symbol)
end = datetime.now()
start = end - timedelta(days)
if start > end:
tmp = end
end = start
start = tmp
bars = database_manager.load_bar_data(
symbol=symbol,
exchange=exchange,
interval=interval,
start=start,
end=end,
)
self.data.clear()
self.data.extend(bars)
def reload(self, count=1):
self.load_bar(days=count)
self.klineitem.generatePicture()
self.volumeitem.generatePicture()
self.oicurve.setData([bar.open_interest for bar in self.data])
def on_bar(self, bar):
self.data.append(bar)
self.klineitem.on_bar(bar)
self.volumeitem.on_bar(bar)
self.oicurve.setData([abar.open_interest for abar in self.data])
# self.xaxis.on_bar(bar)
# self.tmax += 1
# self.pmax = max(self.pmax,bar.high_price)
# self.pmin = min(self.pmin,bar.low_price)
# self.chart.setLimits(
# xMin=self.tmin,
# xMax=self.tmax,
# minXRange=60,
# yMin=self.pmin * 0.95,
# yMax=self.pmax * 1.05,
# )
def on_tick(self, tickevent):
tick = tickevent.data
if tick.full_symbol == self.full_symbol:
self.bg.update_tick(tick)
def init_chart_item(self):
self.chart.addItem(self.klineitem)
# barf = self.data[0]
# bare = self.data[-1]
# self.tmin = 60*(barf.datetime.hour - 9) + barf.datetime.minute - 20
# self.tmax = 60*(bare.datetime.hour - 9) + bare.datetime.minute + 20
# self.pmax = 0
# self.pmin = 999999
# for bar in self.data:
# self.pmax = max(self.pmax,bar.high_price)
# self.pmin = min(self.pmin,bar.low_price)
# self.chart.setLimits(
# xMin=self.tmin,
# xMax=self.tmax,
# minXRange=60,
# yMin=self.pmin * 0.95,
# yMax=self.pmax * 1.05,
# )
self.chartv.addItem(self.volumeitem)
# self.chart.setCursor(QtCore.Qt.BlankCursor)
# self.chart.sigXRangeChanged.connect(self._update_yrange_limits)
# def _update_yrange_limits(self):
# vr = self.chart.viewRect()
# lbar, rbar = max(0,int(vr.left())), min(len(self.data),int(vr.right()))
# bars = self.data[lbar:rbar]
# pmax = 0
# pmin = 999999
# pmean = 0
# for bar in bars:
# pmax = max(pmax,bar.high_price)
# pmin = min(pmin,bar.low_price)
# pmean += bar.close_price
# pmean = pmean/(len(bars))
# ylow = pmin * 0.95
# yhigh = pmax * 1.05
# print(pmax-pmean)
# self.chart.setLimits(yMin=ylow, yMax=yhigh, minYRange= 0.5*abs(pmax-pmean))
# self.chart.setYRange(ylow, yhigh)
def init_chart(self):
self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
self.splitter.setHandleWidth(0)
self.layout.addWidget(self.splitter)
self.chart = pg.PlotWidget(
parent=self.splitter,
axisItems={'bottom': self.xaxis, 'right': PriceAxis()},
enableMenu=True,
)
self.chart.getPlotItem().setContentsMargins(0, 0, 20, 0)
self.chart.setFrameStyle(QtGui.QFrame.StyledPanel | QtGui.QFrame.Plain)
self.chart.hideAxis('left')
self.chart.showAxis('right')
self.chart.showGrid(x=True, y=True)
self.chartv = pg.PlotWidget(
parent=self.splitter,
axisItems={'bottom': self.xaxis,
'right': VolumeAxis(), 'left': OpenInterestAxis()},
enableMenu=True,
)
self.chartv.getPlotItem().setContentsMargins(0, 0, 15, 15)
self.chartv.setFrameStyle(
QtGui.QFrame.StyledPanel | QtGui.QFrame.Plain)
# self.chartv.hideAxis('left')
self.chartv.showAxis('left')
self.chartv.showAxis('right')
self.chartv.setXLink(self.chart)
self.chartoi = pg.ViewBox()
p1 = self.chartv.getPlotItem()
p1.scene().addItem(self.chartoi)
p1.getAxis('left').linkToView(self.chartoi)
self.chartoi.setXLink(p1)
p1.vb.sigResized.connect(self.updateViews)
self.chartoi.addItem(self.oicurve)
def updateViews(self):
p1 = self.chartv.getPlotItem()
p2 = self.chartoi
p2.setGeometry(p1.vb.sceneBoundingRect())
p2.linkedViewChanged(p1.vb, p2.XAxis)
class OrderBookWidget(QtWidgets.QWidget):
tick_signal = QtCore.pyqtSignal(Event)
symbol_signal = QtCore.pyqtSignal(str)
day_signal = QtCore.pyqtSignal(int)
def __init__(self):
""""""
super().__init__()
self.full_symbol = ""
self.init_ui()
self.register_event()
self.clear_label_text()
def init_ui(self):
self.symbol_line = QtWidgets.QLineEdit()
# self.symbol_line.setReadOnly(True)
self.symbol_line.returnPressed.connect(self.process_symbol)
self.change_label = self.create_label(alignment=QtCore.Qt.AlignRight)
self.open_label = self.create_label(alignment=QtCore.Qt.AlignRight)
self.low_label = self.create_label(alignment=QtCore.Qt.AlignRight)
self.high_label = self.create_label(alignment=QtCore.Qt.AlignRight)
bid_color = "rgb(255,174,201)"
ask_color = "rgb(160,255,160)"
self.uplimit_label = self.create_label()
self.bp1_label = self.create_label(bid_color)
self.bp2_label = self.create_label(bid_color)
self.bp3_label = self.create_label(bid_color)
self.bp4_label = self.create_label(bid_color)
self.bp5_label = self.create_label(bid_color)
self.bv1_label = self.create_label(
bid_color, alignment=QtCore.Qt.AlignRight)
self.bv2_label = self.create_label(
bid_color, alignment=QtCore.Qt.AlignRight)
self.bv3_label = self.create_label(
bid_color, alignment=QtCore.Qt.AlignRight)
self.bv4_label = self.create_label(
bid_color, alignment=QtCore.Qt.AlignRight)
self.bv5_label = self.create_label(
bid_color, alignment=QtCore.Qt.AlignRight)
self.ap1_label = self.create_label(ask_color)
self.ap2_label = self.create_label(ask_color)
self.ap3_label = self.create_label(ask_color)
self.ap4_label = self.create_label(ask_color)
self.ap5_label = self.create_label(ask_color)
self.av1_label = self.create_label(
ask_color, alignment=QtCore.Qt.AlignRight)
self.av2_label = self.create_label(
ask_color, alignment=QtCore.Qt.AlignRight)
self.av3_label = self.create_label(
ask_color, alignment=QtCore.Qt.AlignRight)
self.av4_label = self.create_label(
ask_color, alignment=QtCore.Qt.AlignRight)
self.av5_label = self.create_label(
ask_color, alignment=QtCore.Qt.AlignRight)
self.lplimit_lable = self.create_label()
self.lp_label = self.create_label()
self.size_label = self.create_label(alignment=QtCore.Qt.AlignRight)
self.last_volume = 0
form2 = QtWidgets.QFormLayout()
historylabel = self.create_label(alignment=QtCore.Qt.AlignCenter)
historylabel.setText('History Data')
form2.addRow(historylabel)
self.histbar_day = QtWidgets.QLineEdit()
self.histbar_day.setValidator(QtGui.QIntValidator())
self.histbar_day.setText('1')
self.histbar_day.returnPressed.connect(self.process_days)
self.last_days = 1
form2.addRow('Days', self.histbar_day)
self.intervalcombo = QtWidgets.QComboBox()
self.intervalcombo.addItems(["1m", "1h"])
form2.addRow('Interval', self.intervalcombo)
self.indicators = QtWidgets.QComboBox()
self.indicators.addItems(['ma', 'sma'])
form2.addRow('Indicator', self.indicators)
form2.addItem(QtWidgets.QSpacerItem(
40, 40, QtWidgets.QSizePolicy.Expanding))
titlelabel = self.create_label(alignment=QtCore.Qt.AlignCenter)
titlelabel.setText('OrderBook')
# pricelable = self.create_label(alignment=QtCore.Qt.AlignLeft)
# pricelable.setText('Price')
# volumelable = self.create_label(alignment=QtCore.Qt.AlignRight)
# volumelable.setText('Volume')
# verticalSpacer = QtWidgets.QSpacerItem(10, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
form2.addRow(titlelabel)
form2.addRow(self.symbol_line)
form2.addRow(self.change_label, self.open_label)
form2.addRow(self.low_label, self.high_label)
form2.addRow(self.uplimit_label)
form2.addRow(self.ap5_label, self.av5_label)
form2.addRow(self.ap4_label, self.av4_label)
form2.addRow(self.ap3_label, self.av3_label)
form2.addRow(self.ap2_label, self.av2_label)
form2.addRow(self.ap1_label, self.av1_label)
form2.addRow(self.lp_label, self.size_label)
form2.addRow(self.bp1_label, self.bv1_label)
form2.addRow(self.bp2_label, self.bv2_label)
form2.addRow(self.bp3_label, self.bv3_label)
form2.addRow(self.bp4_label, self.bv4_label)
form2.addRow(self.bp5_label, self.bv5_label)
form2.addRow(self.lplimit_lable)
# Overall layout
vbox = QtWidgets.QVBoxLayout()
vbox.addLayout(form2)
self.setLayout(vbox)
self.setFixedWidth(160)
# self.setFixedSize(160,500)
def create_label(self, color: str = "", alignment: int = QtCore.Qt.AlignLeft):
"""
Create label with certain font color.
"""
label = QtWidgets.QLabel()
if color:
label.setStyleSheet(f"color:{color}")
label.setAlignment(alignment)
return label
def register_event(self):
""""""
self.tick_signal.connect(self.process_tick_event)
self.symbol_signal.connect(self.set_full_symbol)
def process_tick_event(self, tickevent: Event):
""""""
tick = tickevent.data
if not tick:
return
if (tick.full_symbol != self.full_symbol):
return
self.lp_label.setText(str(tick.last_price))
self.open_label.setText(str(tick.open_price))
self.low_label.setText(str(tick.low_price))
self.high_label.setText(str(tick.high_price))
self.size_label.setText(str(tick.volume - self.last_volume))
self.last_volume = tick.volume
self.bp1_label.setText(str(tick.bid_price_1))
self.bv1_label.setText(str(tick.bid_volume_1))
self.ap1_label.setText(str(tick.ask_price_1))
self.av1_label.setText(str(tick.ask_volume_1))
self.uplimit_label.setText(str(tick.limit_up))
self.lplimit_lable.setText(str(tick.limit_down))
if tick.pre_close != 0.0:
r = (tick.last_price / tick.pre_close - 1) * 100
self.change_label.setText(f"{r:.2f}%")
if tick.depth == 5:
self.bp2_label.setText(str(tick.bid_price_2))
self.bv2_label.setText(str(tick.bid_volume_2))
self.ap2_label.setText(str(tick.ask_price_2))
self.av2_label.setText(str(tick.ask_volume_2))
self.bp3_label.setText(str(tick.bid_price_3))
self.bv3_label.setText(str(tick.bid_volume_3))
self.ap3_label.setText(str(tick.ask_price_3))
self.av3_label.setText(str(tick.ask_volume_3))
self.bp4_label.setText(str(tick.bid_price_4))
self.bv4_label.setText(str(tick.bid_volume_4))
self.ap4_label.setText(str(tick.ask_price_4))
self.av4_label.setText(str(tick.ask_volume_4))
self.bp5_label.setText(str(tick.bid_price_5))
self.bv5_label.setText(str(tick.bid_volume_5))
self.ap5_label.setText(str(tick.ask_price_5))
self.av5_label.setText(str(tick.ask_volume_5))
def process_symbol(self):
sym = self.symbol_line.text()
if sym:
self.symbol_signal.emit(sym)
def process_days(self):
days = int(self.histbar_day.text())
if days != self.last_days:
self.last_days = days
self.day_signal.emit(days)
def set_full_symbol(self, symbol: str):
"""
Set the tick depth data to monitor by full_symbol.
"""
# Update name line widget and clear all labels
self.full_symbol = symbol
self.symbol_line.setText(symbol)
self.clear_label_text()
def clear_label_text(self):
"""
Clear text on all labels.
"""
self.lp_label.setText("Last")
self.change_label.setText("Change")
self.lplimit_lable.setText('LowerLimit')
self.uplimit_label.setText('UpperLimit')
self.open_label.setText('Open')
self.low_label.setText('Low')
self.high_label.setText('High')
self.size_label.setText('Volume')
self.bv1_label.setText("")
self.bv2_label.setText("")
self.bv3_label.setText("")
self.bv4_label.setText("")
self.bv5_label.setText("")
self.av1_label.setText("")
self.av2_label.setText("")
self.av3_label.setText("")
self.av4_label.setText("")
self.av5_label.setText("")
self.bp1_label.setText("")
self.bp2_label.setText("")
self.bp3_label.setText("")
self.bp4_label.setText("")
self.bp5_label.setText("")
self.ap1_label.setText("")
self.ap2_label.setText("")
self.ap3_label.setText("")
self.ap4_label.setText("")
self.ap5_label.setText("")