MLThon Order package¶
Submodules¶
mlthon.order.order module¶
mlthon.order.order_mgr module¶
- class OrderMgr(client_id_prefix)[source]¶
Bases:
object
Class handling the tracking of orders and their information. Used to manage the orders in the strategies. Note that an OrderMgr instance is assumed to be associated to a single exchange.
- add_open_order(client_id, exchange_id, instrument_id, side, price, qty, order_type, tif, exec_instr, nullable_attachment)[source]¶
To be invoked to add open orders that existed before creating the OrderMgr instance. This method is not recommended in practice. Should clear all the open orders when stop trading and thus when a new strat is started, no existing open orders would be there.
- Parameters
client_id (str) – client ID, identification in our internal system.
exchange_id (str) – ID in external exchange.
instrument_id (int) – product of this order, represented via its ID, e.g. 30000000000 represents BTC-USD inverse perpetual in Bybit.
side (
Side
) – side of this order, Side.Buy or Side.Sell.price (
Price
) – price of this order.qty (
Qty
) – quantity of this order.order_type (
OrderType
) – type of this order, OrderType.Unset or OrderType.Limit (limit order).tif (
TIF
) – time in force, TIF.Unset, TIF.GTC (Good to Cancel), TIF.IOC (Execute immediately, even partially, the rest is cancelled).exec_instr (
ExecInstructions
) – execution instruction, ExecInstructions.Unset or ExecInstructions.PostOnlynullable_attachment (Optional[object]) – an any-type object researchers want to keep track of in the lifecycle of this order. It would be attached to this order. Could be None.
- Return type
None
- apply_cancel_order_ack(client_id)[source]¶
To be invoked upon reception of a CancelOrderAck msg from the exchange (e.g. use it in
IStrategy
.on_cancel_order_ack` callback method of the strat). Note that this does not mean the order is effectively cancelled, simply that the cancel request has been received by the exchange. The effective cancellation of the order happens by invoking apply_order_cancelled(). No-op if the client_id does not exist.- Parameters
client_id (str) – client_id of the order for which the CancelOrderAck has been received.
- Return type
None
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_cancel_order_ack(self, exchange: Exchange, client_id: str): self._order_mgr_.apply_cancel_order_ack(client_id=client_id) self.log_.info("on_cancel_order_ack: {ep} {clid}".format(ep=exchange.name, clid=client_id))
- apply_cancel_order_reject(client_id)[source]¶
To be invoked upon reception of a CancelOrderReject msg from the exchange (e.g. use it in
IStrategy
.on_cancel_order_reject` callback method of the strat). No-op if the client_id does not exist.- Parameters
client_id (str) – client_id of the order for which the CancelOrderReject has been received.
- Return type
None
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_cancel_order_reject(self, exchange: Exchange, client_id: str, reject_code: GtwRejectCode, reject_reason: str): self._order_mgr_.apply_cancel_order_reject(client_id=client_id) self.log_.info("on_cancel_order_reject: {ep} {clid} {rej_code} '{rej_detail}'".format(ep=exchange.name, clid=client_id, rej_code=reject_code.name, rej_detail=reject_reason))
- apply_modify_order_ack(client_id, leaves_qty)[source]¶
To be invoked upon reception of a ModifyOrderAck msg from the exchange (e.g. use it in
IStrategy.on_modify_order_ack
callback method of the strat). No-op if the client_id does not exist. An example is provided below (could check it in demo strat as well). An example is provided below.- Parameters
client_id (str) – client_id of the order for which the ModifyOrderAck has been received.
leaves_qty (
Qty
) – leaves_qty: quantity left as provided by the exchange.
- Return type
None
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_modify_order_ack(self, exchange: Exchange, client_id: str, new_price: Price, new_qty: Qty, leaves_qty: Qty): order = self._order_mgr_.get_order_with_client_id(client_id) if order: self._order_mgr_.apply_modify_order_ack(client_id=client_id, leaves_qty=leaves_qty) self.log_.info("on_modify_order_ack: {ep} {clid} {qty} @ {price}".format(ep=exchange.name, clid=client_id, qty=new_qty, price=new_price))
- apply_modify_order_reject(client_id)[source]¶
To be invoked upon reception of a ModifyOrderReject msg from the exchange (e.g. use it in
IStrategy.on_modify_order_reject
callback method of the strat). No-op if the client_id does not exist. An example is provided below.- Parameters
client_id (str) – client_id of the order for which the ModifyOrderReject has been received.
- Return type
None
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_modify_order_reject(self, exchange: Exchange, client_id: str, reject_code: GtwRejectCode, reject_reason: str): self._order_mgr_.apply_modify_order_reject(client_id=client_id) self.log_.info("on_modify_order_reject: {ep} {clid} {rej_code} '{rej_detail}'".format(ep=exchange.name, clid=client_id, rej_code=reject_code.name, rej_detail=reject_reason))
- apply_new_order_ack(client_id, exchange_id, price, leaves_qty)[source]¶
To be invoked upon reception of a NewOrderAck msg from the exchange (e.g. use it in
IStrategy.on_new_order_ack
callback method of the strat). No-op if the client_id does not exist. An example is provided below (could check it in demo strat as well).- Parameters
- Return type
None
Example
# An common usage for this method (Check demo strat for more details):
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_new_order_ack(self, exchange: Exchange, client_id: str, exchange_id: str, instrument_id: int, side: Side, price: Price, qty: Qty, leaves_qty: Qty, order_type: OrderType, tif: TIF, exec_instr: ExecInstructions): order = self._order_mgr_.get_order_with_client_id(client_id) if order: self._order_mgr_.apply_new_order_ack(client_id=client_id, exchange_id=exchange_id, price=price, leaves_qty=qty) self.log_.info("on_new_order_ack: {ep} {clid} {side} {qty} @ {price}" .format(ep=exchange.name, side=side.name, clid=client_id, qty=qty, price=price))
- apply_new_order_reject(client_id)[source]¶
To be invoked upon reception of a NewOrderReject msg from the exchange(e.g. use it in
IStrategy.on_new_order_reject
callback method of the strat). No-op if the client_id does not exist. Example is provided below, check demo strat for more details.- Parameters
client_id (str) – client_id of the order for which the NewOrderReject has been received.
- Return type
None
Example
# An common usage for this method (Check demo strat for more details):
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_new_order_reject(self, exchange: Exchange, client_id: str, reject_code: GtwRejectCode, reject_reason: str): self._order_mgr_.apply_new_order_reject(client_id=client_id) self.log_.info("on_new_order_reject: {ep} {clid} {rej_code} '{rej_detail}'".format(ep=exchange.name, clid=client_id, rej_code=reject_code.name, rej_detail=reject_reason))
- apply_order_cancelled(client_id)[source]¶
To be invoked upon reception of a OrderCancelled msg from the exchange (e.g. use it in
IStrategy
.on_order_cancelled` callback method of the strat). No-op if the client_id does not exist.- Parameters
client_id (str) – client_id of the order for which the OrderCancelled has been received.
- Return type
None
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_order_cancelled(self, exchange: Exchange, client_id: str, unsolicited: bool, engine_ts: int, recv_ts: int, cancel_code: CancelCode, cancel_reason: str): self._order_mgr_.apply_order_cancelled(client_id=client_id) self.log_.info("on_order_cancelled: {ep} {clid} {clx_code} '{clx_reason}' transac_ts={ex_ts} recv_ts={rx_ts}".format(ep=exchange.name, clid=client_id, clx_code=cancel_code.name, clx_reason=cancel_reason, ex_ts=engine_ts, rx_ts=recv_ts))))
- apply_order_execution(client_id, fill_qty, nullable_leaves_qty)[source]¶
To be invoked upon reception of a OrderExecution msg from the exchange (e.g. use it in
IStrategy
.on_order_execution` callback method of the strat). No-op if the client_id does not exist. An example is provided below (could check it in demo strat as well).- Parameters
- Returns
typing.Optional[bool] (None if the order doesn’t exist. If the order exists, True if the order has been fully)
executed, False otherwise.
Example
An example usage of this method is as follows. Use order mgr to confirm the order is fully executed in order to start calculating the realized PNL, etc. Check demo strat for more details.
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def on_order_execution(self, exchange: Exchange, client_id: str, side: Side, price: Price, fill_qty: Qty, leaves_qty: Qty, exec_ts: int, recv_ts: int): if leaves_qty and leaves_qty.is_null(): leaves_qty = None order = self._order_mgr_.get_order_with_client_id(client_id) if order: is_fully_executed = self._order_mgr_.apply_order_execution(client_id=client_id, fill_qty=fill_qty, nullable_leaves_qty=leaves_qty) if is_fully_executed is not None: # could start to calculate PNL, etc. (check demo strat for more details) ......
- check_for_stale_orders(now_ts)[source]¶
Check if there are stale orders and returns them in a list. An order is considered stale if it is left in a ‘pending state’ for more than 10 seconds. More specifically if a prepare_new, prepare_modify, prepare_cancel is left unanswered, or if an order is not effectively cancelled after its cancel request has been acked.
- Parameters
now_ts (int) – current timestamp in milliseconds.
- Returns
typing.List[:obj:`.Order`]
- Return type
list of stale orders.
- get_all_orders()[source]¶
Get a list of all orders currently managed by this instance. Includes all orders expect those that have been fully executed or cancelled, and have no pending requests.
- Returns
typing.List[:obj:`.Order`]
- Return type
list of all orders managed by this instance.
- get_num_open_orders()[source]¶
Get the number of open orders on both side. Note that a pending-new order for which the NewOrderAck has not been received is not considered to be an open order.
- Returns
int
- Return type
number of open orders.
- get_num_open_orders_on_side(side)[source]¶
Get the number of open orders on the given side. Note that a pending-new order for which the NewOrderAck has not been received is not considered to be an open order.
- Parameters
side (
Side
) – side for which the number of orders is requested.- Returns
int
- Return type
number of open orders on the corresponding side.
- get_open_orders()[source]¶
Get a list of all the open orders. Note that a pending-new order for which the NewOrderAck has not been received is not considered to be an open order.
- Returns
typing.List[:obj:`.Order`]
- Return type
list of open orders.
- get_open_orders_on_side(side)[source]¶
Get a list of all the open orders on the provided side. Note that a pending-new order for which the NewOrderAck has not been received is not considered to be an open order.
- get_order_with_client_id(client_id)[source]¶
Get an order provided its client_id.
- Parameters
client_id (str) – client_id (internal identification) of the order to retrieve.
- Returns
:obj:`.Order`
- Return type
order with matching client_id, None if not found.
- get_order_with_exchange_id(exchange_id)[source]¶
Get an order provided its exchange_id.
- Parameters
exchange_id (str) – exchange_id (external identification) of the order to retrieve.
- Returns
:obj:`.Order`
- Return type
order with matching exchange_id, None if not found.
- prepare_cancel_order(client_id)[source]¶
Prepare the cancellation of an order given its client_id. Return True if the order can be cancelled, meaning no other request is pending. An example is provided below (could check it in demo strat as well).
- Parameters
client_id (str) – client_id of the order to be cancelled.
- Returns
bool
- Return type
True if the order can be cancelled, meaning no other request is pending, False otherwise.
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def CancelOrder(self, order: Order, instrument_id: int, reason = 'cancel_order'): order_id = order.get_client_id() if order.is_new_pending() or order.is_modify_pending() or order.is_cancel_pending(): self.log_.info("Cannot cacenl Order: " + str(order_id) + " in " + order_state + " state") return ready_to_send_cancel = self._order_mgr_.prepare_cancel_order(client_id=order_id) if ready_to_send_cancel: self.env_.send_cancel_order(exchange=self._exch_, instrument_id=instrument_id, client_ord_id=order_id) self.env_.publish_telegram("Sent a cancel: " + str(order_id) + " reason:" + reason)
Then use CancelOrder() method to cancel the orders safely in the strat.
- prepare_modify_order(client_id, new_price, new_qty)[source]¶
Prepare the modification of an order given the provided parameters. Return true if the modification can be done, meaning the order has NO other pending request. This method should be used before sending modify order vid trading environment. An example is provided below.
- Parameters
- Returns
bool
- Return type
True if the order can be modified, False otherwise.
Example
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def ModifyOrder(self, client_id: str, side: Side, price: float, qty: Qty, reason: str, exch: Exchange): # may need to format price and qty first. Check demo strat for more details can_be_modified = self._order_mgr_.prepare_modify_order(client_id=client_id, new_price=price, new_qty=qty) if can_be_modified: self.env_.send_modify_order(exchange=exch, client_ord_id=client_id, new_price=price, new_qty=qty)
Then use ModifyOrder() method to send modify orders and keep track of order status inside the strat
- prepare_new_order(instrument_id, side, price, qty, order_type, tif, exec_instr, nullable_attachment)[source]¶
To be called before sending an order. If no cancel-all is pending, prepare a new Order instance based on the given parameters. The created order will have a uniquely generated client_id. Example usage is provided below.
- Parameters
instrument_id (int) – product of this order, represented via its ID, e.g. 30000000000 represents BTC-USD inverse perpetual in Bybit.
side (
Side
) – side of this order, Side.Buy or Side.Sell.price (
Price
) – price of this order.qty (
Qty
) – quantity of this order.order_type (
OrderType
) – type of this order, OrderType.Unset or OrderType.Limit (limit order).tif (
TIF
) – time in force, TIF.Unset, TIF.GTC (Good to Cancel), TIF.IOC (Execute immediately, even partially, the rest is cancelled).exec_instr (
ExecInstructions
) – execution instruction, ExecInstructions.Unset or ExecInstructions.PostOnlynullable_attachment (Optional[object]) – an any-type object researchers want to keep track of in the lifecycle of this order. It would be attached to this order. Could be None.
- Return type
None if a cancel-all is pending. Otherwise, it will return a valid Order instance.
Example
# An common usage for this method (Check demo strat for more details):
class DemoStrat(): def __init__(self, cfg): # or no cfg ... ...... def SendOrder(self, side: Side, price: float, qty: Qty, reason: str, exch: Exchange, instrument_id: int, exec_instr=ExecInstructions.Unset, ord_type=OrderType.Limit, tif=TIF.GTC, close_position: bool = False): # may need to round up/down the price and qty first. Check demo strat for more details order = self._order_mgr_.prepare_new_order(instrument_id=instrument_id, side=side, price=price, qty=qty, exec_instr=exec_instr, order_type=OrderType.Limit, tif=TIF.GTC, nullable_attachment=reason) if order: new_order_clid = order.get_client_id() self.env_.send_new_order(client_id=new_order_clid, exchange=exch, instrument_id=instrument_id, side=side, price=price, qty=qty, exec_instr=exec_instr, ord_type, time_in_force=tif, close_position=close_position) ......
Then use this SendOrder() method to send the orders into the trading system, and keep track of this order inside the strat.