回到OptionMaster

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

看看结构

  1. class OptionManager(QtWidgets.QWidget):
  2. """"""
  3. signal_new_portfolio = QtCore.pyqtSignal(Event)
  4. def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
  5. pass
  6. def init_ui(self):
  7. pass
  8. def register_event(self):
  9. pass
  10. def process_new_portfolio_event(self, event: Event):
  11. pass
  12. def update_portfolio_combo(self):
  13. pass
  14. def open_portfolio_dialog(self):
  15. pass
  16. def init_widgets(self):
  17. pass
  18. def calculate_underlying_adjustment(self):
  19. pass

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

__init__

  1. def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
  2. """"""
  3. super().__init__()
  4. self.main_engine = main_engine
  5. self.event_engine = event_engine
  6. self.option_engine = main_engine.get_engine(APP_NAME)
  7. self.portfolio_name: str = ""
  8. self.market_monitor: OptionMarketMonitor = None
  9. self.greeks_monitor: OptionGreeksMonitor = None
  10. self.docks: List[QtWidgets.QDockWidget] = []
  11. self.init_ui()
  12. self.register_event()

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

init_ui

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

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



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

open_portfolio_dialog

  1. def open_portfolio_dialog(self):
  2. """"""
  3. portfolio_name = self.portfolio_combo.currentText()
  4. if not portfolio_name:
  5. return
  6. self.portfolio_name = portfolio_name
  7. dialog = PortfolioDialog(self.option_engine, portfolio_name)
  8. result = dialog.exec_()
  9. if result == dialog.Accepted:
  10. self.portfolio_combo.setEnabled(False)
  11. self.portfolio_button.setEnabled(False)
  12. self.init_widgets()

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

init_widgets

  1. def init_widgets(self):
  2. """"""
  3. self.market_monitor = OptionMarketMonitor(self.option_engine, self.portfolio_name)
  4. self.greeks_monitor = OptionGreeksMonitor(self.option_engine, self.portfolio_name)
  5. self.manual_trader = OptionManualTrader(self.option_engine, self.portfolio_name)
  6. self.market_monitor.itemDoubleClicked.connect(self.manual_trader.update_symbol)
  7. self.market_button.clicked.connect(self.market_monitor.showMaximized)
  8. self.greeks_button.clicked.connect(self.greeks_monitor.showMaximized)
  9. self.manual_button.clicked.connect(self.manual_trader.show)
  10. self.chain_button.clicked.connect(self.calculate_underlying_adjustment)
  11. for button in [
  12. self.market_button,
  13. self.greeks_button,
  14. self.chain_button,
  15. self.manual_button
  16. ]:
  17. button.setEnabled(True)

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

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

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

register_event

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

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

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

process_new_portfolio_event

  1. def process_new_portfolio_event(self, event: Event):
  2. """"""
  3. self.update_portfolio_combo()
  4. def update_portfolio_combo(self):
  5. """"""
  6. if not self.portfolio_combo.isEnabled():
  7. return
  8. self.portfolio_combo.clear()
  9. portfolio_names = self.option_engine.get_portfolio_names()
  10. self.portfolio_combo.addItems(portfolio_names)

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

calculate_underlying_adjustment


  1. self.chain_button.clicked.connect(self.calculate_underlying_adjustment)
  1. def calculate_underlying_adjustment(self):
  2. """"""
  3. portfolio = self.option_engine.get_portfolio(self.portfolio_name)
  4. for chain in portfolio.chains.values():
  5. 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

  1. class OptionMarketMonitor(MonitorTable):
  2. def __init__(self, option_engine: OptionEngine, portfolio_name: str):
  3. def init_ui(self):
  4. def register_event(self):
  5. def process_tick_event(self, event: Event):
  6. def process_trade_event(self, event: Event):
  7. def process_position_event(self, event: Event):
  8. def update_pos(self, vt_symbol: str):
  9. def update_price(self, vt_symbol: str):
  10. def update_impv(self, vt_symbol: str):
  11. def update_greeks(self, vt_symbol: str):
  12. def scroll_to_middle(self):
  13. def resizeEvent(self, event: QtGui.QResizeEvent):

