Mariner Backtesting - order.send() LOO or LOC

Limit On Open & Limit On Close (Simple)

Limit On Open (LOO) and Limit On Close (LOC) Orders (Simple Order Algo)

ELITE ONLY

Overview:

Function to submit LOO and LOC orders.

Limit On Open - if no LOO is available a limit order is entered that automatically cancels after 2 minutes.

Limit On Close - if no LOC is available a limit order is automatically submitted to the market 2 minutes before the close.

There are a number of Exchange rules surrounding Limit On Open (LOO) and Limit on Close (LOC) orders. These generally relate to the timing of the order and the direction of the order.

For simplest usage place your LOO orders before 9:20am (md.market_open_time - service.time_interval(minutes=11)) and your LOC orders more than 15 minutes before the close (md.market_close_time - service.time_interval(minutes=16).

If you try to enter beyond those times, you must abide by each individual exchange's rules regarding imbalances.

Remember to extend your backtests beyond the normal core hours to allow your orders to be sent/filled. Use custom hours. Starting at 09:15 and ending at 16:15 should get the majority of your fills but keep an eye on outstanding positions, some symbols can fill very late after the close.

Examples
order.send(self.symbol, 'buy', 100, type='LOO')
order.send(self.symbol, 'sell', 100, type='LOC') 

Not for use with live trading

This order method is for use with backtesting only. It isn't supported in live trading.

Parameters
Argument Required Description Example(s)
symbol Yes The symbol for the order. QQQ
side Yes The "buy" or "sell" indicator. buy, sell
qty Yes The order quantity. 100
type Yes The order type. LOO,LOC
start_time No The time that the order is to be sent. Defaults to now. Only available for Elite. md.market_open_time - service.time_interval(minute=15)
Working Example:(Link)
 # Copyright Cloudquant, LLC. All right reserved.
# LOO CQ ELITE ONLY   = Limit  On Open  -  if no LOO is available a limit order is entered that automatically cancels after 2 minutes.
# LOC CQ ELITE ONLY   = Limit  On Close -  if no LOC is available a limit order is automatically submitted to the market 2 minutes before the close.
# Run 09:15 to 16:15 to allow time for the LOO to be submitted and the LOC to close.
# You can use the + button on custom hours and set two time periods if your model is only expected to trade in exclusive time periods.
# For this model you could run 09:15 to 09:45 and 15:44 to 16:15
# For this model, entry LOO orders are submitted 9:15am, Exit LOC orders are submitted at 15:44. 
# Actual timing requirements/cut-offs for submitting On Open and On Close orders vary significantly.

# We will run for 7/5/2017 and 7/6/2017 
# GOOG 7/5/2017 Open 901.76 Close 911.71
# GOOG 7/6/2017 Open 904.12 Close 906.69
# We will submit a LOO @ 903.00 and a LOC @ 908.00 which will work on 6/18 but not 6/19

from cloudquant.interfaces import Strategy
class New_Order_Method_LOO_LOC(Strategy):

    @classmethod
    def is_symbol_qualified(cls, symbol, md, service, account):
        return symbol=="GOOG"

    def on_start(self, md, order, service, account):
        # LOO CQ ELITE ONLY   = Limit  On Open  - matches the exchange for the symbol - if no LOO is available a limit order is entered that automatically cancels after 2 minutes.
        # Buy at a maximum of 903.50, so this should fill on the first day and not on the second.
        order.send(self.symbol, 'buy', 100, type='LOO', price=903.50) 
        print("Pre-Open - Buy    LOO {} Exchange {}".format(self.symbol.ljust(6),md.stat.exchange))
        self.status = 1

    def on_minute_bar(self, event, md, order, service, account, bar):
        if event.timestamp >= service.time(15,44) and (self.status==1 or self.status==2): # we check for both status' in case it is running in CQ LITE and so does not call on_fill
            time_string =service.time_to_string(event.timestamp, format='%H:%M:%S') 
            # LOC CQ ELITE ONLY   = Limit  On Close - matches the exchange for the symbol - if no LOC is available a limit order is automatically submitted to the market 2 minutes before the close.
            # Sell at a minimum of 908.00, so this should fill on the first day and not on the second
            order.send(self.symbol, 'sell', 100, type='LOC', price=908.00) 
            print("{} - Sell   LOC {} Exchange {}".format(time_string ,self.symbol.ljust(6),md.stat.exchange))
            self.status = 3

# Note : on_fill will only be called for CQ Elite users 
    def on_fill(self, event, md, order, service, account): 
        time_string =service.time_to_string(event.timestamp, format='%H:%M:%S') 
        if self.status == 1:
            print("{} - Filled LOO {} Price{:8.2f}".format(time_string,self.symbol.ljust(6),event.price))
            self.status = 2
        if self.status == 3:
            print("{} - Filled LOC {} Price{:8.2f}".format(time_string,self.symbol.ljust(6),event.price))
            self.status = 4

Console

2017-07-05
Pre-Open - Buy    LOO GOOG   Exchange Q
09:30:00 - Filled LOO GOOG   Price  901.76
15:44:01 - Sell   LOC GOOG   Exchange Q
16:00:00 - Filled LOC GOOG   Price  911.71

2017-07-06
Pre-Open - Buy    LOO GOOG   Exchange Q
15:44:01 - Sell   LOC GOOG   Exchange Q