From 023e6b42210391542cb36ce1e3f241a1016a3b8e Mon Sep 17 00:00:00 2001 From: nanoric Date: Mon, 18 Mar 2019 05:37:18 -0400 Subject: [PATCH 1/5] [Add] CsvLoader --- vnpy/app/csv_loader/CsvLoader.py | 58 ++++++++++++++ vnpy/app/csv_loader/__init__.py | 17 ++++ vnpy/app/csv_loader/base.py | 2 + vnpy/app/csv_loader/ui/__init__.py | 1 + vnpy/app/csv_loader/ui/ui.py | 120 +++++++++++++++++++++++++++++ vnpy/app/csv_loader/ui/widget.py | 46 +++++++++++ 6 files changed, 244 insertions(+) create mode 100644 vnpy/app/csv_loader/CsvLoader.py create mode 100644 vnpy/app/csv_loader/__init__.py create mode 100644 vnpy/app/csv_loader/base.py create mode 100644 vnpy/app/csv_loader/ui/__init__.py create mode 100644 vnpy/app/csv_loader/ui/ui.py create mode 100644 vnpy/app/csv_loader/ui/widget.py diff --git a/vnpy/app/csv_loader/CsvLoader.py b/vnpy/app/csv_loader/CsvLoader.py new file mode 100644 index 00000000..3add2951 --- /dev/null +++ b/vnpy/app/csv_loader/CsvLoader.py @@ -0,0 +1,58 @@ +import csv +from datetime import datetime + +from vnpy.event import EventEngine +from vnpy.trader.constant import Exchange, Interval +from vnpy.trader.database import DbBarData +from vnpy.trader.engine import BaseEngine, MainEngine +from vnpy.trader.object import BarData + +from .base import APP_NAME + + +class CsvLoader(BaseEngine): + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + """""" + super().__init__(main_engine, event_engine, APP_NAME) + + self.file_path: str = '' + + self.symbol: str = "" + self.exchange: Exchange = Exchange.SSE + self.interval: Interval = Interval.MINUTE + self.datetime_head: str = '' + self.open_head: str = '' + self.close_head: str = '' + self.low_head: str = '' + self.high_head: str = '' + self.volume_head: str = '' + + def load(self): + symbol = self.symbol + exchange = self.exchange + interval = self.interval + + datetime_head = self.datetime_head + open_head = self.open_head + close_head = self.close_head + low_head = self.low_head + high_head = self.high_head + volume_head = self.volume_head + + with open(self.file_path, 'rt') as f: + reader = csv.DictReader(f) + for item in reader: + bar = BarData( + '', + symbol, + exchange, + datetime.fromisoformat(item[datetime_head]), + interval, + item[volume_head], + item[open_head], + item[high_head], + item[low_head], + item[close_head], + ) + DbBarData.from_bar(bar).save() diff --git a/vnpy/app/csv_loader/__init__.py b/vnpy/app/csv_loader/__init__.py new file mode 100644 index 00000000..495075c0 --- /dev/null +++ b/vnpy/app/csv_loader/__init__.py @@ -0,0 +1,17 @@ +from pathlib import Path + +from vnpy.trader.app import BaseApp +from .CsvLoader import CsvLoader +from .base import APP_NAME + + +class CsvLoaderApp(BaseApp): + """""" + + app_name = APP_NAME + app_module = __module__ + app_path = Path(__file__).parent + display_name = "CSV行情载入器" + engine_class = CsvLoader + widget_name = "CsvLoaderWidget" + icon_name = "cta.ico" diff --git a/vnpy/app/csv_loader/base.py b/vnpy/app/csv_loader/base.py new file mode 100644 index 00000000..043ba828 --- /dev/null +++ b/vnpy/app/csv_loader/base.py @@ -0,0 +1,2 @@ +APP_NAME = "CsvLoader" +STOPORDER_PREFIX = "STOP" diff --git a/vnpy/app/csv_loader/ui/__init__.py b/vnpy/app/csv_loader/ui/__init__.py new file mode 100644 index 00000000..8e613ee3 --- /dev/null +++ b/vnpy/app/csv_loader/ui/__init__.py @@ -0,0 +1 @@ +from .widget import CsvLoaderWidget diff --git a/vnpy/app/csv_loader/ui/ui.py b/vnpy/app/csv_loader/ui/ui.py new file mode 100644 index 00000000..47a45936 --- /dev/null +++ b/vnpy/app/csv_loader/ui/ui.py @@ -0,0 +1,120 @@ +from PyQt5 import QtCore, QtWidgets +from vnpy.trader.constant import Exchange, Interval + + +class CsvLoaderUI(object): + + def __init__(self, instance: QtWidgets.QDialog): + instance.setObjectName("CsvLoader") + + self.vertical_layout = QtWidgets.QVBoxLayout(instance) + self.vertical_layout.setObjectName("verticalLayout") + self.horizontal_layout = QtWidgets.QHBoxLayout() + self.horizontal_layout.setObjectName("horizontalLayout") + self.choose_button = QtWidgets.QPushButton(instance) + self.choose_button.setObjectName("choose_button") + self.horizontal_layout.addWidget(self.choose_button) + self.file_edit = QtWidgets.QLineEdit(instance) + self.file_edit.setObjectName("file_edit") + self.horizontal_layout.addWidget(self.file_edit) + self.vertical_layout.addLayout(self.horizontal_layout) + self.form_layout = QtWidgets.QFormLayout() + self.form_layout.setObjectName("formLayout") + + self.label_8 = QtWidgets.QLabel(instance) + self.label_8.setObjectName("label_8") + self.form_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.label_8) + self.label_9 = QtWidgets.QLabel(instance) + self.label_9.setObjectName("label_9") + self.form_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_9) + self.symbol_edit = QtWidgets.QLineEdit(instance) + self.symbol_edit.setObjectName("symbol_edit") + self.form_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.symbol_edit) + self.label_12 = QtWidgets.QLabel(instance) + self.label_12.setObjectName("label_12") + self.form_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_12) + self.exchange_combo = QtWidgets.QComboBox(instance) + self.exchange_combo.setObjectName("exchange_combo") + self.form_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.exchange_combo) + self.label_11 = QtWidgets.QLabel(instance) + self.label_11.setObjectName("label_11") + self.form_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_11) + self.interval_combo = QtWidgets.QComboBox(instance) + self.interval_combo.setObjectName("interval_combo") + self.form_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.interval_combo) + self.label = QtWidgets.QLabel(instance) + self.label.setObjectName("label") + self.form_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.label) + self.label_2 = QtWidgets.QLabel(instance) + self.label_2.setObjectName("label_2") + self.form_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.datetime_edit = QtWidgets.QLineEdit(instance) + self.datetime_edit.setObjectName("datetime_edit") + self.form_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.datetime_edit) + self.label_3 = QtWidgets.QLabel(instance) + self.label_3.setObjectName("label_3") + self.form_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.open_edit = QtWidgets.QLineEdit(instance) + self.open_edit.setObjectName("open_edit") + self.form_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.open_edit) + self.label_4 = QtWidgets.QLabel(instance) + self.label_4.setObjectName("label_4") + self.form_layout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_4) + self.high_edit = QtWidgets.QLineEdit(instance) + self.high_edit.setObjectName("high_edit") + self.form_layout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.high_edit) + self.label_5 = QtWidgets.QLabel(instance) + self.label_5.setObjectName("label_5") + self.form_layout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_5) + self.low_edit = QtWidgets.QLineEdit(instance) + self.low_edit.setObjectName("low_edit") + self.form_layout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.low_edit) + self.label_6 = QtWidgets.QLabel(instance) + self.label_6.setObjectName("label_6") + self.form_layout.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_6) + self.close_edit = QtWidgets.QLineEdit(instance) + self.close_edit.setObjectName("close_edit") + self.form_layout.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.close_edit) + self.label_7 = QtWidgets.QLabel(instance) + self.label_7.setObjectName("label_7") + self.form_layout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.label_7) + self.volume_edit = QtWidgets.QLineEdit(instance) + self.volume_edit.setObjectName("volume_edit") + self.form_layout.setWidget(10, QtWidgets.QFormLayout.FieldRole, self.volume_edit) + + self.vertical_layout.addLayout(self.form_layout) + self.load_button = QtWidgets.QPushButton(instance) + self.load_button.setObjectName("load_button") + self.vertical_layout.addWidget(self.load_button) + + for i in Interval: + self.interval_combo.addItem(str(i), i) + + for i in Exchange: + self.exchange_combo.addItem(str(i), i) + + self.retranslate_ui(instance) + QtCore.QMetaObject.connectSlotsByName(instance) + + def retranslate_ui(self, instance): + _translate = QtCore.QCoreApplication.translate + instance.setWindowTitle(_translate("CsvLoader", "Csv载入器")) + self.choose_button.setText(_translate("CsvLoader", "选择文件")) + self.label_8.setText(_translate("CsvLoader", "合约信息")) + self.label_9.setText(_translate("CsvLoader", "Symbol")) + self.label_11.setText(_translate("CsvLoader", "Interval")) + self.label_12.setText(_translate("CsvLoader", "Exchange")) + self.label.setText(_translate("CsvLoader", "表头属性")) + self.label_2.setText(_translate("CsvLoader", "Datetime")) + self.datetime_edit.setText(_translate("CsvLoader", "DateTime")) + self.label_3.setText(_translate("CsvLoader", "Open")) + self.open_edit.setText(_translate("CsvLoader", "Open")) + self.label_4.setText(_translate("CsvLoader", "High")) + self.high_edit.setText(_translate("CsvLoader", "High")) + self.label_5.setText(_translate("CsvLoader", "Low")) + self.low_edit.setText(_translate("CsvLoader", "Low")) + self.label_6.setText(_translate("CsvLoader", "Close")) + self.close_edit.setText(_translate("CsvLoader", "Close")) + self.label_7.setText(_translate("CsvLoader", "Volume")) + self.volume_edit.setText(_translate("CsvLoader", "Volume")) + self.load_button.setText(_translate("CsvLoader", "载入")) diff --git a/vnpy/app/csv_loader/ui/widget.py b/vnpy/app/csv_loader/ui/widget.py new file mode 100644 index 00000000..b189d9f4 --- /dev/null +++ b/vnpy/app/csv_loader/ui/widget.py @@ -0,0 +1,46 @@ +from PyQt5.QtWidgets import QFileDialog +from vnpy.event import EventEngine +from vnpy.trader.engine import MainEngine +from vnpy.trader.ui import QtWidgets + +from .ui import CsvLoaderUI + +from ..CsvLoader import CsvLoader + + +class CsvLoaderWidget(QtWidgets.QWidget): + """""" + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + super().__init__() + self.loader = CsvLoader(main_engine, event_engine) + self.ui: CsvLoaderUI = CsvLoaderUI(self) + + def on_choose_button_pressed(self): + result: str = QFileDialog.getOpenFileName(self) + filename = result[0] + if filename: + self.ui.file_edit.setText(filename) + + def on_load_button_pressed(self): + self.loader.file_path = self.ui.file_edit.text() + self.loader.symbol = self.ui.symbol_edit.text() + self.loader.exchange = self.ui.exchange_combo.currentData() + self.loader.interval = self.ui.interval_combo.currentData() + self.loader.datetime_head = self.ui.datetime_edit.text() + self.loader.open_head = self.ui.open_edit.text() + self.loader.close_head = self.ui.close_edit.text() + self.loader.low_head = self.ui.low_edit.text() + self.loader.high_head = self.ui.high_edit.text() + self.loader.volume_head = self.ui.volume_edit.text() + + self.loader.load() + + + + + + + + + + From 277a6f6be19896fb5f84040d05800fc5642d144d Mon Sep 17 00:00:00 2001 From: nanoric Date: Mon, 18 Mar 2019 05:47:41 -0400 Subject: [PATCH 2/5] [Fix] make flake8 happy --- vnpy/app/csv_loader/ui/widget.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/vnpy/app/csv_loader/ui/widget.py b/vnpy/app/csv_loader/ui/widget.py index b189d9f4..71183554 100644 --- a/vnpy/app/csv_loader/ui/widget.py +++ b/vnpy/app/csv_loader/ui/widget.py @@ -4,12 +4,12 @@ from vnpy.trader.engine import MainEngine from vnpy.trader.ui import QtWidgets from .ui import CsvLoaderUI - from ..CsvLoader import CsvLoader class CsvLoaderWidget(QtWidgets.QWidget): """""" + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): super().__init__() self.loader = CsvLoader(main_engine, event_engine) @@ -34,13 +34,3 @@ class CsvLoaderWidget(QtWidgets.QWidget): self.loader.volume_head = self.ui.volume_edit.text() self.loader.load() - - - - - - - - - - From 6ade6bc3885b442d8cabfd86f5f3afddfb55f3bd Mon Sep 17 00:00:00 2001 From: nanoric Date: Mon, 18 Mar 2019 06:25:44 -0400 Subject: [PATCH 3/5] [Mod] use designer --- compile_ui.py | 89 +++++++++++ vnpy/app/csv_loader/ui/CsvLoader.ui | 166 ++++++++++++++++++++ vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py | 127 +++++++++++++++ vnpy/app/csv_loader/ui/widget.py | 16 +- 4 files changed, 396 insertions(+), 2 deletions(-) create mode 100644 compile_ui.py create mode 100644 vnpy/app/csv_loader/ui/CsvLoader.ui create mode 100644 vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py diff --git a/compile_ui.py b/compile_ui.py new file mode 100644 index 00000000..d49950b0 --- /dev/null +++ b/compile_ui.py @@ -0,0 +1,89 @@ +import subprocess +from argparse import ArgumentParser + +import os +import logging + + +def is_ui_file(path): + return os.path.splitext(path)[1] == '.ui' + + +def is_py_file(path): + return os.path.splitext(path)[1] == '.py' + + +def seek_files(root, comp): # type(str)->list[str] + results = [] + for root, dirs, files in os.walk(root, followlinks=True): + for filename in files: + try: + path = os.path.join(root, filename) + if comp(path): + results.append(path) + except: # noqa + pass + return results + + +class UICompiler(object): + + def __init__(self, root, uic_bin_path, lupdate_bin_path, ts_output, + strip_ui_prefix, + ): # type: (str, str, str, str, bool)->UICompiler + self.root = root + self.lupdate_bin_path = lupdate_bin_path + self.uic_bin_path = uic_bin_path + self.ts_output = ts_output + self.strip_ui_prefix = strip_ui_prefix + + self.ui_files = [] + + def collect_ui(self, path): # type(str)->None + self.ui_files.append(path) + + def compile_ui(self, path, out_path): # type: (str, any)->int + if out_path is None: + dir, filename = os.path.split(path) + basename, ext = os.path.splitext(filename) + out_path = [os.path.join(dir, 'uic/uic_{}.py'.format(basename))] + if self.strip_ui_prefix and basename.startswith('ui'): + out_path[0] = os.path.join(dir, 'uic/uic_{}.py'.format(basename[2:])) + out_path = out_path[0] + uic_dir = os.path.dirname(out_path) + if not os.path.exists(uic_dir): + os.mkdir(uic_dir) + res = subprocess.check_call('{} {} -o {} -x'.format(self.uic_bin_path, path, out_path)) + + logging.info('ui compiled : {}', path) + return res + + def lupdate(self, py_files, ts_output): # type: (list[str], str)->int + uis = " ".join(py_files) + return subprocess.check_call('{} {} -ts {}'.format(self.lupdate_bin_path, uis, ts_output)) + + def compile_all_ui(self): + for ui_file in self.ui_files: + self.compile_ui(ui_file, None) + + def exec_(self): + self.ui_files = seek_files(self.root, comp=is_ui_file) + self.compile_all_ui() + + # translation is not needed currently + # py_files = seek_files(self.root, comp=is_py_file) + # self.lupdate(py_files=py_files, ts_output=self.ts_output) + + +if __name__ == "__main__": + parser = ArgumentParser() + parser.add_argument('--root', default='.') + parser.add_argument('--strip-ui-prefix', type=bool, default=True) + parser.add_argument('--uic', default='pyuic5.exe') + parser.add_argument('--lupdate', default='pylupdate5.exe') + parser.add_argument('--ts-output', default='CryptoTrader/translate.ts') + + args = parser.parse_args() + compiler = UICompiler(root=args.root, uic_bin_path=args.uic, lupdate_bin_path=args.lupdate, ts_output=args.ts_output, + strip_ui_prefix=args.strip_ui_prefix) + compiler.exec_() diff --git a/vnpy/app/csv_loader/ui/CsvLoader.ui b/vnpy/app/csv_loader/ui/CsvLoader.ui new file mode 100644 index 00000000..73b21e96 --- /dev/null +++ b/vnpy/app/csv_loader/ui/CsvLoader.ui @@ -0,0 +1,166 @@ + + + CsvLoader + + + Csv载入器 + + + + + + + + 选择文件 + + + + + + + + + + + + + + 合约信息 + + + + + + + Symbol + + + + + + + + + + Interval + + + + + + + + + + 表头属性 + + + + + + + Datetime + + + + + + + Datetime + + + + + + + Open + + + + + + + Open + + + + + + + High + + + + + + + High + + + + + + + Low + + + + + + + Low + + + + + + + Close + + + + + + + Close + + + + + + + Volume + + + + + + + Volume + + + + + + + Exchange + + + + + + + + + + + + 载入 + + + + + + + + diff --git a/vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py b/vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py new file mode 100644 index 00000000..d768f572 --- /dev/null +++ b/vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '.\vnpy\app\csv_loader\ui\CsvLoader.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_CsvLoader(object): + def setupUi(self, CsvLoader): + CsvLoader.setObjectName("CsvLoader") + self.verticalLayout = QtWidgets.QVBoxLayout(CsvLoader) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.choose_button = QtWidgets.QPushButton(CsvLoader) + self.choose_button.setObjectName("choose_button") + self.horizontalLayout.addWidget(self.choose_button) + self.file_edit = QtWidgets.QLineEdit(CsvLoader) + self.file_edit.setObjectName("file_edit") + self.horizontalLayout.addWidget(self.file_edit) + self.verticalLayout.addLayout(self.horizontalLayout) + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setObjectName("formLayout") + self.label_8 = QtWidgets.QLabel(CsvLoader) + self.label_8.setObjectName("label_8") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.label_8) + self.label_9 = QtWidgets.QLabel(CsvLoader) + self.label_9.setObjectName("label_9") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_9) + self.symbol_edit = QtWidgets.QLineEdit(CsvLoader) + self.symbol_edit.setObjectName("symbol_edit") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.symbol_edit) + self.label_11 = QtWidgets.QLabel(CsvLoader) + self.label_11.setObjectName("label_11") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_11) + self.interval_combo = QtWidgets.QComboBox(CsvLoader) + self.interval_combo.setObjectName("interval_combo") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.interval_combo) + self.label = QtWidgets.QLabel(CsvLoader) + self.label.setObjectName("label") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.label) + self.label_2 = QtWidgets.QLabel(CsvLoader) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.datetime_edit = QtWidgets.QLineEdit(CsvLoader) + self.datetime_edit.setObjectName("datetime_edit") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.datetime_edit) + self.label_3 = QtWidgets.QLabel(CsvLoader) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.open_edit = QtWidgets.QLineEdit(CsvLoader) + self.open_edit.setObjectName("open_edit") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.open_edit) + self.label_4 = QtWidgets.QLabel(CsvLoader) + self.label_4.setObjectName("label_4") + self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_4) + self.high_edit = QtWidgets.QLineEdit(CsvLoader) + self.high_edit.setObjectName("high_edit") + self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.high_edit) + self.label_5 = QtWidgets.QLabel(CsvLoader) + self.label_5.setObjectName("label_5") + self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_5) + self.low_edit = QtWidgets.QLineEdit(CsvLoader) + self.low_edit.setObjectName("low_edit") + self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.low_edit) + self.label_6 = QtWidgets.QLabel(CsvLoader) + self.label_6.setObjectName("label_6") + self.formLayout.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_6) + self.close_edit = QtWidgets.QLineEdit(CsvLoader) + self.close_edit.setObjectName("close_edit") + self.formLayout.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.close_edit) + self.label_7 = QtWidgets.QLabel(CsvLoader) + self.label_7.setObjectName("label_7") + self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.label_7) + self.volume_edit = QtWidgets.QLineEdit(CsvLoader) + self.volume_edit.setObjectName("volume_edit") + self.formLayout.setWidget(10, QtWidgets.QFormLayout.FieldRole, self.volume_edit) + self.label_12 = QtWidgets.QLabel(CsvLoader) + self.label_12.setObjectName("label_12") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_12) + self.exchange_combo = QtWidgets.QComboBox(CsvLoader) + self.exchange_combo.setObjectName("exchange_combo") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.exchange_combo) + self.verticalLayout.addLayout(self.formLayout) + self.load_button = QtWidgets.QPushButton(CsvLoader) + self.load_button.setObjectName("load_button") + self.verticalLayout.addWidget(self.load_button) + + self.retranslateUi(CsvLoader) + QtCore.QMetaObject.connectSlotsByName(CsvLoader) + + def retranslateUi(self, CsvLoader): + _translate = QtCore.QCoreApplication.translate + CsvLoader.setWindowTitle(_translate("CsvLoader", "Csv载入器")) + self.choose_button.setText(_translate("CsvLoader", "选择文件")) + self.label_8.setText(_translate("CsvLoader", "合约信息")) + self.label_9.setText(_translate("CsvLoader", "Symbol")) + self.label_11.setText(_translate("CsvLoader", "Interval")) + self.label.setText(_translate("CsvLoader", "表头属性")) + self.label_2.setText(_translate("CsvLoader", "Datetime")) + self.datetime_edit.setText(_translate("CsvLoader", "Datetime")) + self.label_3.setText(_translate("CsvLoader", "Open")) + self.open_edit.setText(_translate("CsvLoader", "Open")) + self.label_4.setText(_translate("CsvLoader", "High")) + self.high_edit.setText(_translate("CsvLoader", "High")) + self.label_5.setText(_translate("CsvLoader", "Low")) + self.low_edit.setText(_translate("CsvLoader", "Low")) + self.label_6.setText(_translate("CsvLoader", "Close")) + self.close_edit.setText(_translate("CsvLoader", "Close")) + self.label_7.setText(_translate("CsvLoader", "Volume")) + self.volume_edit.setText(_translate("CsvLoader", "Volume")) + self.label_12.setText(_translate("CsvLoader", "Exchange")) + self.load_button.setText(_translate("CsvLoader", "载入")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + CsvLoader = QtWidgets.QDialog() + ui = Ui_CsvLoader() + ui.setupUi(CsvLoader) + CsvLoader.show() + sys.exit(app.exec_()) + diff --git a/vnpy/app/csv_loader/ui/widget.py b/vnpy/app/csv_loader/ui/widget.py index 71183554..9b48cbd6 100644 --- a/vnpy/app/csv_loader/ui/widget.py +++ b/vnpy/app/csv_loader/ui/widget.py @@ -1,9 +1,10 @@ from PyQt5.QtWidgets import QFileDialog from vnpy.event import EventEngine +from vnpy.trader.constant import Interval, Exchange from vnpy.trader.engine import MainEngine from vnpy.trader.ui import QtWidgets -from .ui import CsvLoaderUI +from .uic.uic_CsvLoader import Ui_CsvLoader from ..CsvLoader import CsvLoader @@ -13,7 +14,18 @@ class CsvLoaderWidget(QtWidgets.QWidget): def __init__(self, main_engine: MainEngine, event_engine: EventEngine): super().__init__() self.loader = CsvLoader(main_engine, event_engine) - self.ui: CsvLoaderUI = CsvLoaderUI(self) + self.ui = Ui_CsvLoader() + + self.init_ui() + + def init_ui(self): + self.ui.setupUi(self) + + for i in Interval: + self.ui.interval_combo.addItem(str(i), i) + + for i in Exchange: + self.ui.exchange_combo.addItem(str(i), i) def on_choose_button_pressed(self): result: str = QFileDialog.getOpenFileName(self) From 5ee4672c2957b9ef124979104201a5ac1db7d884 Mon Sep 17 00:00:00 2001 From: nanoric Date: Mon, 18 Mar 2019 06:26:27 -0400 Subject: [PATCH 4/5] [Add] flake8: ignore qt compiled files(uic generated) --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 143e40fd..ab63c931 100644 --- a/.flake8 +++ b/.flake8 @@ -1,5 +1,5 @@ [flake8] -exclude = __pycache__,__init__.py,ib,talib +exclude = __pycache__,__init__.py,ib,talib,uic ignore = E501 line too long, fixed by black W503 line break before binary operator From 969c59a08af4478816ef69a82f75fe924478c978 Mon Sep 17 00:00:00 2001 From: nanoric Date: Tue, 19 Mar 2019 02:36:59 -0400 Subject: [PATCH 5/5] [Add] Added some comments [Mod] rename files --- compile_ui.py | 89 ------------- vnpy/app/csv_loader/__init__.py | 3 +- vnpy/app/csv_loader/base.py | 2 - .../{CsvLoader.py => csv_loader.py} | 25 +++- vnpy/app/csv_loader/ui/__init__.py | 2 +- .../ui/{CsvLoader.ui => csv_loader.ui} | 0 .../ui/{widget.py => csv_loader_widget.py} | 17 ++- vnpy/app/csv_loader/ui/ui.py | 120 ------------------ .../{uic_CsvLoader.py => uic_csv_loader.py} | 12 +- 9 files changed, 42 insertions(+), 228 deletions(-) delete mode 100644 compile_ui.py delete mode 100644 vnpy/app/csv_loader/base.py rename vnpy/app/csv_loader/{CsvLoader.py => csv_loader.py} (73%) rename vnpy/app/csv_loader/ui/{CsvLoader.ui => csv_loader.ui} (100%) rename vnpy/app/csv_loader/ui/{widget.py => csv_loader_widget.py} (84%) delete mode 100644 vnpy/app/csv_loader/ui/ui.py rename vnpy/app/csv_loader/ui/uic/{uic_CsvLoader.py => uic_csv_loader.py} (95%) diff --git a/compile_ui.py b/compile_ui.py deleted file mode 100644 index d49950b0..00000000 --- a/compile_ui.py +++ /dev/null @@ -1,89 +0,0 @@ -import subprocess -from argparse import ArgumentParser - -import os -import logging - - -def is_ui_file(path): - return os.path.splitext(path)[1] == '.ui' - - -def is_py_file(path): - return os.path.splitext(path)[1] == '.py' - - -def seek_files(root, comp): # type(str)->list[str] - results = [] - for root, dirs, files in os.walk(root, followlinks=True): - for filename in files: - try: - path = os.path.join(root, filename) - if comp(path): - results.append(path) - except: # noqa - pass - return results - - -class UICompiler(object): - - def __init__(self, root, uic_bin_path, lupdate_bin_path, ts_output, - strip_ui_prefix, - ): # type: (str, str, str, str, bool)->UICompiler - self.root = root - self.lupdate_bin_path = lupdate_bin_path - self.uic_bin_path = uic_bin_path - self.ts_output = ts_output - self.strip_ui_prefix = strip_ui_prefix - - self.ui_files = [] - - def collect_ui(self, path): # type(str)->None - self.ui_files.append(path) - - def compile_ui(self, path, out_path): # type: (str, any)->int - if out_path is None: - dir, filename = os.path.split(path) - basename, ext = os.path.splitext(filename) - out_path = [os.path.join(dir, 'uic/uic_{}.py'.format(basename))] - if self.strip_ui_prefix and basename.startswith('ui'): - out_path[0] = os.path.join(dir, 'uic/uic_{}.py'.format(basename[2:])) - out_path = out_path[0] - uic_dir = os.path.dirname(out_path) - if not os.path.exists(uic_dir): - os.mkdir(uic_dir) - res = subprocess.check_call('{} {} -o {} -x'.format(self.uic_bin_path, path, out_path)) - - logging.info('ui compiled : {}', path) - return res - - def lupdate(self, py_files, ts_output): # type: (list[str], str)->int - uis = " ".join(py_files) - return subprocess.check_call('{} {} -ts {}'.format(self.lupdate_bin_path, uis, ts_output)) - - def compile_all_ui(self): - for ui_file in self.ui_files: - self.compile_ui(ui_file, None) - - def exec_(self): - self.ui_files = seek_files(self.root, comp=is_ui_file) - self.compile_all_ui() - - # translation is not needed currently - # py_files = seek_files(self.root, comp=is_py_file) - # self.lupdate(py_files=py_files, ts_output=self.ts_output) - - -if __name__ == "__main__": - parser = ArgumentParser() - parser.add_argument('--root', default='.') - parser.add_argument('--strip-ui-prefix', type=bool, default=True) - parser.add_argument('--uic', default='pyuic5.exe') - parser.add_argument('--lupdate', default='pylupdate5.exe') - parser.add_argument('--ts-output', default='CryptoTrader/translate.ts') - - args = parser.parse_args() - compiler = UICompiler(root=args.root, uic_bin_path=args.uic, lupdate_bin_path=args.lupdate, ts_output=args.ts_output, - strip_ui_prefix=args.strip_ui_prefix) - compiler.exec_() diff --git a/vnpy/app/csv_loader/__init__.py b/vnpy/app/csv_loader/__init__.py index 495075c0..f97d4319 100644 --- a/vnpy/app/csv_loader/__init__.py +++ b/vnpy/app/csv_loader/__init__.py @@ -1,8 +1,7 @@ from pathlib import Path from vnpy.trader.app import BaseApp -from .CsvLoader import CsvLoader -from .base import APP_NAME +from .csv_loader import APP_NAME, CsvLoader class CsvLoaderApp(BaseApp): diff --git a/vnpy/app/csv_loader/base.py b/vnpy/app/csv_loader/base.py deleted file mode 100644 index 043ba828..00000000 --- a/vnpy/app/csv_loader/base.py +++ /dev/null @@ -1,2 +0,0 @@ -APP_NAME = "CsvLoader" -STOPORDER_PREFIX = "STOP" diff --git a/vnpy/app/csv_loader/CsvLoader.py b/vnpy/app/csv_loader/csv_loader.py similarity index 73% rename from vnpy/app/csv_loader/CsvLoader.py rename to vnpy/app/csv_loader/csv_loader.py index 3add2951..3d8c651a 100644 --- a/vnpy/app/csv_loader/CsvLoader.py +++ b/vnpy/app/csv_loader/csv_loader.py @@ -1,3 +1,25 @@ +""" +Author: nanoric + +Load data from a csv file. + +Differences to 1.9.2: + * combine Date column and Time column into one DateTime column + +Sample csv file: + +```csv +"DateTime","Open","High","Low","Close","Volume" +2010-04-16T09:16:00.000000,3450.0,3488.0,3450.0,3468.0,489 +2010-04-16T09:17:00.000000,3468.0,3473.8,3467.0,3467.0,302 +2010-04-16T09:18:00.000000,3467.0,3471.0,3466.0,3467.0,203 +2010-04-16T09:19:00.000000,3467.0,3468.2,3448.0,3448.0,280 +2010-04-16T09:20:00.000000,3448.0,3459.0,3448.0,3454.0,250 +2010-04-16T09:21:00.000000,3454.0,3456.8,3454.0,3456.8,109 +``` + +""" + import csv from datetime import datetime @@ -7,7 +29,7 @@ from vnpy.trader.database import DbBarData from vnpy.trader.engine import BaseEngine, MainEngine from vnpy.trader.object import BarData -from .base import APP_NAME +APP_NAME = "CsvLoader" class CsvLoader(BaseEngine): @@ -29,6 +51,7 @@ class CsvLoader(BaseEngine): self.volume_head: str = '' def load(self): + """""" symbol = self.symbol exchange = self.exchange interval = self.interval diff --git a/vnpy/app/csv_loader/ui/__init__.py b/vnpy/app/csv_loader/ui/__init__.py index 8e613ee3..3a01a8c6 100644 --- a/vnpy/app/csv_loader/ui/__init__.py +++ b/vnpy/app/csv_loader/ui/__init__.py @@ -1 +1 @@ -from .widget import CsvLoaderWidget +from .csv_loader_widget import CsvLoaderWidget diff --git a/vnpy/app/csv_loader/ui/CsvLoader.ui b/vnpy/app/csv_loader/ui/csv_loader.ui similarity index 100% rename from vnpy/app/csv_loader/ui/CsvLoader.ui rename to vnpy/app/csv_loader/ui/csv_loader.ui diff --git a/vnpy/app/csv_loader/ui/widget.py b/vnpy/app/csv_loader/ui/csv_loader_widget.py similarity index 84% rename from vnpy/app/csv_loader/ui/widget.py rename to vnpy/app/csv_loader/ui/csv_loader_widget.py index 9b48cbd6..4264ac65 100644 --- a/vnpy/app/csv_loader/ui/widget.py +++ b/vnpy/app/csv_loader/ui/csv_loader_widget.py @@ -1,17 +1,27 @@ +""" +Author: nanoric + +UI is designed by Qt Designer. source at csv_loader.ui +compile: +``` +pyuic5 csv_loader.ui -o uic/uic_csv_loader.py +``` +""" from PyQt5.QtWidgets import QFileDialog from vnpy.event import EventEngine from vnpy.trader.constant import Interval, Exchange from vnpy.trader.engine import MainEngine from vnpy.trader.ui import QtWidgets -from .uic.uic_CsvLoader import Ui_CsvLoader -from ..CsvLoader import CsvLoader +from .uic.uic_csv_loader import Ui_CsvLoader +from ..csv_loader import CsvLoader class CsvLoaderWidget(QtWidgets.QWidget): """""" def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + """""" super().__init__() self.loader = CsvLoader(main_engine, event_engine) self.ui = Ui_CsvLoader() @@ -19,6 +29,7 @@ class CsvLoaderWidget(QtWidgets.QWidget): self.init_ui() def init_ui(self): + """""" self.ui.setupUi(self) for i in Interval: @@ -28,12 +39,14 @@ class CsvLoaderWidget(QtWidgets.QWidget): self.ui.exchange_combo.addItem(str(i), i) def on_choose_button_pressed(self): + """""" result: str = QFileDialog.getOpenFileName(self) filename = result[0] if filename: self.ui.file_edit.setText(filename) def on_load_button_pressed(self): + """""" self.loader.file_path = self.ui.file_edit.text() self.loader.symbol = self.ui.symbol_edit.text() self.loader.exchange = self.ui.exchange_combo.currentData() diff --git a/vnpy/app/csv_loader/ui/ui.py b/vnpy/app/csv_loader/ui/ui.py deleted file mode 100644 index 47a45936..00000000 --- a/vnpy/app/csv_loader/ui/ui.py +++ /dev/null @@ -1,120 +0,0 @@ -from PyQt5 import QtCore, QtWidgets -from vnpy.trader.constant import Exchange, Interval - - -class CsvLoaderUI(object): - - def __init__(self, instance: QtWidgets.QDialog): - instance.setObjectName("CsvLoader") - - self.vertical_layout = QtWidgets.QVBoxLayout(instance) - self.vertical_layout.setObjectName("verticalLayout") - self.horizontal_layout = QtWidgets.QHBoxLayout() - self.horizontal_layout.setObjectName("horizontalLayout") - self.choose_button = QtWidgets.QPushButton(instance) - self.choose_button.setObjectName("choose_button") - self.horizontal_layout.addWidget(self.choose_button) - self.file_edit = QtWidgets.QLineEdit(instance) - self.file_edit.setObjectName("file_edit") - self.horizontal_layout.addWidget(self.file_edit) - self.vertical_layout.addLayout(self.horizontal_layout) - self.form_layout = QtWidgets.QFormLayout() - self.form_layout.setObjectName("formLayout") - - self.label_8 = QtWidgets.QLabel(instance) - self.label_8.setObjectName("label_8") - self.form_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.label_8) - self.label_9 = QtWidgets.QLabel(instance) - self.label_9.setObjectName("label_9") - self.form_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_9) - self.symbol_edit = QtWidgets.QLineEdit(instance) - self.symbol_edit.setObjectName("symbol_edit") - self.form_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.symbol_edit) - self.label_12 = QtWidgets.QLabel(instance) - self.label_12.setObjectName("label_12") - self.form_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_12) - self.exchange_combo = QtWidgets.QComboBox(instance) - self.exchange_combo.setObjectName("exchange_combo") - self.form_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.exchange_combo) - self.label_11 = QtWidgets.QLabel(instance) - self.label_11.setObjectName("label_11") - self.form_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_11) - self.interval_combo = QtWidgets.QComboBox(instance) - self.interval_combo.setObjectName("interval_combo") - self.form_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.interval_combo) - self.label = QtWidgets.QLabel(instance) - self.label.setObjectName("label") - self.form_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.label) - self.label_2 = QtWidgets.QLabel(instance) - self.label_2.setObjectName("label_2") - self.form_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_2) - self.datetime_edit = QtWidgets.QLineEdit(instance) - self.datetime_edit.setObjectName("datetime_edit") - self.form_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.datetime_edit) - self.label_3 = QtWidgets.QLabel(instance) - self.label_3.setObjectName("label_3") - self.form_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_3) - self.open_edit = QtWidgets.QLineEdit(instance) - self.open_edit.setObjectName("open_edit") - self.form_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.open_edit) - self.label_4 = QtWidgets.QLabel(instance) - self.label_4.setObjectName("label_4") - self.form_layout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_4) - self.high_edit = QtWidgets.QLineEdit(instance) - self.high_edit.setObjectName("high_edit") - self.form_layout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.high_edit) - self.label_5 = QtWidgets.QLabel(instance) - self.label_5.setObjectName("label_5") - self.form_layout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_5) - self.low_edit = QtWidgets.QLineEdit(instance) - self.low_edit.setObjectName("low_edit") - self.form_layout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.low_edit) - self.label_6 = QtWidgets.QLabel(instance) - self.label_6.setObjectName("label_6") - self.form_layout.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_6) - self.close_edit = QtWidgets.QLineEdit(instance) - self.close_edit.setObjectName("close_edit") - self.form_layout.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.close_edit) - self.label_7 = QtWidgets.QLabel(instance) - self.label_7.setObjectName("label_7") - self.form_layout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.label_7) - self.volume_edit = QtWidgets.QLineEdit(instance) - self.volume_edit.setObjectName("volume_edit") - self.form_layout.setWidget(10, QtWidgets.QFormLayout.FieldRole, self.volume_edit) - - self.vertical_layout.addLayout(self.form_layout) - self.load_button = QtWidgets.QPushButton(instance) - self.load_button.setObjectName("load_button") - self.vertical_layout.addWidget(self.load_button) - - for i in Interval: - self.interval_combo.addItem(str(i), i) - - for i in Exchange: - self.exchange_combo.addItem(str(i), i) - - self.retranslate_ui(instance) - QtCore.QMetaObject.connectSlotsByName(instance) - - def retranslate_ui(self, instance): - _translate = QtCore.QCoreApplication.translate - instance.setWindowTitle(_translate("CsvLoader", "Csv载入器")) - self.choose_button.setText(_translate("CsvLoader", "选择文件")) - self.label_8.setText(_translate("CsvLoader", "合约信息")) - self.label_9.setText(_translate("CsvLoader", "Symbol")) - self.label_11.setText(_translate("CsvLoader", "Interval")) - self.label_12.setText(_translate("CsvLoader", "Exchange")) - self.label.setText(_translate("CsvLoader", "表头属性")) - self.label_2.setText(_translate("CsvLoader", "Datetime")) - self.datetime_edit.setText(_translate("CsvLoader", "DateTime")) - self.label_3.setText(_translate("CsvLoader", "Open")) - self.open_edit.setText(_translate("CsvLoader", "Open")) - self.label_4.setText(_translate("CsvLoader", "High")) - self.high_edit.setText(_translate("CsvLoader", "High")) - self.label_5.setText(_translate("CsvLoader", "Low")) - self.low_edit.setText(_translate("CsvLoader", "Low")) - self.label_6.setText(_translate("CsvLoader", "Close")) - self.close_edit.setText(_translate("CsvLoader", "Close")) - self.label_7.setText(_translate("CsvLoader", "Volume")) - self.volume_edit.setText(_translate("CsvLoader", "Volume")) - self.load_button.setText(_translate("CsvLoader", "载入")) diff --git a/vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py b/vnpy/app/csv_loader/ui/uic/uic_csv_loader.py similarity index 95% rename from vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py rename to vnpy/app/csv_loader/ui/uic/uic_csv_loader.py index d768f572..48789519 100644 --- a/vnpy/app/csv_loader/ui/uic/uic_CsvLoader.py +++ b/vnpy/app/csv_loader/ui/uic/uic_csv_loader.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file '.\vnpy\app\csv_loader\ui\CsvLoader.ui' +# Form implementation generated from reading ui file 'csv_loader.ui' # # Created by: PyQt5 UI code generator 5.11.3 # @@ -115,13 +115,3 @@ class Ui_CsvLoader(object): self.label_12.setText(_translate("CsvLoader", "Exchange")) self.load_button.setText(_translate("CsvLoader", "载入")) - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - CsvLoader = QtWidgets.QDialog() - ui = Ui_CsvLoader() - ui.setupUi(CsvLoader) - CsvLoader.show() - sys.exit(app.exec_()) -