Skip to content

Commit

Permalink
on_order_status and on_fill reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
letianzj committed Aug 14, 2020
1 parent 4fbeb57 commit 71c0deb
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 30 deletions.
10 changes: 6 additions & 4 deletions quanttrading2/backtest_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ def _setup(self):

## 6. wire up event handlers
self._events_engine.register_handler(EventType.TICK, self._tick_event_handler)
# to be consistent with current live, order is placed directly
# self._events_engine.register_handler(EventType.ORDER, self._order_event_handler)
# to be consistent with current live, order is placed directly; this accepts other status like status, fill, cancel
self._events_engine.register_handler(EventType.ORDER, self._order_event_handler)
self._events_engine.register_handler(EventType.FILL, self._fill_event_handler)

# ------------------------------------ private functions -----------------------------#
Expand All @@ -117,11 +117,13 @@ def _tick_event_handler(self, tick_event):
def _order_event_handler(self, order_event):
"""
This is not active
backtest doesn't send order_event back to strategy. It fills directly and becoems fill_event
backtest doesn't send order_event back to strategy. It fills directly and becomes fill_event
"""
self._backtest_brokerage.place_order(order_event)
# self._backtest_brokerage.place_order(order_event)
pass

def _fill_event_handler(self, fill_event):
self._order_manager.on_fill(fill_event)
self._position_manager.on_fill(fill_event)
self._performance_manager.on_fill(fill_event)
self._strategy.on_fill(fill_event)
Expand Down
4 changes: 2 additions & 2 deletions quanttrading2/brokerage/ib_brokerage.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ def openOrder(self, orderId: OrderId, contract: Contract, order: Order, orderSta
def openOrderEnd(self):
super().openOrderEnd()
_logger.info("OpenOrderEnd")
_logger.info(f"Received %d openOrders {len(list(self.broker.order_dict.keys()))}")
_logger.info(f"Received openOrders {len(list(self.broker.order_dict.keys()))}")

def orderStatus(self, orderId: OrderId, status: str, filled: float,
remaining: float, avgFillPrice: float, permId: int,
Expand Down Expand Up @@ -619,7 +619,7 @@ def pnlSingle(self, reqId: int, pos: int, dailyPnL: float,

def marketDataType(self, reqId: TickerId, marketDataType: int):
super().marketDataType(reqId, marketDataType)
_logger.info("MarketDataType. ReqId:", reqId, "Type:", marketDataType)
_logger.info(f"MarketDataType. ReqId: {reqId}, Type: {marketDataType}")

def tickPrice(self, reqId: TickerId, tickType: TickType, price: float,
attrib: TickAttrib):
Expand Down
8 changes: 5 additions & 3 deletions quanttrading2/gui/ui_fill_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
_logger = logging.getLogger(__name__)

class FillWindow(QtWidgets.QTableWidget):
"""
present fills
"""
fill_signal = QtCore.pyqtSignal(type(FillEvent()))

def __init__(self, order_manager, parent=None):
def __init__(self, parent=None):
super(FillWindow, self).__init__(parent)

self.header = ['OrderID',
Expand All @@ -23,7 +26,6 @@ def __init__(self, order_manager, parent=None):
'Account']

self.init_table()
self._order_manager = order_manager
self._fillids = []
self.fill_signal.connect(self.update_table)

Expand All @@ -42,7 +44,7 @@ def update_table(self,fill_event):
Only add row
'''
if fill_event.fill_id in self._fillids:
row = self._orderids.index(fill_event.broker_order_id)
row = self._fillids.index(fill_event.fill_id)
self.item(row, 6).setText(fill_event.fill_time)
_logger.error('received same fill twice')
else: # including empty
Expand Down
20 changes: 11 additions & 9 deletions quanttrading2/gui/ui_main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ def __init__(self, config, strat_dict):

self._ui_events_engine = LiveEventEngine() # update ui
self._broker = InteractiveBrokers(self._ui_events_engine, self._config['account'])
self._position_manager = PositionManager()
self._position_manager = PositionManager() # global position manager
self._position_manager.set_multiplier(self.multiplier_dict)
self._order_manager = OrderManager()
self._order_manager = OrderManager() # global order manager
self._data_board = DataBoard()
self.risk_manager = PassThroughRiskManager()
self.account_manager = AccountManager(self._config['account'])

self._strategy_manager = StrategyManager(self._broker, self._order_manager, self._position_manager, self._data_board, self.risk_manager, self.multiplier_dict)
self._strategy_manager = StrategyManager(self._config, self._broker, self._order_manager, self._position_manager, self.risk_manager, self._data_board, self.multiplier_dict)
self._load_strategy(strat_dict)

self.widgets = dict()
Expand Down Expand Up @@ -136,20 +136,22 @@ def closeEvent(self, a0: QtGui.QCloseEvent):
def _tick_event_handler(self, tick_event):
self._current_time = tick_event.timestamp

self._data_board.on_tick(tick_event) # update databoard
self._order_manager.on_tick(tick_event)
self._strategy_manager.on_tick(tick_event) # feed strategies
self._position_manager.mark_to_market(tick_event.timestamp, tick_event.full_symbol, tick_event.price, self._data_board)
self._data_board.on_tick(tick_event) # update databoard

def _order_status_event_handler(self, order_status_event): # including cancel
def _order_status_event_handler(self, order_event): # including cancel
# this is moved to ui_thread for consistency
# self._order_manager.on_order_status(order_event)
self._strategy_manager.on_order_status(order_event)
pass

def _fill_event_handler(self, fill_event):
# update portfolio manager for pnl
self._position_manager.on_fill(fill_event) # update portfolio manager for pnl
self._order_manager.on_fill(fill_event) # update order manager with fill
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,
self.order_window.update_order_status(fill_event.order_id, # let order_window listen to fill as well
self._order_manager.retrieve_order(fill_event.order_id).order_status)

def _position_event_handler(self, position_event):
Expand Down Expand Up @@ -242,7 +244,7 @@ def init_central_area(self):
tab2_layout.addWidget(self.order_window)
tab2.setLayout(tab2_layout)

self.fill_window =FillWindow(self._order_manager)
self.fill_window =FillWindow()
tab3_layout = QtWidgets.QVBoxLayout()
tab3_layout.addWidget(self.fill_window)
tab3.setLayout(tab3_layout)
Expand Down
7 changes: 4 additions & 3 deletions quanttrading2/gui/ui_order_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def update_table(self, order_event):
'''
update = self._order_manager.on_order_status(order_event)

if (update):
if(update):
if order_event.order_id in self._orderids:
row = self._orderids.index(order_event.order_id)
self.item(row, 7).setText(str(self._order_manager.order_dict[order_event.order_id].fill_size))
Expand All @@ -77,8 +77,9 @@ def update_order_status(self, order_id, order_status):
"""
This is called by fill handler to update order status
"""
row = self._orderids.index(order_id)
self.item(row, 8).setText(order_status.name)
if order_id in self._orderids:
row = self._orderids.index(order_id)
self.item(row, 8).setText(order_status.name)

def cancel_order(self,mi):
row = mi.row()
Expand Down
5 changes: 5 additions & 0 deletions quanttrading2/order/order_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ def on_order_status(self, order_event):
return True

def on_cancel(self, o):
"""
TODO: remove on cancel? It's one order status
:param o:
:return:
"""
self._canceled_order_list.append(o.order_id)
if o.order_id in self.order_dict.keys():
self.order_dict[o.order_id].order_status = OrderStatus.CANCELED
Expand Down
10 changes: 5 additions & 5 deletions quanttrading2/strategy/strategy_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self):
self.strategy_manager = None # to place order through strategy_manager
self._data_board = None # to get current data
self._position_manager = PositionManager() # track local positions and cash
self._order_manager = OrderManager() # manage lcoal (standing) orders and fills
self._order_manager = OrderManager() # manage local (standing) orders and fills

self.active = False
self.initialized = False
Expand Down Expand Up @@ -63,28 +63,28 @@ def on_tick(self, tick_event):
# for backtest, call super().on_tick() if need to track positions or npv or cash
self._position_manager.mark_to_market(tick_event.timestamp, tick_event.full_symbol, tick_event.price, self._data_board)


def on_order_status(self, order_event):
"""
on order acknowledged
:return:
"""
#raise NotImplementedError("Should implement on_order_status()")
pass
self._order_manager.on_order_status(order_event)

def on_cancel(self):
def on_cancel(self, order_event):
"""
on order canceled
:return:
"""
pass
self._order_manager.on_cancel(order_event)

def on_fill(self, fill_event):
"""
on order filled
derived class call super().on_fill first
"""
self._position_manager.on_fill(fill_event)
self._order_manager.on_fill(fill_event)

def place_order(self, o):
"""
Expand Down
28 changes: 24 additions & 4 deletions quanttrading2/strategy/strategy_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,40 @@ def on_tick(self, k):
self._strategy_dict[sid].on_tick(k)

def on_position(self, pos):
"""
get initial position
read from config file instead
:param pos:
:return:
"""
pass

def on_order_status(self, order_event):
"""
TODO: check if source is working
:param order_event:
:return:
"""
sid = order_event.source
if sid in self._strategy_dict.keys():
self._strategy_dict[sid].on_order_status(order_event)
else:
_logger.info('strategy manager doesnt hold the oid, possibly from outside of the system')

def on_cancel(self, oid):
pass
def on_cancel(self, order_event):
sid = order_event.source
if sid in self._strategy_dict.keys():
self._strategy_dict[sid].on_order_status(order_event)
else:
_logger.info('strategy manager doesnt hold the oid, possibly from outside of the system')

def on_fill(self, fill):
def on_fill(self, fill_event):
"""
assign fill ordering to order id ==> strategy id
TODO: check fill_event source; if not, fix it or use fill_event.order_id
"""
pass
sid = fill_event.source
if sid in self._strategy_dict.keys():
self._strategy_dict[sid].on_fill(fill_event)
else:
_logger.info('strategy manager doesnt hold the oid, possibly from outside of the system')

0 comments on commit 71c0deb

Please sign in to comment.