Code reading for MainEngine
In the entry file, we see the MainEngine and EventEngin sections in addition to the generation of the form interface.Learn about MainEngine's code today.
First in the run code, we see the following code
main_engine.add_gateway(DeribitGateway) main_engine.add_app(OptionMasterApp)
From the above code, you can basically guess that all the network administrators, settings, and even the policy engine conditions are related to MainEngine, which should be a mainline to plug in all the components.MainEngine must be an important big fish.Here's where we start in MainEngin: \vnpy\trader\engine.py
The general context of MainEngine
class MainEngine: #Initialization def __init__(self, event_engine: EventEngine = None): pass #Add Engine def add_engine(self, engine_class: Any): pass #Add network management def add_gateway(self, gateway_class: Type[BaseGateway]): pass #Add app def add_app(self, app_class: Type[BaseApp]): pass #Initialization Engine def init_engines(self): pass #Write to Log def write_log(self, msg: str, source: str = ""): pass #Get Engine def get_engine(self, engine_name: str): pass #Get Default Settings def get_default_setting(self, gateway_name: str): pass #Get the names of all engines def get_all_gateway_names(self): pass #Get all APP s def get_all_apps(self): pass #Get all exchanges def get_all_exchanges(self): pass #Connect to Quotes def connect(self, setting: dict, gateway_name: str): pass #Contract Subscription def subscribe(self, req: SubscribeRequest, gateway_name: str): pass #Place an order def send_order(self, req: OrderRequest, gateway_name: str): pass #Cancellation of order def cancel_order(self, req: CancelRequest, gateway_name: str): pass #Bulk Order def send_orders(self, reqs: Sequence[OrderRequest], gateway_name: str): pass #Bulk Cancel Order def cancel_orders(self, reqs: Sequence[CancelRequest], gateway_name: str): pass #History Query def query_history(self, req: HistoryRequest, gateway_name: str): pass #Close def close(self): pass
I stripped out all the method bodies, leaving just the method names and parameters. Basically, the structure above shows that MainEngine is a mix of almost all components (GateWay, App, Engin) connected together, while providing a mix of transaction-related connections, subscriptions, placing orders, withdrawals, history, and so on.Next let's start with a method of reading and learning.
__init__
def __init__(self, event_engine: EventEngine = None): """""" if event_engine: self.event_engine = event_engine else: self.event_engine = EventEngine() self.event_engine.start() self.gateways = {} self.engines = {} self.apps = {} self.exchanges = [] os.chdir(TRADER_DIR) # Change working directory self.init_engines() # Initialize function engines
The code to initialize is essentially to instantiate the Event Engin, start it, create a dictionary for getways, engines, apps, exchanges, and call the init_engines() method.
Various add methods, AddEngine, AddGateWay, AddApp
def add_engine(self, engine_class: Any): """ Add function engine. """ engine = engine_class(self, self.event_engine) self.engines[engine.engine_name] = engine return engine def add_gateway(self, gateway_class: Type[BaseGateway]): """ Add gateway. """ gateway = gateway_class(self.event_engine) self.gateways[gateway.gateway_name] = gateway # Add gateway supported exchanges into engine for exchange in gateway.exchanges: if exchange not in self.exchanges: self.exchanges.append(exchange) return gateway def add_app(self, app_class: Type[BaseApp]): """ Add app. """ app = app_class() self.apps[app.app_name] = app engine = self.add_engine(app.engine_class) return engine
The three Add methods mentioned above are relatively simple, basically adding various APP s, Engine s, Gateways, instantiating them and name to form key-value pairs into the map.The only clue we can get is that there should be a correspondence between gateways and Exchanges. In a word, gateways are API docking network managers for trading sites.So each time you add a gateway, you add a name for the exchange.
get method
def get_gateway(self, gateway_name: str): """ Return gateway object by name. """ gateway = self.gateways.get(gateway_name, None) if not gateway: self.write_log(f"Unable to find the underlying interface:{gateway_name}") return gateway def get_engine(self, engine_name: str): """ Return engine object by name. """ engine = self.engines.get(engine_name, None) if not engine: self.write_log(f"Engine not found:{engine_name}") return engine def get_default_setting(self, gateway_name: str): """ Get default setting dict of a specific gateway. """ gateway = self.get_gateway(gateway_name) if gateway: return gateway.get_default_setting() return None
Basically, it's a way to get an object from a map based on a specified name.Stick out a mile.The get_default_setting method should belong to a subordinate method of get_gateway to get the setting of the gateway.
get_all method
def get_all_apps(self): """ Get all app objects. """ return list(self.apps.values()) def get_all_exchanges(self): """ Get all exchanges. """ return self.exchanges
It is also a global method of acquiring objects that add enters.
connect
def connect(self, setting: dict, gateway_name: str): """ Start connection of a specific gateway. """ gateway = self.get_gateway(gateway_name) if gateway: gateway.connect(setting)
Basically, you can understand that connects are a way to decorate a gateway.With add, you can insert a gateway, then call the connect method, get the interface through gateway_name, and then call the connection method of the gateway.Unexpectedly, the following subscription quotations, placing orders, withdrawals, bulk withdrawals are similar.
Other similar methods of gateway
def subscribe(self, req: SubscribeRequest, gateway_name: str): """ Subscribe tick data update of a specific gateway. """ gateway = self.get_gateway(gateway_name) if gateway: gateway.subscribe(req) def send_order(self, req: OrderRequest, gateway_name: str): """ Send new order request to a specific gateway. """ gateway = self.get_gateway(gateway_name) if gateway: return gateway.send_order(req) else: return "" def cancel_order(self, req: CancelRequest, gateway_name: str): """ Send cancel order request to a specific gateway. """ gateway = self.get_gateway(gateway_name) if gateway: gateway.cancel_order(req) def send_orders(self, reqs: Sequence[OrderRequest], gateway_name: str): """ """ gateway = self.get_gateway(gateway_name) if gateway: return gateway.send_orders(reqs) else: return ["" for req in reqs] def cancel_orders(self, reqs: Sequence[CancelRequest], gateway_name: str): """ """ gateway = self.get_gateway(gateway_name) if gateway: gateway.cancel_orders(reqs) def query_history(self, req: HistoryRequest, gateway_name: str): """ Send cancel order request to a specific gateway. """ gateway = self.get_gateway(gateway_name) if gateway: return gateway.query_history(req) else: return None
init_engine
def init_engines(self): """ Init all engines. """ self.add_engine(LogEngine) self.add_engine(OmsEngine) self.add_engine(EmailEngine)
Assemble logs, OMSEngin, EmialEngin
close method
def close(self): """ Make sure every gateway and app is closed properly before programme exit. """ # Stop event engine first to prevent new timer event. self.event_engine.stop() for engine in self.engines.values(): engine.close() for gateway in self.gateways.values(): gateway.close()
Basically it's the aftermath after the program exits.
summary
By sorting through MainEngin code, we can see that MainEngine itself is not really deep.Is the mode of an adapter that abstracts all operations into APP, Gateway, Engine.It also provides a unified access to operations, which makes it easy to extend.