[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:
parent
ae78a7f0c0
commit
6c91951e02
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,3 +15,6 @@
|
||||
build
|
||||
dist
|
||||
*.local
|
||||
|
||||
# vn.py
|
||||
.vntrader
|
@ -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):
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
BIN
vnpy/trader/ui/ico/forum.ico
Normal file
BIN
vnpy/trader/ui/ico/forum.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
@ -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/")
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user