diff --git a/test/trader/run.py b/test/trader/run.py index dd519036..f6240f53 100644 --- a/test/trader/run.py +++ b/test/trader/run.py @@ -4,7 +4,9 @@ from vnpy.trader.ui import MainWindow, create_qapp from vnpy.trader.ui.widget import TickMonitor -if __name__ == "__main__": + +def main(): + """""" qapp = create_qapp() event_engine = EventEngine() @@ -16,4 +18,8 @@ if __name__ == "__main__": monitor = TickMonitor(main_engine, event_engine) monitor.show() - qapp.exec() \ No newline at end of file + qapp.exec() + + +if __name__ == "__main__": + main() diff --git a/vnpy/trader/engine.py b/vnpy/trader/engine.py index 955e5263..0163c9c3 100644 --- a/vnpy/trader/engine.py +++ b/vnpy/trader/engine.py @@ -8,9 +8,10 @@ from vnpy.event import EventEngine, Event from .event import EVENT_LOG from .object import LogData, SubscribeRequest, OrderRequest, CancelRequest -from .utility import Singleton, get_temp_path +from .utility import Singleton, get_temp_path, check_order_active from .setting import SETTINGS + class MainEngine: """ Acts as the core of VN Trader. @@ -25,10 +26,34 @@ class MainEngine: self.event_engine.start() self.gateways = {} + self.engines = {} self.apps = {} - self.log_engine = LogEngine(self, self.event_engine) + self.init_engines() + def init_engines: + """ + Init all engines. + """ + # Log Engine + self.engines["log"] = LogEngine(self, self.event_engine) + + # OMS Engine + self.engines["oms"] = OmsEngine(self, self.event_engine) + + oms_engine = self.engines["oms"] + self.get_tick = oms_engine.get_tick + self.get_order = oms_engine.get_order + self.get_position = oms_engine.get_position + self.get_account = oms_engine.get_account + self.get_contract = oms_engine.get_contract + self.get_all_ticks = oms.get_all_ticks + self.get_all_orders = oms.get_all_orders + self.get_all_trades = oms.get_all_trades + self.get_all_positions = oms.get_all_positions + self.get_all_accounts = oms.get_all_accounts + self.get_all_active_orders = oms.get_all_active_orders + def write_log(self, msg: str): """ Put log event with specific message. @@ -91,7 +116,7 @@ class MainEngine: class LogEngine: """ - Process log event and output with logging module. + Processes log event and output with logging module. """ __metaclass__ = Singleton @@ -106,13 +131,15 @@ class LogEngine: self.level = SETTINGS["log.level"] self.logger = logging.getLogger("VN Trader") - self.formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") - + self.formatter = logging.Formatter( + "%(asctime)s %(levelname)s: %(message)s" + ) + self.add_null_handler() if SETTINGS["log.console"]: self.add_console_handler() - + if SETTINGS["log.file"]: self.add_file_handler() @@ -124,7 +151,7 @@ class LogEngine: """ null_handler = logging.NullHandler() self.logger.addHandler(null_handler) - + def add_console_handler(self): """ Add console output of log. @@ -133,7 +160,7 @@ class LogEngine: console_handler.setLevel(self.level) console_handler.setFormatter(self.formatter) self.logger.addHandler(console_handler) - + def add_file_handler(self): """ Add file output of log. @@ -152,6 +179,160 @@ class LogEngine: self.event_engine.register(EVENT_LOG, self.process_log_event) def process_log_event(self, event: Event): - """""" + """ + Output log event data with logging function. + """ log = event.data - self.logger.log(log.level, log.msg) \ No newline at end of file + self.logger.log(log.level, log.msg) + + +class OmsEngine: + """ + Provides order management system function for VN Trader. + """ + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + """""" + self.main_engine = main_engine + self.event_engine = event_engine + + self.ticks = {} + self.orders = {} + self.trades = {} + self.positions = {} + self.accounts = {} + self.contracts = {} + + self.active_orders = {} + + self.register_event() + + def register_event(self): + """""" + self.event_engine.register(EVENT_TICK, self.process_tick_event) + self.event_engine.register(EVENT_ORDER, self.process_order_event) + self.event_engine.register(EVENT_TRADE, self.process_trade_event) + self.event_engine.register(EVENT_POSITION, self.process_position_event) + self.event_engine.register(EVENT_ACCOUNT, self.process_account_event) + self.event_engine.register(EVENT_CONTRACT, self.process_contract_event) + + def process_tick_event(self, event: Event): + """""" + tick = event.data + self.ticks[tick.vt_symbol] = tick + + def process_order_event(self, event: Event): + """""" + order = event.data + self.orders[order.vt_orderid] = order + + # If order is active, then update data in dict. + if check_order_active(order.status): + self.active_orders[order.vt_orderid] = order + # Otherwise, pop inactive order from in dict + elif order.vt_orderid in self.active_orders: + self.active_orders.pop(order.vt_orderid) + + def process_trade_event(self, event: Event): + """""" + trade = event.data + self.trades[trade.vt_tradeid] = trade + + def process_position_event(self, event: Event): + """""" + position = event.data + self.positions[position.vt_positionid] = position + + def process_account_event(self, event: Event): + """""" + account = event.data + self.accounts[account.vt_accountid] = account + + def process_contract_event(self, event: Event): + """""" + contract = event.data + self.contracts[contract.vt_symbol]] = contract + + def get_tick(self, vt_symbol): + """ + Get latest market tick data by vt_symbol. + """ + return self.ticks.get(vt_symbol, None) + + def get_order(self, vt_orderid): + """ + Get latest order data by vt_orderid. + """ + return self.orders.get(vt_orderid, None) + + def get_trade(self, vt_tradeid): + """ + Get trade data by vt_tradeid. + """ + return self.trades.get(vt_tradeid, None) + + def get_position(self, vt_positionid): + """ + Get latest position data by vt_positionid. + """ + return self.positions.get(vt_positionid, None) + + def get_account(self, vt_accountid): + """ + Get latest account data by vt_accountid. + """ + return self.accounts.get(vt_accountid, None) + + def get_contract(self, vt_symbol): + """ + Get contract data by vt_symbol. + """ + return self.contracts.get(vt_symbol, None) + + def get_all_ticks(self): + """ + Get all tick data. + """ + return list(self.ticks.values()) + + def get_all_orders(self): + """ + Get all order data. + """ + return list(self.orders.values()) + + def get_all_trades(self): + """ + Get all trade data. + """ + return list(self.trades.values()) + + def get_all_positions(self): + """ + Get all position data. + """ + return list(self.positions.values()) + + def get_all_accounts(self): + """ + Get all account data. + """ + return list(self.accounts.values()) + + def get_all_contracts(self): + """ + Get all contract data. + """ + return list(self.contracts.values()) + + def get_all_active_orders(self, vt_symbol: str=''): + """ + Get all active orders by vt_symbol. + + If vt_symbol is empty, return all active orders. + """ + if not vt_symbol: + return list(self.active_orders.values()) + else: + active_orders = [order for order in self.active_orders.values() if order.vt_symbol == vt_symbol] + return active_orders \ No newline at end of file diff --git a/vnpy/trader/utility.py b/vnpy/trader/utility.py index 81b0f055..fdeb8374 100644 --- a/vnpy/trader/utility.py +++ b/vnpy/trader/utility.py @@ -4,6 +4,9 @@ General utility functions. from pathlib import Path +from .constant import (STATUS_NOTTRADED, STATUS_PARTTRADED, STATUS_SUBMITTING) + + class Singleton(type): """ Singleton metaclass, @@ -17,12 +20,14 @@ class Singleton(type): def __call__(cls, *args, **kwargs): """""" if cls not in cls._instances: - cls._instances[cls] = super(VtSingleton, cls).__call__(*args, **kwargs) - + cls._instances[cls] = super(VtSingleton, + cls).__call__(*args, + **kwargs) + return cls._instances[cls] -def get_temp_path(filename): +def get_temp_path(filename: str): """ Get path for temp file with filename. """ @@ -31,5 +36,18 @@ def get_temp_path(filename): if not temp_path.exists(): temp_path.mkdir() - - return temp_path.joinpath(filename) \ No newline at end of file + + return temp_path.joinpath(filename) + + +ACTIVE_STATUSES = set([STATUS_SUBMITTING, STATUS_NOTTRADED, STATUS_PARTTRADED]) + + +def check_order_active(status: str): + """ + Check if order is active by status. + """ + if status in ACTIVE_STATUSES: + return True + else: + return False \ No newline at end of file