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 diff --git a/vnpy/app/csv_loader/__init__.py b/vnpy/app/csv_loader/__init__.py new file mode 100644 index 00000000..f97d4319 --- /dev/null +++ b/vnpy/app/csv_loader/__init__.py @@ -0,0 +1,16 @@ +from pathlib import Path + +from vnpy.trader.app import BaseApp +from .csv_loader import APP_NAME, CsvLoader + + +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/csv_loader.py b/vnpy/app/csv_loader/csv_loader.py new file mode 100644 index 00000000..3d8c651a --- /dev/null +++ b/vnpy/app/csv_loader/csv_loader.py @@ -0,0 +1,81 @@ +""" +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 + +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 + +APP_NAME = "CsvLoader" + + +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/ui/__init__.py b/vnpy/app/csv_loader/ui/__init__.py new file mode 100644 index 00000000..3a01a8c6 --- /dev/null +++ b/vnpy/app/csv_loader/ui/__init__.py @@ -0,0 +1 @@ +from .csv_loader_widget import CsvLoaderWidget diff --git a/vnpy/app/csv_loader/ui/csv_loader.ui b/vnpy/app/csv_loader/ui/csv_loader.ui new file mode 100644 index 00000000..73b21e96 --- /dev/null +++ b/vnpy/app/csv_loader/ui/csv_loader.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/csv_loader_widget.py b/vnpy/app/csv_loader/ui/csv_loader_widget.py new file mode 100644 index 00000000..4264ac65 --- /dev/null +++ b/vnpy/app/csv_loader/ui/csv_loader_widget.py @@ -0,0 +1,61 @@ +""" +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_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() + + 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) + 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() diff --git a/vnpy/app/csv_loader/ui/uic/uic_csv_loader.py b/vnpy/app/csv_loader/ui/uic/uic_csv_loader.py new file mode 100644 index 00000000..48789519 --- /dev/null +++ b/vnpy/app/csv_loader/ui/uic/uic_csv_loader.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'csv_loader.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", "载入")) +