diff --git a/.gitignore b/.gitignore index 7ac72ffe..15d7ed33 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ build dist *.local + +# vn.py +.vntrader \ No newline at end of file diff --git a/vnpy/app/cta_strategy/engine.py b/vnpy/app/cta_strategy/engine.py index 38ed0581..f7a0ce93 100644 --- a/vnpy/app/cta_strategy/engine.py +++ b/vnpy/app/cta_strategy/engine.py @@ -2,7 +2,6 @@ import importlib import os -import shelve import traceback from collections import defaultdict from pathlib import Path @@ -21,7 +20,7 @@ from vnpy.trader.object import ( ) from vnpy.trader.event import EVENT_TICK, EVENT_ORDER, EVENT_TRADE from vnpy.trader.constant import Direction, PriceType, Interval -from vnpy.trader.utility import get_temp_path, load_json, save_json +from vnpy.trader.utility import load_json, save_json from vnpy.trader.database import DbTickData, DbBarData from .base import ( @@ -43,7 +42,7 @@ class CtaEngine(BaseEngine): engine_type = EngineType.LIVE # live trading engine - setting_filename = "cta_strategy_setting.vt" + setting_filename = "cta_strategy_setting.json" data_filename = "cta_strategy_data.json" def __init__(self, main_engine: MainEngine, event_engine: EventEngine): @@ -52,6 +51,7 @@ class CtaEngine(BaseEngine): main_engine, event_engine, "CtaStrategy") self.setting_file = None # setting file object + self.strategy_setting = {} # strategy_name: dict self.strategy_data = {} # strategy_name: dict self.classes = {} # class_name: stategy_class @@ -80,7 +80,7 @@ class CtaEngine(BaseEngine): def close(self): """""" - self.save_strategy_setting() + pass def register_event(self): """""" @@ -410,7 +410,7 @@ class CtaEngine(BaseEngine): def init_strategy(self, strategy_name: str): """ Init a strategy. - """ + """ self.init_queue.put(strategy_name) if not self.init_thread: @@ -612,12 +612,15 @@ class CtaEngine(BaseEngine): """ Load setting file. """ - filepath = str(get_temp_path(self.setting_filename)) - self.setting_file = shelve.open(filepath) + self.strategy_setting = load_json(self.setting_filename) - for tp in list(self.setting_file.values()): - class_name, strategy_name, vt_symbol, setting = tp - self.add_strategy(class_name, strategy_name, vt_symbol, setting) + for strategy_name, strategy_config in self.strategy_setting.items(): + self.add_strategy( + strategy_config["class_name"], + strategy_name, + strategy_config["vt_symbol"], + strategy_config["setting"] + ) def update_strategy_setting(self, strategy_name: str, setting: dict): """ @@ -625,13 +628,12 @@ class CtaEngine(BaseEngine): """ strategy = self.strategies[strategy_name] - self.setting_file[strategy_name] = ( - strategy.__class__.__name__, - strategy_name, - strategy.vt_symbol, - setting, - ) - self.setting_file.sync() + self.strategy_setting[strategy_name] = { + "class_name": strategy.__class__.__name__, + "vt_symbol": strategy.vt_symbol, + "setting": setting, + } + save_json(self.setting_filename, self.strategy_setting) def remove_strategy_setting(self, strategy_name: str): """ @@ -640,15 +642,8 @@ class CtaEngine(BaseEngine): if strategy_name not in self.setting_file: return - self.setting_file.pop(strategy_name) - self.setting_file.sync() - - def save_strategy_setting(self): - """ - Save and close setting file. - """ - if self.setting_file: - self.setting_file.close() + self.strategy_setting.pop(strategy_name) + save_json(self.setting_filename, self.strategy_setting) def put_stop_order_event(self, stop_order: StopOrder): """ diff --git a/vnpy/app/cta_strategy/strategies/double_ma_strategy.py b/vnpy/app/cta_strategy/strategies/double_ma_strategy.py index 1547c408..779bdbad 100644 --- a/vnpy/app/cta_strategy/strategies/double_ma_strategy.py +++ b/vnpy/app/cta_strategy/strategies/double_ma_strategy.py @@ -5,7 +5,7 @@ class DoubleMaStrategy(CtaTemplate): author = "用Python的交易员" fast_window = 10 - slow_window = 20.10 + slow_window = 20 fast_ma = 0.0 slow_ma = 0.0 diff --git a/vnpy/gateway/ctp/ctp_gateway.py b/vnpy/gateway/ctp/ctp_gateway.py index b95e1af0..1129d897 100644 --- a/vnpy/gateway/ctp/ctp_gateway.py +++ b/vnpy/gateway/ctp/ctp_gateway.py @@ -27,7 +27,7 @@ from vnpy.trader.object import ( CancelRequest, SubscribeRequest, ) -from vnpy.trader.utility import get_temp_path +from vnpy.trader.utility import get_folder_path from vnpy.trader.event import EVENT_TIMER @@ -305,8 +305,8 @@ class CtpMdApi(MdApi): # If not connected, then start connection first. if not self.connect_status: - path = get_temp_path(f"{self.gateway_name}_md_" ) - self.createFtdcMdApi(str(path)) + path = get_folder_path(self.gateway_name.lower()) + self.createFtdcMdApi(str(path) + "\\Md") self.registerFront(address) self.init() @@ -1076,8 +1076,8 @@ class CtpTdApi(TdApi): self.product_info = product_info if not self.connect_status: - path = get_temp_path(f"{self.gateway_name}_td_") - self.createFtdcTraderApi(str(path)) + path = get_folder_path(self.gateway_name.lower()) + self.createFtdcTraderApi(str(path) + "\\Td") self.subscribePrivateTopic(0) self.subscribePublicTopic(0) diff --git a/vnpy/trader/database.py b/vnpy/trader/database.py index aa44a79f..87fb3eae 100644 --- a/vnpy/trader/database.py +++ b/vnpy/trader/database.py @@ -4,10 +4,10 @@ from peewee import SqliteDatabase, Model, CharField, DateTimeField, FloatField from .constant import Exchange, Interval from .object import BarData, TickData -from .utility import get_temp_path +from .utility import get_file_path -DB_NAME = "database.vt" -DB = SqliteDatabase(str(get_temp_path(DB_NAME))) +DB_NAME = "database.db" +DB = SqliteDatabase(str(get_file_path(DB_NAME))) class DbBarData(Model): diff --git a/vnpy/trader/engine.py b/vnpy/trader/engine.py index 2eed3ff4..9ba94082 100644 --- a/vnpy/trader/engine.py +++ b/vnpy/trader/engine.py @@ -24,7 +24,7 @@ from .event import ( from .gateway import BaseGateway from .object import CancelRequest, LogData, OrderRequest, SubscribeRequest from .setting import SETTINGS -from .utility import Singleton, get_temp_path +from .utility import Singleton, get_folder_path class MainEngine: @@ -246,7 +246,8 @@ class LogEngine(BaseEngine): """ today_date = datetime.now().strftime("%Y%m%d") filename = f"vt_{today_date}.log" - file_path = get_temp_path(filename) + log_path = get_folder_path("log") + file_path = log_path.joinpath(filename) file_handler = logging.FileHandler( file_path, mode="w", encoding="utf8" diff --git a/vnpy/trader/ui/__init__.py b/vnpy/trader/ui/__init__.py index e88065ae..16f6fcd1 100644 --- a/vnpy/trader/ui/__init__.py +++ b/vnpy/trader/ui/__init__.py @@ -12,7 +12,12 @@ from ..utility import get_icon_path def excepthook(exctype, value, tb): - """异常捕捉钩子""" + """ + Raise exception under debug mode, otherwise + show exception detail with QMessageBox. + """ + sys.__excepthook__(exctype, value, tb) + msg = "".join(traceback.format_exception(exctype, value, tb)) QtWidgets.QMessageBox.critical( None, "Exception", msg, QtWidgets.QMessageBox.Ok diff --git a/vnpy/trader/ui/ico/forum.ico b/vnpy/trader/ui/ico/forum.ico new file mode 100644 index 00000000..edfad2b4 Binary files /dev/null and b/vnpy/trader/ui/ico/forum.ico differ diff --git a/vnpy/trader/ui/mainwindow.py b/vnpy/trader/ui/mainwindow.py index ada552e5..2171a42c 100644 --- a/vnpy/trader/ui/mainwindow.py +++ b/vnpy/trader/ui/mainwindow.py @@ -2,6 +2,7 @@ Implements main window of VN Trader. """ +import webbrowser from functools import partial from importlib import import_module from typing import Callable @@ -23,7 +24,7 @@ from .widget import ( AboutDialog, ) from ..engine import MainEngine -from ..utility import get_icon_path, get_trader_path +from ..utility import get_icon_path, TRADER_PATH class MainWindow(QtWidgets.QMainWindow): @@ -37,8 +38,7 @@ class MainWindow(QtWidgets.QMainWindow): self.main_engine = main_engine self.event_engine = event_engine - self.path = get_trader_path() - self.window_title = f"VN Trader [{self.path}]" + self.window_title = f"VN Trader [{TRADER_PATH}]" self.connect_dialogs = {} self.widgets = {} @@ -129,6 +129,10 @@ class MainWindow(QtWidgets.QMainWindow): help_menu, "测试邮件", "email.ico", self.send_test_email ) + self.add_menu_action( + help_menu, "社区论坛", "forum.ico", self.open_forum + ) + self.add_menu_action( help_menu, "关于", @@ -246,3 +250,8 @@ class MainWindow(QtWidgets.QMainWindow): Sending a test email. """ self.main_engine.send_email("VN Trader", "testing") + + def open_forum(self): + """ + """ + webbrowser.open("https://www.vnpy.com/forum/") diff --git a/vnpy/trader/ui/widget.py b/vnpy/trader/ui/widget.py index f81d41c2..93df02d1 100644 --- a/vnpy/trader/ui/widget.py +++ b/vnpy/trader/ui/widget.py @@ -20,7 +20,7 @@ from ..event import ( EVENT_LOG ) from ..object import OrderRequest, SubscribeRequest -from ..utility import load_setting, save_setting +from ..utility import load_json, save_json COLOR_LONG = QtGui.QColor("red") COLOR_SHORT = QtGui.QColor("green") @@ -490,7 +490,7 @@ class ConnectDialog(QtWidgets.QDialog): self.main_engine = main_engine self.gateway_name = gateway_name - self.filename = f"Connect{gateway_name}.vt" + self.filename = f"connect_{gateway_name.lower()}.json" self.widgets = {} @@ -505,7 +505,7 @@ class ConnectDialog(QtWidgets.QDialog): self.gateway_name) # Saved setting provides field data used last time. - loaded_setting = load_setting(self.filename) + loaded_setting = load_json(self.filename) # Initialize line edits and form layout based on setting. form = QtWidgets.QFormLayout() @@ -550,7 +550,7 @@ class ConnectDialog(QtWidgets.QDialog): field_value = field_type(widget.text()) setting[field_name] = field_value - save_setting(self.filename, setting) + save_json(self.filename, setting) self.main_engine.connect(setting, self.gateway_name)