diff --git a/check.py b/check.py deleted file mode 100644 index e8439add..00000000 --- a/check.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Check code quality for vn.py project. -""" - -import logging -import os -import subprocess -from typing import Callable - -logger = logging.Logger(__file__) - - -def check_and_warning(*args: list, fast_fail: bool = False): - """ - Run check and show related warning - """ - passed = True - for i in args: - if isinstance(i, Callable): - print(f"check using {i}") - cwd = os.getcwd() - res = i() - os.chdir(cwd) - if not res: - passed = False - logger.warning("check of %s failed!", i) - if not passed and fast_fail: - return False - return passed - - -def check_flake8(): - """ - Check code with flake8. - """ - passed = True - try: - subprocess.check_call(["python", "-m", "flake8", "./"]) - except subprocess.SubprocessError: - passed = False - return passed - - -def check_all(): - """ - Run check with all tools (only flake8 for now). - """ - return check_and_warning(check_flake8) - - -if __name__ == "__main__": - if not check_all(): - exit(1) - exit(0) diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index 7dd8f770..00000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.doctrees \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 3dbff961..b5eea238 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,5 @@ # vn.py文档 - * [vn.py简介](introduction.md) * [项目安装](install.md) * [基本使用](quickstart.md) diff --git a/docs/locale/en/LC_MESSAGES/introduction.po b/docs/locale/en/LC_MESSAGES/introduction.po deleted file mode 100644 index be28769d..00000000 --- a/docs/locale/en/LC_MESSAGES/introduction.po +++ /dev/null @@ -1,23 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2019, vn.py Team -# This file is distributed under the same license as the vnpy package. -# FIRST AUTHOR , 2019. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: vnpy 2.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-02-13 01:17-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" - -#: ../introduction.md:1 -msgid "vn.py文档" -msgstr "" - diff --git a/docs/locale/introduction.pot b/docs/locale/introduction.pot deleted file mode 100644 index d51b56a1..00000000 --- a/docs/locale/introduction.pot +++ /dev/null @@ -1,22 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2019, vn.py Team -# This file is distributed under the same license as the vnpy package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: vnpy 2.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-02-13 01:17-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: ../introduction.md:1 -msgid "vn.py文档" -msgstr "" - diff --git a/docs/locale/zh-CN/LC_MESSAGES/introduction.po b/docs/locale/zh-CN/LC_MESSAGES/introduction.po deleted file mode 100644 index be28769d..00000000 --- a/docs/locale/zh-CN/LC_MESSAGES/introduction.po +++ /dev/null @@ -1,23 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2019, vn.py Team -# This file is distributed under the same license as the vnpy package. -# FIRST AUTHOR , 2019. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: vnpy 2.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-02-13 01:17-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" - -#: ../introduction.md:1 -msgid "vn.py文档" -msgstr "" - diff --git a/docs/translation-update.sh b/docs/translation-update.sh deleted file mode 100644 index f7ef5ce5..00000000 --- a/docs/translation-update.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -sphinx-build -b gettext . locale -sphinx-intl update -p locale -l zh-CN -l en \ No newline at end of file diff --git a/tests/trader/run.py b/tests/trader/run.py index b319b213..f7bd4df1 100644 --- a/tests/trader/run.py +++ b/tests/trader/run.py @@ -11,6 +11,7 @@ from vnpy.gateway.ctp import CtpGateway from vnpy.gateway.tiger import TigerGateway from vnpy.app.cta_strategy import CtaStrategyApp +from vnpy.app.csv_loader import CsvLoaderApp def main(): @@ -27,6 +28,7 @@ def main(): main_engine.add_gateway(TigerGateway) main_engine.add_app(CtaStrategyApp) + main_engine.add_app(CsvLoaderApp) main_window = MainWindow(main_engine, event_engine) main_window.showMaximized() diff --git a/vnpy/app/csv_loader/__init__.py b/vnpy/app/csv_loader/__init__.py index 390f61c2..c346646f 100644 --- a/vnpy/app/csv_loader/__init__.py +++ b/vnpy/app/csv_loader/__init__.py @@ -1,7 +1,7 @@ from pathlib import Path from vnpy.trader.app import BaseApp -from .csv_loader import APP_NAME, CsvLoader +from .engine import APP_NAME, CsvLoaderEngine class CsvLoaderApp(BaseApp): @@ -10,7 +10,7 @@ class CsvLoaderApp(BaseApp): app_name = APP_NAME app_module = __module__ app_path = Path(__file__).parent - display_name = "CSV行情载入器" - engine_class = CsvLoader + display_name = "CSV加载器" + engine_class = CsvLoaderEngine widget_name = "CsvLoaderWidget" icon_name = "csv.ico" diff --git a/vnpy/app/csv_loader/csv_loader.py b/vnpy/app/csv_loader/csv_loader.py deleted file mode 100644 index 3d8c651a..00000000 --- a/vnpy/app/csv_loader/csv_loader.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -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/engine.py b/vnpy/app/csv_loader/engine.py new file mode 100644 index 00000000..0f4152d2 --- /dev/null +++ b/vnpy/app/csv_loader/engine.py @@ -0,0 +1,99 @@ +""" +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 + + +APP_NAME = "CsvLoader" + + +class CsvLoaderEngine(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, + file_path: str, + symbol: str, + exchange: Exchange, + interval: Interval, + datetime_head: str, + open_head: str, + close_head: str, + low_head: str, + high_head: str, + volume_head: str): + """""" + vt_symbol = f"{symbol}.{exchange.value}" + + start = None + end = None + count = 0 + + with open(file_path, 'rt') as f: + reader = csv.DictReader(f) + + for item in reader: + db_bar = DbBarData() + + db_bar.symbol = symbol + db_bar.exchange = exchange.value + db_bar.datetime = datetime.fromisoformat(item[datetime_head]) + db_bar.interval = interval.value + db_bar.volume = item[volume_head] + db_bar.open_price = item[open_head] + db_bar.high_price = item[high_head] + db_bar.low_price = item[low_head] + db_bar.close_price = item[close_head] + db_bar.vt_symbol = vt_symbol + db_bar.gateway_name = "DB" + + db_bar.save() + + # do some statistics + count += 1 + if not start: + start = db_bar.datetime + + end = db_bar.datetime + + return start, end, count diff --git a/vnpy/app/csv_loader/ui/__init__.py b/vnpy/app/csv_loader/ui/__init__.py index 3a01a8c6..8e613ee3 100644 --- a/vnpy/app/csv_loader/ui/__init__.py +++ b/vnpy/app/csv_loader/ui/__init__.py @@ -1 +1 @@ -from .csv_loader_widget import CsvLoaderWidget +from .widget import CsvLoaderWidget diff --git a/vnpy/app/csv_loader/ui/csv.ico b/vnpy/app/csv_loader/ui/csv.ico new file mode 100644 index 00000000..4c9b9534 Binary files /dev/null and b/vnpy/app/csv_loader/ui/csv.ico differ diff --git a/vnpy/app/csv_loader/ui/csv_loader_widget.py b/vnpy/app/csv_loader/ui/csv_loader_widget.py deleted file mode 100644 index adcb2cc8..00000000 --- a/vnpy/app/csv_loader/ui/csv_loader_widget.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -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 gettext import gettext as _ - -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import QFileDialog, QMessageBox - -from vnpy.event import EventEngine -from vnpy.trader.constant import Exchange, Interval -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): - """""" - # someone ask me to disable maximum button - self.setWindowFlags( - (self.windowFlags() | Qt.CustomizeWindowHint) - & ~Qt.WindowMaximizeButtonHint) - self.ui.setupUi(self) - - for i in Interval: - self.ui.interval_combo.addItem(str(i.name), i) - - for i in Exchange: - self.ui.exchange_combo.addItem(str(i.name), 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() - QMessageBox.information(self, _("载入成功!"), _("CSV行情载入成功!")) diff --git a/vnpy/app/csv_loader/ui/widget.py b/vnpy/app/csv_loader/ui/widget.py new file mode 100644 index 00000000..a9ea2008 --- /dev/null +++ b/vnpy/app/csv_loader/ui/widget.py @@ -0,0 +1,90 @@ +""" +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 gettext import gettext as _ + +from vnpy.event import EventEngine +from vnpy.trader.constant import Exchange, Interval +from vnpy.trader.engine import MainEngine +from vnpy.trader.ui import QtWidgets, QtCore + +from .uic.uic_csv_loader import Ui_CsvLoader +from ..engine import APP_NAME + + +class CsvLoaderWidget(QtWidgets.QWidget): + """""" + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + """""" + super().__init__() + + self.engine = main_engine.get_engine(APP_NAME) + + self.init_ui() + + def init_ui(self): + """""" + self.setWindowFlags( + (self.windowFlags() | QtCore.Qt.CustomizeWindowHint) + & ~QtCore.Qt.WindowMaximizeButtonHint) + + self.ui = Ui_CsvLoader() + self.ui.setupUi(self) + + for i in Interval: + self.ui.interval_combo.addItem(str(i.name), i) + + for i in Exchange: + self.ui.exchange_combo.addItem(str(i.name), i) + + def on_choose_button_pressed(self): + """""" + result: str = QtWidgets.QFileDialog.getOpenFileName(self) + filename = result[0] + if filename: + self.ui.file_edit.setText(filename) + + def on_load_button_pressed(self): + """""" + file_path = self.ui.file_edit.text() + symbol = self.ui.symbol_edit.text() + exchange = self.ui.exchange_combo.currentData() + interval = self.ui.interval_combo.currentData() + datetime_head = self.ui.datetime_edit.text() + open_head = self.ui.open_edit.text() + low_head = self.ui.low_edit.text() + high_head = self.ui.high_edit.text() + close_head = self.ui.close_edit.text() + volume_head = self.ui.volume_edit.text() + + start, end, count = self.engine.load( + file_path, + symbol, + exchange, + interval, + datetime_head, + open_head, + high_head, + low_head, + close_head, + volume_head + ) + + msg = f""" + CSV载入成功 + 代码:{symbol} + 交易所:{exchange.value} + 周期:{interval.value} + 起始:{start} + 结束:{end} + 总数量:{count} + """ + QtWidgets.QMessageBox.information(self, _("载入成功!"), msg)