# Copyright 2019 The TensorTrade Authors.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the LicensefromtypingimportList,DictfromcollectionsimportOrderedDictfromtensortrade.core.baseimportTimeIndexedfromtensortrade.oms.orders.orderimportOrder,OrderStatusfromtensortrade.oms.orders.order_listenerimportOrderListener
[docs]classBroker(OrderListener,TimeIndexed):"""A broker for handling the execution of orders on multiple exchanges. Orders are kept in a virtual order book until they are ready to be executed. Attributes ---------- unexecuted : `List[Order]` The list of orders the broker is waiting to execute, when their criteria is satisfied. executed : `Dict[str, Order]` The dictionary of orders the broker has executed since resetting, organized by order id. trades : `Dict[str, Trade]` The dictionary of trades the broker has executed since resetting, organized by order id. """def__init__(self):self.unexecuted=[]self.executed={}self.trades=OrderedDict()
[docs]defsubmit(self,order:"Order")->None:"""Submits an order to the broker. Adds `order` to the queue of orders waiting to be executed. Parameters ---------- order : `Order` The order to be submitted. """self.unexecuted+=[order]
[docs]defcancel(self,order:"Order")->None:"""Cancels an order. Parameters ---------- order : `Order` The order to be canceled. """iforder.status==OrderStatus.CANCELLED:raiseWarning(f"Order {order.id} has already been cancelled.")iforderinself.unexecuted:self.unexecuted.remove(order)order.cancel()
[docs]defupdate(self)->None:"""Updates the brokers order management system. The broker will look through the unexecuted orders and if an order is ready to be executed the broker will submit it to the executed list and execute the order. Then the broker will find any orders that are active, but expired, and proceed to cancel them. """executed_ids=[]fororderinself.unexecuted:iforder.is_executable:executed_ids.append(order.id)self.executed[order.id]=orderorder.attach(self)order.execute()fororder_idinexecuted_ids:self.unexecuted.remove(self.executed[order_id])fororderinself.unexecuted+list(self.executed.values()):iforder.is_activeandorder.is_expired:self.cancel(order)
[docs]defon_fill(self,order:"Order",trade:"Trade")->None:"""Updates the broker after an order has been filled. Parameters ---------- order : `Order` The order that is being filled. trade : `Trade` The trade that is being made to fill the order. """iftrade.order_idinself.executedandtradenotinself.trades:self.trades[trade.order_id]=self.trades.get(trade.order_id,[])self.trades[trade.order_id]+=[trade]iforder.is_complete:next_order=order.complete()ifnext_order:ifnext_order.is_executable:self.executed[next_order.id]=next_ordernext_order.attach(self)next_order.execute()else:self.submit(next_order)
[docs]defreset(self)->None:"""Resets the broker."""self.unexecuted=[]self.executed={}self.trades=OrderedDict()