From 999bf151def0d0c0d67b74da7b8000cb43ae0bd0 Mon Sep 17 00:00:00 2001 From: letianzj Date: Tue, 25 Aug 2020 19:07:14 -0400 Subject: [PATCH] copy order to two order managers --- examples/instrument_meta.yaml | 27 +++++++++++++++++++ .../strategy/moving_average_cross_strategy.py | 8 ++++-- quanttrading2/brokerage/ib_brokerage.py | 2 +- quanttrading2/event/live_event_engine.py | 4 ++- quanttrading2/gui/ui_main_window.py | 9 ++++--- quanttrading2/order/fill_event.py | 4 +-- quanttrading2/order/order_manager.py | 3 ++- 7 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 examples/instrument_meta.yaml diff --git a/examples/instrument_meta.yaml b/examples/instrument_meta.yaml new file mode 100644 index 0000000..79e65b3 --- /dev/null +++ b/examples/instrument_meta.yaml @@ -0,0 +1,27 @@ +# default: multiplier: 1 +# margin: 100% +ES: + Type: FUT + Root: ES + Multiplier: 50 + Margin: 12000 +NQ: + Type: FUT + Root: NQ + Multiplier: 20 + Margin: 16000 +CL: + Type: FUT + Root: CL + Multiplier: 1000 + Margin: 6200 +HO: + Type: FUT + Root: HO + Multiplier: 42000 + Margin: 5100 +RB: + Type: FUT + Root: RB + Multiplier: 42000 + Margin: 6000 diff --git a/examples/strategy/moving_average_cross_strategy.py b/examples/strategy/moving_average_cross_strategy.py index 1434ce2..faf27f8 100644 --- a/examples/strategy/moving_average_cross_strategy.py +++ b/examples/strategy/moving_average_cross_strategy.py @@ -54,6 +54,8 @@ def on_tick(self, k): if k.price > self.ema: # (flip to) long # check standing orders; if it is also a buy order, do nothing # elif it is a sell order; cancel the order + # TODO it's possible that order fails to be placed due to connection issue; and order status is kept as acknowledged + # TODO it's also possible to cancel a partially filled order standing_oids = self._order_manager.retrieve_standing_orders() if len(standing_oids) > 0: _logger.info(f"MovingAverageCrossStrategy standing orders: {','.join(map(str, standing_oids))}") @@ -72,13 +74,14 @@ def on_tick(self, k): current_pos = int(self._position_manager.get_position_size(symbol)) if current_pos not in [-1, 0]: + # _logger.error(f'MovingAverageCrossStrategy current size exceeds. {current_pos}') return o = OrderEvent() o.full_symbol = symbol o.order_type = OrderType.LIMIT o.limit_price = self.last_bid o.order_size = 1 - current_pos - _logger.info(f'MovingAverageCrossStrategy long order placed, size {o.order_size}. ema {self.ema}, last {k.price}, bid {self.last_bid}') + _logger.info(f'MovingAverageCrossStrategy long order placed, current size {current_pos}, order size {o.order_size}. ema {self.ema}, last {k.price}, bid {self.last_bid}') self.place_order(o) else: # (flip to) short # check standing orders; if it is also a short order, do nothing @@ -101,11 +104,12 @@ def on_tick(self, k): current_pos = int(self._position_manager.get_position_size(symbol)) if current_pos not in [0, 1]: + # _logger.error(f'MovingAverageCrossStrategy current size exceeds. {current_pos}') return o = OrderEvent() o.full_symbol = symbol o.order_type = OrderType.LIMIT o.limit_price = self.last_ask o.order_size = -1 - current_pos - _logger.info(f'MovingAverageCrossStrategy short order placed, size {o.order_size}, ema {self.ema}, last {k.price}, ask {self.last_ask}') + _logger.info(f'MovingAverageCrossStrategy short order placed, current size {current_pos}, order size {o.order_size}, ema {self.ema}, last {k.price}, ask {self.last_ask}') self.place_order(o) diff --git a/quanttrading2/brokerage/ib_brokerage.py b/quanttrading2/brokerage/ib_brokerage.py index 64831ad..e9932e9 100644 --- a/quanttrading2/brokerage/ib_brokerage.py +++ b/quanttrading2/brokerage/ib_brokerage.py @@ -957,7 +957,7 @@ def currentTime(self, time: int): def execDetails(self, reqId: int, contract: Contract, execution: Execution): super().execDetails(reqId, contract, execution) msg = f"ExecDetails. ReqId: {reqId}, Symbol: {contract.symbol}, SecType: {contract.secType}, " \ - f"Currency: {contract.currency}, {execution}" + f"Currency: {contract.currency}, oid: {execution.orderId}, {execution.price}, {execution.shares}" _logger.info(msg) fill_event = FillEvent() diff --git a/quanttrading2/event/live_event_engine.py b/quanttrading2/event/live_event_engine.py index 455b276..99dd8ad 100644 --- a/quanttrading2/event/live_event_engine.py +++ b/quanttrading2/event/live_event_engine.py @@ -34,15 +34,17 @@ def _run(self): run dispatcher """ while self.__active == True: + event_type=None try: event = self._queue.get(block=True, timeout=1) + event_type = event.event_type # call event handlers if event.event_type in self._handlers: [handler(event) for handler in self._handlers[event.event_type]] except Empty: pass except Exception as e: - _logger.error(f"Error {str(e)}") + _logger.error(f"Event {event_type}, Error {str(e)}") #----------------------------- end of private functions ---------------------------# diff --git a/quanttrading2/gui/ui_main_window.py b/quanttrading2/gui/ui_main_window.py index a78bf18..5e91932 100644 --- a/quanttrading2/gui/ui_main_window.py +++ b/quanttrading2/gui/ui_main_window.py @@ -44,7 +44,7 @@ def __init__(self, config, strat_dict): self._config = config self.multiplier_dict = dict() self.central_widget = None - self.message_window = None + self.log_window = None self.order_window = None self.fill_window = None self.position_window = None @@ -78,8 +78,11 @@ def __init__(self, config, strat_dict): ## wire up event handlers self._tick_events_engine.register_handler(EventType.TICK, self._tick_event_handler) self._msg_events_engine.register_handler(EventType.ORDER, self._order_status_event_handler) + self._msg_events_engine.register_handler(EventType.ORDER, self.order_window.order_status_signal.emit) # display self._msg_events_engine.register_handler(EventType.FILL, self._fill_event_handler) + self._msg_events_engine.register_handler(EventType.FILL, self.fill_window.fill_signal.emit) # display self._msg_events_engine.register_handler(EventType.POSITION, self._position_event_handler) + self._msg_events_engine.register_handler(EventType.POSITION, self.position_window.position_signal.emit) # display self._msg_events_engine.register_handler(EventType.ACCOUNT, self.account_window.account_signal.emit) self._msg_events_engine.register_handler(EventType.CONTRACT, self._contract_event_handler) self._msg_events_engine.register_handler(EventType.HISTORICAL, self._historical_event_handler) @@ -183,21 +186,19 @@ def _tick_event_handler(self, tick_event): def _order_status_event_handler(self, order_event): # including cancel # self._order_manager.on_order_status(order_event) # this moves to order_window to tell it to update - self.order_window.order_status_signal.emit(copy(order_event)) # NEED TO MAKE A COPY self._strategy_manager.on_order_status(order_event) self.strategy_window.update_order(order_event) def _fill_event_handler(self, fill_event): # self._position_manager.on_fill(fill_event) # update portfolio manager for pnl # do not fill; just update from position_event self._order_manager.on_fill(fill_event) # update order manager with fill + self._position_manager.on_fill(fill_event) self._strategy_manager.on_fill(fill_event) # feed fill to strategy - self.fill_window.fill_signal.emit(fill_event) # display self.order_window.update_order_status(fill_event.order_id) # let order_window listen to fill as well self.strategy_window.update_fill(fill_event) def _position_event_handler(self, position_event): self._position_manager.on_position(position_event) # position received - self.position_window.position_signal.emit(position_event) # display def _account_event_handler(self, account_event): pass diff --git a/quanttrading2/order/fill_event.py b/quanttrading2/order/fill_event.py index a6cd589..a0f5bbf 100644 --- a/quanttrading2/order/fill_event.py +++ b/quanttrading2/order/fill_event.py @@ -42,6 +42,6 @@ def to_position(self): return new_position def __str__(self): - return "Time: %s, Source: %s, Ticker: %s, Price: %s, Size %s Comm %s" % ( - self.fill_time, str(self.source), self.full_symbol, str(self.fill_price), str(self.fill_size), str(self.commission) + return "Time: %s, Source: %s, Oid: %s, Ticker: %s, Price: %s, Size %s Comm %s" % ( + self.fill_time, str(self.source), str(self.order_id), self.full_symbol, str(self.fill_price), str(self.fill_size), str(self.commission) ) \ No newline at end of file diff --git a/quanttrading2/order/order_manager.py b/quanttrading2/order/order_manager.py index 919305b..1172119 100644 --- a/quanttrading2/order/order_manager.py +++ b/quanttrading2/order/order_manager.py @@ -3,6 +3,7 @@ from .order_type import * from .order_status import * from datetime import datetime +from copy import copy import logging _logger = logging.getLogger(__name__) @@ -56,7 +57,7 @@ def on_order_status(self, order_event): return False # order_id not yet assigned, open order at connection or placed by trader? else: - self.order_dict[order_event.order_id] = order_event + self.order_dict[order_event.order_id] = copy(order_event) # it is important to use copy if order_event.order_status < OrderStatus.FILLED: self.standing_order_set.add(order_event.order_id) elif order_event.order_status == OrderStatus.CANCELED: