diff --git a/tests/trader/run.py b/tests/trader/run.py index e6427744..67164438 100644 --- a/tests/trader/run.py +++ b/tests/trader/run.py @@ -5,6 +5,8 @@ from vnpy.gateway.ib import IbGateway from vnpy.gateway.futu import FutuGateway from vnpy.gateway.bitmex import BitmexGateway +from vnpy.app.cta_strategy import CtaStrategyApp + import os import logging import time @@ -21,6 +23,8 @@ def main(): main_engine.add_gateway(FutuGateway) main_engine.add_gateway(BitmexGateway) + main_engine.add_app(CtaStrategyApp) + main_window = MainWindow(main_engine, event_engine) main_window.showMaximized() diff --git a/vnpy/app/cta_strategy/__init__.py b/vnpy/app/cta_strategy/__init__.py new file mode 100644 index 00000000..f4204b5c --- /dev/null +++ b/vnpy/app/cta_strategy/__init__.py @@ -0,0 +1,15 @@ +from pathlib import Path + +from vnpy.trader.app import BaseApp +from .cta_engine import CtaEngine + + +class CtaStrategyApp(BaseApp): + """""" + app_name = "CtaStrategy" + app_module = __module__ + app_path = Path(__file__).parent + display_name = "CTA策略" + engine_class = CtaEngine + widget_name = "CtaManager" + icon_name = "cta.ico" \ No newline at end of file diff --git a/vnpy/app/cta_strategy/backtesting.py b/vnpy/app/cta_strategy/backtesting.py new file mode 100644 index 00000000..e69de29b diff --git a/vnpy/app/cta_strategy/engine.py b/vnpy/app/cta_strategy/engine.py new file mode 100644 index 00000000..bb0b0f2e --- /dev/null +++ b/vnpy/app/cta_strategy/engine.py @@ -0,0 +1,13 @@ +"""""" + +from vnpy.event import EventEngine +from vnpy.trader.engine import BaseEngine, MainEngine + + +class CtaEngine(BaseEngine): + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + super(CtaEngine, + self).__init__(main_engine, + event_engine, + "CtaStrategy") diff --git a/vnpy/app/cta_strategy/template.py b/vnpy/app/cta_strategy/template.py new file mode 100644 index 00000000..56e90015 --- /dev/null +++ b/vnpy/app/cta_strategy/template.py @@ -0,0 +1,11 @@ +"""""" + +from abc import ABC + + +class CtaTemplate(ABC): + """""" + + def __init__(self, engine): + """""" + self.engine = engine diff --git a/vnpy/app/cta_strategy/ui/__init__.py b/vnpy/app/cta_strategy/ui/__init__.py new file mode 100644 index 00000000..ce7bb539 --- /dev/null +++ b/vnpy/app/cta_strategy/ui/__init__.py @@ -0,0 +1 @@ +from .widget import CtaManager \ No newline at end of file diff --git a/vnpy/app/cta_strategy/ui/cta.ico b/vnpy/app/cta_strategy/ui/cta.ico new file mode 100644 index 00000000..25cbaa73 Binary files /dev/null and b/vnpy/app/cta_strategy/ui/cta.ico differ diff --git a/vnpy/app/cta_strategy/ui/widget.py b/vnpy/app/cta_strategy/ui/widget.py new file mode 100644 index 00000000..541bc237 --- /dev/null +++ b/vnpy/app/cta_strategy/ui/widget.py @@ -0,0 +1,13 @@ +from vnpy.event import EventEngine +from vnpy.trader.engine import BaseEngine, MainEngine +from vnpy.trader.ui import QtGui, QtWidgets + + +class CtaManager(QtWidgets.QWidget): + """""" + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + super(CtaManager, self).__init__() + + self.main_engine = main_engine + self.event_engine = event_engine \ No newline at end of file diff --git a/vnpy/trader/app.py b/vnpy/trader/app.py index e01bb50c..e78dc771 100644 --- a/vnpy/trader/app.py +++ b/vnpy/trader/app.py @@ -1,11 +1,16 @@ +"""""" + from abc import ABC class BaseApp(ABC): """ - Abstract class for app. + Absstract class for app. """ - - app_name = '' - app_engine = None - app_ui = None \ No newline at end of file + app_name = "" # Unique name used for creating engine and widget + app_module = "" # App module string used in import_module + app_path = "" # Absolute path of app folder + display_name = "" # Name for display on the menu. + engine_class = None # App engine class + widget_name = "" # Class name of app widget + icon_name = "" # Icon file name of app widget diff --git a/vnpy/trader/engine.py b/vnpy/trader/engine.py index 2eff1943..c39700e8 100644 --- a/vnpy/trader/engine.py +++ b/vnpy/trader/engine.py @@ -25,6 +25,7 @@ from .object import LogData, SubscribeRequest, OrderRequest, CancelRequest from .utility import Singleton, get_temp_path from .setting import SETTINGS from .gateway import BaseGateway +from .app import BaseApp class MainEngine: @@ -60,6 +61,15 @@ class MainEngine: gateway = gateway_class(self.event_engine) self.gateways[gateway.gateway_name] = gateway + def add_app(self, app_class: BaseApp): + """ + Add app. + """ + app = app_class() + self.apps[app.app_name] = app + + self.add_engine(app.engine_class) + def init_engines(self): """ Init all engines. @@ -101,6 +111,12 @@ class MainEngine: """ return list(self.gateways.keys()) + def get_all_apps(self): + """ + Get all app objects. + """ + return list(self.apps.values()) + def connect(self, setting: dict, gateway_name: str): """ Start connection of a specific gateway. diff --git a/vnpy/trader/ui/__init__.py b/vnpy/trader/ui/__init__.py index 4630b75c..dcc8252c 100644 --- a/vnpy/trader/ui/__init__.py +++ b/vnpy/trader/ui/__init__.py @@ -3,7 +3,7 @@ import ctypes from pathlib import Path import qdarkstyle -from PyQt5 import QtWidgets, QtGui +from PyQt5 import QtWidgets, QtGui, QtCore from .mainwindow import MainWindow from ..setting import SETTINGS diff --git a/vnpy/trader/ui/mainwindow.py b/vnpy/trader/ui/mainwindow.py index 58d84b71..f436efef 100644 --- a/vnpy/trader/ui/mainwindow.py +++ b/vnpy/trader/ui/mainwindow.py @@ -4,6 +4,7 @@ Implements main window of VN Trader. from functools import partial from typing import Callable +from importlib import import_module from PyQt5 import QtWidgets, QtCore, QtGui @@ -85,6 +86,22 @@ class MainWindow(QtWidgets.QMainWindow): self.add_menu_action(sys_menu, "退出", "exit.ico", self.close) # App menu + all_apps = self.main_engine.get_all_apps() + for app in all_apps: + try: + ui_module = import_module(app.app_module + ".ui") + widget_class = getattr(ui_module, app.widget_name) + except ImportError: + continue + + func = partial(self.open_widget, widget_class, app.app_name) + icon_path = str(app.app_path.joinpath("ui", app.icon_name)) + self.add_menu_action( + app_menu, + f"打开{app.display_name}", + icon_path, + func + ) # Help menu self.add_menu_action( @@ -205,16 +222,16 @@ class MainWindow(QtWidgets.QMainWindow): Save current window size and state by trader path and setting name. """ settings = QtCore.QSettings(self.window_title, name) - settings.setValue('state', self.saveState()) - settings.setValue('geometry', self.saveGeometry()) + settings.setValue("state", self.saveState()) + settings.setValue("geometry", self.saveGeometry()) def load_window_setting(self, name: str): """ Load previous window size and state by trader path and setting name. """ settings = QtCore.QSettings(self.window_title, name) - state = settings.value('state') - geometry = settings.value('geometry') + state = settings.value("state") + geometry = settings.value("geometry") if isinstance(state, QtCore.QByteArray): self.restoreState(state) diff --git a/vnpy/trader/utility.py b/vnpy/trader/utility.py index e8a176aa..3c61fd04 100644 --- a/vnpy/trader/utility.py +++ b/vnpy/trader/utility.py @@ -19,7 +19,7 @@ class Singleton(type): def __call__(cls, *args, **kwargs): """""" if cls not in cls._instances: - cls._instances[cls] = super(VtSingleton, + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)