[Add] general functions of VN Trader

1. use json instead of shelve for setting/data storage
2. call original sys.__excepthook__ before showing exception with QMessageBox
This commit is contained in:
vn.py 2019-02-17 22:59:01 +08:00
parent ae78a7f0c0
commit 6c91951e02
10 changed files with 58 additions and 45 deletions

3
.gitignore vendored
View File

@ -15,3 +15,6 @@
build
dist
*.local
# vn.py
.vntrader

View File

@ -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):
""""""
@ -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):
"""

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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"

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -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/")

View File

@ -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)