我们看到 OptionMarketMonitor继承了MonitorTable,而MonitorTable基本上和框架里面的MonitorBase如出一辙。其实大量代码几乎可以重用。

我们先来看看这个类的具体代码,最值得琢磨的其实是这个

  1. def register_event(self):
  2. """"""
  3. self.signal_tick.connect(self.process_tick_event)
  4. self.signal_trade.connect(self.process_trade_event)
  5. self.signal_position.connect(self.process_position_event)
  6. self.event_engine.register(EVENT_TICK, self.signal_tick.emit)
  7. self.event_engine.register(EVENT_TRADE, self.signal_trade.emit)
  8. self.event_engine.register(EVENT_POSITION, self.signal_position.emit)
  9. def __init__(self, option_engine: OptionEngine, portfolio_name: str):
  10. """"""
  11. super().__init__()
  12. self.option_engine = option_engine
  13. self.event_engine = option_engine.event_engine
  14. self.portfolio_name = portfolio_name

把处理tick事件,交易事件,仓位事件都和OptionEngine连接起来。

而这些处理的Handler无非根据信息改变界面,就不一一研究。

其他窗体

  1. class OptionManualTrader(QtWidgets.QWidget):
  2. def __init__(self, option_engine: OptionEngine, portfolio_name: str):
  3. """"""
  4. super().__init__()
  5. self.option_engine = option_engine
  6. self.main_engine: MainEngine = option_engine.main_engine
  7. self.event_engine: EventEngine = option_engine.event_engine

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

  1. def send_order(self):
  2. """"""
  3. symbol = self.symbol_line.text()
  4. contract = self.contracts.get(symbol, None)
  5. if not contract:
  6. return
  7. price_text = self.price_line.text()
  8. volume_text = self.volume_line.text()
  9. if not price_text or not volume_text:
  10. return
  11. price = float(price_text)
  12. volume = int(volume_text)
  13. direction = Direction(self.direction_combo.currentText())
  14. offset = Offset(self.offset_combo.currentText())
  15. req = OrderRequest(
  16. symbol=contract.symbol,
  17. exchange=contract.exchange,
  18. direction=direction,
  19. type=OrderType.LIMIT,
  20. offset=offset,
  21. volume=volume,
  22. price=price
  23. )
  24. self.main_engine.send_order(req, contract.gateway_name)

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

而gateway_name来自contract合约

而合约来自main_engin

  1. def init_contracts(self):
  2. """"""
  3. contracts = self.main_engine.get_all_contracts()
  4. for contract in contracts:
  5. self.contracts[contract.symbol] = contract

我们可以想象得到。而main_engine中合约的信息又来自OmsEngine 指定管理系统 (Order Manage System)

接下来我们要继续深入就必须深入到引擎的内容了。

