zoukankan      html  css  js  c++  java
  • vnpy源码阅读学习(8):关于app

    关于app

    在入口程序中,我们看到了把 gatewayapp, 各类的engine都添加到mainEngine中来。不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不难看出Engine则是vnpy的核心,可以处理策略,回测等各方面的事情。我们吃柿子找软的捏的方式,先挑选最简单的容易理解的部分开始阅读,然后逐步想最难的部分去理解。所以先从APP部分开始阅读。

    开始

    main_engine.add_app(OptionMasterApp)
    

    入口部分既然有这个代码。那么我们就从OptionMasterApp开始。

    一路跟踪

    #vnpyappoption_master\__init__.py
    class OptionMasterApp(BaseApp):
        #省略
    
    #vnpy	raderapp.py
    class BaseApp(ABC):
        #省略
    #D:PythonPython36Libabc.py
    

    APC是python内置的模块了,首先让我们学习下abc的用法。我找到以下教程

    Python中的abc模块

    通过对ABC类的学习,我们大概能明白,ABC类是一个抽象类,相当于其他语言接口的概念。我们可以理解为BaseApp是一个抽象的接口。

    BaseApp

    class BaseApp(ABC):
        """
        Absstract class for app.
        """
    
        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
    

    BaseApp的接口类中,我们看到定义了app_name, app_moudel, app_path, display_name, engine_class, widget_name, icon_name等属性,不难猜测,这个是一个可以动态扩展模块或者组件的基类。应该是所有继承BaseApp的子类,都可以被vnpy动态的作为app被加载进来。我们就以 OptionMasterApp 为例子。看看app部分是如何实现的。

    OptionMasterApp

    #vnpyappoption_master\__init__.py
    from pathlib import Path
    from vnpy.trader.app import BaseApp
    from .engine import OptionEngine, APP_NAME
    
    
    class OptionMasterApp(BaseApp):
        app_name = APP_NAME
        app_module = __module__
        app_path = Path(__file__).parent
        display_name = "期权交易"
        engine_class = OptionEngine
        widget_name = "OptionManager"
        icon_name = "option.ico"
    

    OptionMasterApp所在的路径,我们不难发现,OptionMasterApp是一个独立的包。不难猜测到整个包实现了一个OptionMaster的app. 而 APP_NAME__module__则应该是app的入口和包的名字。engine_class 加载的则是提供给app的引擎。这个包的代码总体如下:

    我们先顺着APP_NAME跟踪得到base.py的代码,看到定义的一些常量

    APP_NAME = "OptionMaster"
    
    EVENT_OPTION_LOG = "eOptionLog"
    EVENT_OPTION_NEW_PORTFOLIO = "eOptionNewPortfolio"
    
    
    CHAIN_UNDERLYING_MAP = {
        "510050_O.SSE": "510050",
        "IO.CFFEX": "IF",
        "HO.CFFEX": "IH"
    }
    

    应该是通过 OptionMasterApp app能够提供的代码,就可以加载进来这个APP了,我们先把跟踪OptionMasterApp的线索放一放,我们去看看,通过这些信息,APP是如何被加载进来的。然后再回头逐个了解这些APP

    回到MainEngine

    我们知道所有的App都通过MainEngine.add_app()的方法加载进入了MainEngine,然后通过MainEngine.get_all_apps()则可以调用所有加入的APP。然后逐个开始调用。我们只需要查找MainEngine.get_all_apps()的引用即可找到。

        def init_menu(self):
            # 获得所有的继承了BaseApp的配置信息
            all_apps = self.main_engine.get_all_apps()
    
            for app in all_apps:
                #引入BaseApp moudle中的.ui的包
                ui_module = import_module(app.app_module + ".ui")
                #通过ui的包查找widget_name
                widget_class = getattr(ui_module, app.widget_name)
    
                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, app.display_name, icon_path, func
                )
                self.add_toolbar_action(
                    app.display_name, icon_path, func
                )
        def add_menu_action(
            self,
            menu: QtWidgets.QMenu,
            action_name: str,
            icon_name: str,
            func: Callable,
        ):
            """"""
            icon = QtGui.QIcon(get_icon_path(__file__, icon_name))
    
            action = QtWidgets.QAction(action_name, self)
            action.triggered.connect(func)
            action.setIcon(icon)
    
            menu.addAction(action)
    
        def add_toolbar_action(
            self,
            action_name: str,
            icon_name: str,
            func: Callable,
        ):
            """"""
            icon = QtGui.QIcon(get_icon_path(__file__, icon_name))
    
            action = QtWidgets.QAction(action_name, self)
            action.triggered.connect(func)
            action.setIcon(icon)
    
            self.toolbar.addAction(action)
    
        def open_widget(self, widget_class: QtWidgets.QWidget, name: str):
            """
            Open contract manager.
            """
            widget = self.widgets.get(name, None)
            if not widget:
                widget = widget_class(self.main_engine, self.event_engine)
                self.widgets[name] = widget
    
            if isinstance(widget, QtWidgets.QDialog):
                widget.exec_()
            else:
                widget.show()
    

    关于用到python一些内置函数的教程

    Python编程:importlib.import_module动态导入模块

    Python getattr() 函数

    python partial函数

    通过上述代码,我们大概梳理了下思路。如下

  • 相关阅读:
    PG中 generate_series函数的使用
    代码搜索神器ag
    效率神器2
    效率神器
    Django-cookie组件
    Django-form组件
    Django组件-分页器
    Django与Ajax
    Django-模型层
    Django-模板层
  • 原文地址:https://www.cnblogs.com/bbird/p/12597169.html
Copyright © 2011-2022 走看看