vnpy source reading learning: code reading about MainEngine

Keywords: Python network

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.

Posted by Orpheus13 on Mon, 27 Jan 2020 20:10:58 -0800