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()方法,要继续深入下去,我们有几个方向:
- market_monitor
- greeks_monitor
- manual_trader
- option_engine
- 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的更多相关文章
- vnpy源码阅读学习(1):准备工作
vnpy源码阅读学习 目标 通过阅读vnpy,学习量化交易系统的一些设计思路和理念. 通过阅读vnpy学习python项目开发的一些技巧和范式 通过vnpy的设计,可以用python复现一个小型简单的 ...
- vnpy源码阅读学习(5):关于MainEngine的代码阅读
关于MainEngine的代码阅读 在入口文件中,我们看到了除了窗体界面的产生,还有关于MainEngine和EventEngin部分.今天来学习下MainEngine的代码. 首先在run代码中,我 ...
- vnpy源码阅读学习(4):自己写一个类似vnpy的UI框架
自己写一个类似vnpy的界面框架 概述 通过之前3次对vnpy的界面代码的研究,我们去模仿做一个vn.py的大框架.巩固一下PyQt5的学习. 这部分的代码相对来说没有难度和深度,基本上就是把PyQt ...
- vnpy源码阅读学习(8):关于app
关于app 在入口程序中,我们看到了把 gateway,app, 各类的engine都添加到mainEngine中来.不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不 ...
- vnpy源码阅读学习(3):学习vnpy的界面的实现
学习vnpy的界面的实现 通过简单的学习了PyQt5的一些代码以后,我们基本上可以理解PyQt的一些用法,下面让我们来先研究下vnpy的UI部分的代码. 首先回到上一节看到的run.py(/vnpy/ ...
- vnpy源码阅读学习(2):学习PyQt5
PyQt5的学习 花费了一个下午把PyQt5大概的学习了下.找了一个教程 PyQt5教程 跟着挨着把上面的案例做了一遍,大概知道PyQt5是如何生成窗体,以及控件的.基本上做到如果有需求要实现,查查手 ...
- vnpy源码阅读学习(7):串在一起
串在一起 我们已经分析了UI.MainEngine.EventEngine.然后他们几个是如何发挥作用的呢?我总结了一张图: 我们来具体的看看UI部分是如何跟EventEngine穿插起来的 \exa ...
- Spring源码阅读学习一
昨天抽时间阅读Spring源码,先从spring 4.x的core包开始吧,除了core和util里,首当其冲的就是asm和cglib. 要实现两个类实例之间的字段的复制功能: 多年之前用C#,因为阅 ...
- requests源码阅读学习笔记
0:此文并不想拆requests的功能,目的仅仅只是让自己以后写的代码更pythonic.可能会涉及到一部分requests的功能模块,但全看心情. 1.另一种类的初始化方式 class Reques ...
随机推荐
- Springcloud config + zuul 搭建动态网关
1,实现的效果,就是zuul 网关的配置路由实现负载均衡,zuul 的配置文件放在springcloud config 上 2,需要的服务如下: 3,其实就是配置下springcloud-zuul 的 ...
- mybatis 入门基础
一.Mybatis介绍 MyBatis是一款一流的支持自定义SQL.存储过程和高级映射的持久化框架.MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去设置参数和获取检索结果.MyBatis ...
- 展示html/javascript/css------Live-Server
Live-server简介 这是一款带有热加载功能的小型开发服务器.用它来展示你的HTML / JavaScript / CSS,但不能用于部署最终的网站. 官网地址:https://www.npmj ...
- (25+4/25+4)复健-KMP/EKMP/manache/Trie
(29/29) 3.23已完成 1.KMP int Next[maxn]; void prekmp(char* x,int len){ ,suf=; Next[]=-; while(suf<l ...
- 逃生 HDU 4857(反向建图 + 拓扑排序)
逃生 链接 Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必 ...
- Java并发基础06. 线程范围内共享数据
假设现在有个公共的变量 data,有不同的线程都可以去操作它,如果在不同的线程对 data 操作完成后再去取这个 data,那么肯定会出现线程间的数据混乱问题,因为 A 线程在取 data 数据前可能 ...
- js检查数据类型
在实际工作中我们经常遇到要检测传入的参数类型是什么.也许第一时间想的的是typeof ,但这个也只是能检测个别的一些类型.如果要检测null,Array这些类型呢? 所以我们可以封装一个方法可以更加方 ...
- STM32F103ZET6通用定时器的输入捕获
1.通用定时器输入捕获功能简介 通用定时器的输入捕获模式可以用来测量脉冲宽度或者测量频率. STM32的每个通用定时器都有4个输入捕获的通道,分别是TIMx_CH1.TIMx_CH2.TIMx_CH3 ...
- Python 参数使用总结
Python 中参数的传递非常灵活,不太容易记住理解,特整理如下备忘: 普通参数 即按照函数所需的参数,对应位置传递对应的值,可以对应 Java 中的普通参数 def max(a, b): if a ...
- PTA | 1009说反话(20分)
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串.字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有 ...