vnpy源码阅读学习(9)回到OptionMaster的更多相关文章

  1. vnpy源码阅读学习(1):准备工作

    vnpy源码阅读学习 目标 通过阅读vnpy,学习量化交易系统的一些设计思路和理念. 通过阅读vnpy学习python项目开发的一些技巧和范式 通过vnpy的设计,可以用python复现一个小型简单的 ...

  2. vnpy源码阅读学习(5):关于MainEngine的代码阅读

    关于MainEngine的代码阅读 在入口文件中,我们看到了除了窗体界面的产生,还有关于MainEngine和EventEngin部分.今天来学习下MainEngine的代码. 首先在run代码中,我 ...

  3. vnpy源码阅读学习(4):自己写一个类似vnpy的UI框架

    自己写一个类似vnpy的界面框架 概述 通过之前3次对vnpy的界面代码的研究,我们去模仿做一个vn.py的大框架.巩固一下PyQt5的学习. 这部分的代码相对来说没有难度和深度,基本上就是把PyQt ...

  4. vnpy源码阅读学习(8):关于app

    关于app 在入口程序中,我们看到了把 gateway,app, 各类的engine都添加到mainEngine中来.不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不 ...

  5. vnpy源码阅读学习(3):学习vnpy的界面的实现

    学习vnpy的界面的实现 通过简单的学习了PyQt5的一些代码以后,我们基本上可以理解PyQt的一些用法,下面让我们来先研究下vnpy的UI部分的代码. 首先回到上一节看到的run.py(/vnpy/ ...

  6. vnpy源码阅读学习(2):学习PyQt5

    PyQt5的学习 花费了一个下午把PyQt5大概的学习了下.找了一个教程 PyQt5教程 跟着挨着把上面的案例做了一遍,大概知道PyQt5是如何生成窗体,以及控件的.基本上做到如果有需求要实现,查查手 ...

  7. vnpy源码阅读学习(7):串在一起

    串在一起 我们已经分析了UI.MainEngine.EventEngine.然后他们几个是如何发挥作用的呢?我总结了一张图: 我们来具体的看看UI部分是如何跟EventEngine穿插起来的 \exa ...

  8. Spring源码阅读学习一

    昨天抽时间阅读Spring源码,先从spring 4.x的core包开始吧,除了core和util里,首当其冲的就是asm和cglib. 要实现两个类实例之间的字段的复制功能: 多年之前用C#,因为阅 ...

  9. requests源码阅读学习笔记

    0:此文并不想拆requests的功能,目的仅仅只是让自己以后写的代码更pythonic.可能会涉及到一部分requests的功能模块,但全看心情. 1.另一种类的初始化方式 class Reques ...

随机推荐

  1. Python python 函数参数:参数组合

    '''在Python中定义函数,可以用必选参数.默认参数.可变参数和关键字参数, 这4种参数都可以一起使用,或者只用其中某些 参数定义的顺序必须是:必选参数.默认参数.可变参数和关键字参数 ''' d ...

  2. 如何测试Linux命令运行时间?

    良许在工作中,写过一个 Shell 脚本,这个脚本可以从 4 个 NTP 服务器轮流获取时间,然后将最可靠的时间设置为系统时间. 因为我们对于时间的要求比较高,需要在短时间内就获取到正确的时间.所以我 ...

  3. 使用内部枚举类作为外部类的参数的Mybatis的参数该如何判断

    新写了一个接口,期望根据不同的参数来给数据库中不同的字段进行传值.这里使用了内部静态枚举类的方式进行传值,在写mybatis动态sql时,如果是普通对象,一般使用,那么使用枚举类,如何判断枚举类的值呢 ...

  4. 性能优化之三:将Dottrace过程加入持续集成

    之前分享过一篇如何做接口性能分析的文章,但是整个分析过程有点繁琐,需要写一个控制台程序调用被测接口,再预热.启动dottrace追踪,最后才能得到我们想要的性能分析报告.如果有办法一键生成性能分析报告 ...

  5. js 图片轮播简单版

    <html> <head> <meta charset="utf-8" /> <title></title> <s ...

  6. Mitmproxy 安装

    Mitmproxy Python 安装步骤 官方文档 安装mitmproxy 在cmd中输入 pip install mitmproxy 安装完成后,在cmd中输入 mitmdump(windows不 ...

  7. IDEA+EasyCode实现代码生成

    IDEA+EasyCode实现代码生成 Easy Code介绍 EasyCode是基于IntelliJ IDEA开发的代码生成插件,支持自定义任意模板(Java,html,js,xml).只要是与数据 ...

  8. Activiti网关--并行网关

    1.什么是并行网关 并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进 入和外出顺序流的: fork 分支: 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支. ...

  9. 1642: 【USACO】Payback(还债)

    1642: [USACO]Payback(还债) 时间限制: 1 Sec 内存限制: 64 MB 提交: 190 解决: 95 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 &quo ...

  10. Pytest系列(7) - skip、skipif跳过用例

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 pytest.mark.sk ...