回到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)

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

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. springBoot集成zuul路由forward,设置setSendZuulResponse无效

    正确书写方式如下: RequestContext ctx = RequestContext.getCurrentContext(); ctx.setSendZuulResponse(false); c ...

  2. Python面向对象之异常处理

    1:什么是异常 异常就是在我们的程序在运行过程中由于某种错误而引发Python抛出的错误: 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序 ...

  3. 服务器部署Jupyter Notebook

    先安装jupyter notebook pip install ipython pip install jupyter 创建一个目录(jupyter notebook工作目录) mkdir jupyt ...

  4. Ubuntu命令方式安装中文语言包

    Ubuntu命令方式安装中文语言包 安装之前执行 $LANG 查看语言环境 中文语言包: language-pack-zh-hans 简体中文 language-pack-zh-hans-base l ...

  5. Java 为 Excel 中的行设置交替背景色

    在制作Excel表格时,通过将数据表中上下相邻的两行用不同的背景色填充,可以使各行的数据看起来更清楚,避免看错行,同时也能增加Excel表格的美观度.本文将介绍如何在Java程序中为 Excel 奇数 ...

  6. MFC之使用blat发送邮件

    blat的下载地址:http://www.blat.net 我用它进行了smtp服务的邮件发送.这里我使用的qq邮箱,qq邮箱使用的密码是授权码,可以再qq邮箱设置里面开启smtp服务.下载下来是文件 ...

  7. C++动态内存new和delete(超详细)

    C++动态内存new和delete C++动态内存是C++灵活.炫酷的一种操作.学好它,能让自己编程逼格上一个level. 在学习动态内存之前,我们先要了解C++是怎么划分内存的: 栈:在函数内部声明 ...

  8. .NET Core项目部署到Linux(Centos7)(二)环境和软件的准备

    目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...

  9. Tkinter 控件

    文章更新于:2020-02-19 待翻译跟进 In this part of the Tkinter tutorial, we will cover some basic Tkinter widget ...

  10. 模板继承和UImodul 和 UImethods

     模板继承和UImodul 和 UImethods 模板的继承 {% extends path %} path为templates下的相对路径 {% block block_name %}conten ...