关于app
在入口程序中,我们看到了把 gateway
,app
, 各类的engine
都添加到mainEngine
中来。不难猜测gateway
主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不难看出Engine则是vnpy
的核心,可以处理策略,回测等各方面的事情。我们吃柿子找软的捏的方式,先挑选最简单的容易理解的部分开始阅读,然后逐步想最难的部分去理解。所以先从APP部分开始阅读。
开始
main_engine.add_app(OptionMasterApp)
入口部分既然有这个代码。那么我们就从OptionMasterApp
开始。
一路跟踪
#\vnpy\app\option_master\__init__.py class OptionMasterApp(BaseApp): #省略 #\vnpy\trader\app.py class BaseApp(ABC): #省略 #D:\Python\Python36\Lib\abc.py
APC是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
#\vnpy\app\option_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动态导入模块
通过上述代码,我们大概梳理了下思路。如下
来源:https://www.cnblogs.com/bbird/p/12597169.html