• vnpy源码阅读学习(9)回到OptionMaster


    回到OptionMaster

    根据我们对APP调用的代码阅读,我们基本上知道了一个APP是如何被调用,那么我们回到OptionMaster学习下这个APP的实现。

    看看结构

    class OptionManager(QtWidgets.QWidget):
        """"""
        signal_new_portfolio = QtCore.pyqtSignal(Event)
    
        def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
            pass
    
        def init_ui(self):
            pass
    
        def register_event(self):
            pass
    
        def process_new_portfolio_event(self, event: Event):
            pass
    
        def update_portfolio_combo(self):
            pass
    
        def open_portfolio_dialog(self):
            pass
    
        def init_widgets(self):
            pass
    
        def calculate_underlying_adjustment(self):
            pass
    

    通过结构和注释,我们基本上知道这是一个期权方面的APP。我们来对代码进行仔细学习

    __init__

        def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
            """"""
            super().__init__()
    
            self.main_engine = main_engine
            self.event_engine = event_engine
            self.option_engine = main_engine.get_engine(APP_NAME)
    
            self.portfolio_name: str = ""
    
            self.market_monitor: OptionMarketMonitor = None
            self.greeks_monitor: OptionGreeksMonitor = None
    
            self.docks: List[QtWidgets.QDockWidget] = []
    
            self.init_ui()
            self.register_event()
    

    在init中我们看到和MainWindow不一样的地方出了main_engine和event_engin还加入了一个他自己的引擎,这个引擎是在app注册时候配置在engine_class中的。然后有两个报表:market_monitor和greeks_monitor

    init_ui

        def init_ui(self):
            #具体实现
            self.portfolio_button = QtWidgets.QPushButton("配置")
            self.portfolio_button.clicked.connect(self.open_portfolio_dialog)
    

    简单的界面配置我们通过运行程序看到实现的大概如下

    我们只看到portfolio_button点击以后调用了self.open_portfolio_dialog

    open_portfolio_dialog

        def open_portfolio_dialog(self):
            """"""
            portfolio_name = self.portfolio_combo.currentText()
            if not portfolio_name:
                return
    
            self.portfolio_name = portfolio_name
    
            dialog = PortfolioDialog(self.option_engine, portfolio_name)
            result = dialog.exec_()
    
            if result == dialog.Accepted:
                self.portfolio_combo.setEnabled(False)
                self.portfolio_button.setEnabled(False)
    
                self.init_widgets()
    

    我们看到点击配置以后,如果有选择期权产品,则弹出 PortfolioDialog对话框。根据对话框的执行结果,如果点击了接受,则下拉框和配置按钮不可用,然后执行init_widgets

    init_widgets

        def init_widgets(self):
            """"""
            self.market_monitor = OptionMarketMonitor(self.option_engine, self.portfolio_name)
            self.greeks_monitor = OptionGreeksMonitor(self.option_engine, self.portfolio_name)
            self.manual_trader = OptionManualTrader(self.option_engine, self.portfolio_name)
    
            self.market_monitor.itemDoubleClicked.connect(self.manual_trader.update_symbol)
    
            self.market_button.clicked.connect(self.market_monitor.showMaximized)
            self.greeks_button.clicked.connect(self.greeks_monitor.showMaximized)
            self.manual_button.clicked.connect(self.manual_trader.show)
            self.chain_button.clicked.connect(self.calculate_underlying_adjustment)
    
            for button in [
                self.market_button,
                self.greeks_button,
                self.chain_button,
                self.manual_button
            ]:
                button.setEnabled(True)
    

    我们看到则是对market_monitor,greeks_monitor,manual_trader进行实例化,并且绑定了事件的信号插槽。同时对一些按钮进行了绑定,基本上都是窗体的显示。主要是以下按钮和窗体的显示的对应

            self.market_button = QtWidgets.QPushButton("T型报价")
            self.greeks_button = QtWidgets.QPushButton("持仓希腊值")
            self.chain_button = QtWidgets.QPushButton("拟合升贴水")
            self.manual_button = QtWidgets.QPushButton("快速交易")
    

    而且每一个窗体都传入了该APP定义的engine

    register_event

    我们在__init__方法中同时看到了此方法的调用。

        def register_event(self):
            """"""
            self.signal_new_portfolio.connect(self.process_new_portfolio_event)
    
            self.event_engine.register(EVENT_OPTION_NEW_PORTFOLIO, self.signal_new_portfolio.emit)
    

    我们看到该方法把 process_new_portfolio_event的Handler和register到了MainEngine中去。

    process_new_portfolio_event

        def process_new_portfolio_event(self, event: Event):
            """"""
            self.update_portfolio_combo()
    
        def update_portfolio_combo(self):
            """"""
            if not self.portfolio_combo.isEnabled():
                return
    
            self.portfolio_combo.clear()
            portfolio_names = self.option_engine.get_portfolio_names()
            self.portfolio_combo.addItems(portfolio_names)
    
    

    根据handler的调用来更新期权产品的列表

    calculate_underlying_adjustment

    
    self.chain_button.clicked.connect(self.calculate_underlying_adjustment)
    
        def calculate_underlying_adjustment(self):
            """"""
            portfolio = self.option_engine.get_portfolio(self.portfolio_name)
    
            for chain in portfolio.chains.values():
                chain.calculate_underlying_adjustment()
    

    我们看到 快速交易点击以后,会执行从引擎中获得期权产品的数据,然后执行calculate_underlying_adjustment()方法,要继续深入下去,我们有几个方向:

    1. market_monitor
    2. greeks_monitor
    3. manual_trader
    4. option_engine
    5. calculate_underlying_adjustment

    我们还是从周围向心脏的方式学习,先看看几个窗体,然后随后深入引擎的代码学习

    market_monitor

    class OptionMarketMonitor(MonitorTable):
    
        def __init__(self, option_engine: OptionEngine, portfolio_name: str):
            
    
        def init_ui(self):
            
    
        def register_event(self):
            
    
        def process_tick_event(self, event: Event):
            
    
        def process_trade_event(self, event: Event):
            
    
        def process_position_event(self, event: Event):
            
    
        def update_pos(self, vt_symbol: str):
            
    
        def update_price(self, vt_symbol: str):
            
    
        def update_impv(self, vt_symbol: str):
            
    
        def update_greeks(self, vt_symbol: str):
            
    
        def scroll_to_middle(self):
            
    
        def resizeEvent(self, event: QtGui.QResizeEvent):
            
    

    我们看到 OptionMarketMonitor继承了MonitorTable,而MonitorTable基本上和框架里面的MonitorBase如出一辙。其实大量代码几乎可以重用。
    我们先来看看这个类的具体代码,最值得琢磨的其实是这个

        def register_event(self):
            """"""
            self.signal_tick.connect(self.process_tick_event)
            self.signal_trade.connect(self.process_trade_event)
            self.signal_position.connect(self.process_position_event)
    
            self.event_engine.register(EVENT_TICK, self.signal_tick.emit)
            self.event_engine.register(EVENT_TRADE, self.signal_trade.emit)
            self.event_engine.register(EVENT_POSITION, self.signal_position.emit)
        def __init__(self, option_engine: OptionEngine, portfolio_name: str):
            """"""
            super().__init__()
    
            self.option_engine = option_engine
            self.event_engine = option_engine.event_engine
            self.portfolio_name = portfolio_name
    

    把处理tick事件,交易事件,仓位事件都和OptionEngine连接起来。
    而这些处理的Handler无非根据信息改变界面,就不一一研究。

    其他窗体

    class OptionManualTrader(QtWidgets.QWidget):
        def __init__(self, option_engine: OptionEngine, portfolio_name: str):
            """"""
            super().__init__()
    
            self.option_engine = option_engine
            self.main_engine: MainEngine = option_engine.main_engine
            self.event_engine: EventEngine = option_engine.event_engine
    

    我们可以看到窗体不但对自己的引擎OptionEngine,而且也对mainEngin和EventEngine有所调用。

     def send_order(self):
            """"""
            symbol = self.symbol_line.text()
            contract = self.contracts.get(symbol, None)
            if not contract:
                return
    
            price_text = self.price_line.text()
            volume_text = self.volume_line.text()
    
            if not price_text or not volume_text:
                return
    
            price = float(price_text)
            volume = int(volume_text)
            direction = Direction(self.direction_combo.currentText())
            offset = Offset(self.offset_combo.currentText())
    
            req = OrderRequest(
                symbol=contract.symbol,
                exchange=contract.exchange,
                direction=direction,
                type=OrderType.LIMIT,
                offset=offset,
                volume=volume,
                price=price
            )
            self.main_engine.send_order(req, contract.gateway_name)
    

    整个是通过main_engin来下单的。而在分析主引擎的时候我们知道send_order正是通过gateway_name来下单的。

    而gateway_name来自contract合约
    而合约来自main_engin

        def init_contracts(self):
            """"""
            contracts = self.main_engine.get_all_contracts()
            for contract in contracts:
                self.contracts[contract.symbol] = contract
    

    我们可以想象得到。而main_engine中合约的信息又来自OmsEngine 指定管理系统 (Order Manage System)
    接下来我们要继续深入就必须深入到引擎的内容了。

  • 相关阅读:
    判断是否是移动端
    html上传文件类型限制accept的全部属性值
    前端cropper裁剪图像大小(原创)
    eslint加不加分号
    手机浏览器使用rem 自适应html宽度大小
    DOMContentLoaded与load的区别
    ES6语法find查找匹配数组
    React的JSX语法
    React的基本使用
    React简介
  • 原文地址:https://www.cnblogs.com/bbird/p/12785476.html
Copyright © 2020-2023  润新知