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.
Examplesorder.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.
ParametersArgument | 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) |
# 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