Back to OptionMaster
According to our code reading of APP calling, we basically know how an app is called. Then we go back to OptionMaster to learn the implementation of this app.
Look at the structure
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
Through structure and annotation, we basically know that this is an APP in terms of options. Let's study the code carefully
__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()
In init, we see that the main engine and event engine are different from the main window, and a new engine is added. This engine is configured in the engine class when the app is registered. Then there are two reports: market monitor and Greeks monitor
init_ui
def init_ui(self): #Specific implementation self.portfolio_button = QtWidgets.QPushButton("To configure") self.portfolio_button.clicked.connect(self.open_portfolio_dialog)
The simple interface configuration we can see from the running program is as follows
We only saw portfolio_button clicking and calling 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()
We see that after clicking configure, if there is an option product selected, the portfolio dialog dialog box will pop up. According to the execution result of the dialog box, if you click accept, the drop-down box and configuration button are not available, and then execute 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)
We can see that we instantiate the market monitor, Greeks monitor, manual trader and bind the signal slot of the event. At the same time, some buttons are bound, which are basically the display of the form. It is mainly the corresponding display of the following buttons and forms
self.market_button = QtWidgets.QPushButton("T Type quote") self.greeks_button = QtWidgets.QPushButton("Position Greek") self.chain_button = QtWidgets.QPushButton("Fitting premium") self.manual_button = QtWidgets.QPushButton("Fast Trading")
And each form has passed in the engine defined by the APP
register_event
We see the call to this method in the init method at the same time.
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)
We see that this method brings the Handler and register of process ﹣ new ﹣ portfolio ﹣ event into 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)
Update the list of options products according to the call of 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()
We can see that after clicking the quick transaction, we will execute the method to obtain the option product data from the engine, and then execute the method of calculate underlying adjustment(). To go further, we have several directions:
- market_monitor
- greeks_monitor
- manual_trader
- option_engine
- calculate_underlying_adjustment
Let's learn from the surrounding to the heart, first look at several forms, and then go deep into the code learning of the engine
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):
We see that the OptionMarketMonitor inherits the MonitorTable, which is basically the same as the MonitorBase in the framework. In fact, a lot of code can almost be reused.
Let's take a look at the specific code of this class. The most worth pondering is this
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
Connect the processing of tick events, transaction events, and bin events with the option engine.
These handlers change the interface according to the information, so they will not study one by one.
Other forms
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
We can see that the form calls not only its own engine, OptionEngine, but also mainEngin and 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)
The whole order is placed through main eng in. When we analyze the main engine, we know that send order is placed through gateway name.
The gateway name comes from the contract
And the contract comes from main eng in
def init_contracts(self): """""" contracts = self.main_engine.get_all_contracts() for contract in contracts: self.contracts[contract.symbol] = contract
We can imagine that. The contract information in main engine comes from the order management system of OmsEngine
Next, we need to go deep into the content of the engine.