Order Types

Limit if Touched Orders

Introduction

Limit if touched (LIT) orders are instructions to place a limit order once an asset touches a specific price level. A buy LIT order has a trigger price below the current market price and a sell LIT order has a trigger price above the current market price. In effect, LIT orders are the opposite of stop limit orders.

Place Orders

To send a LIT order, call the LimitIfTouchedOrder method and provide a Symbol, quantity, trigger price, and limit price. You can also provide a tag and order properties to the LimitIfTouchedOrder method. If you do not have sufficient capital for the order, it's rejected.

LimitIfTouchedOrder(symbol, quantity, triggerPrice, limitPrice, tag, orderProperties);
self.limit_if_touched_order(symbol, quantity, trigger_price, limit_price, tag, order_properties)

To buy an asset with a LIT order that has a marketable limit price, set the trigger price below the current market price and set the limit price above the trigger price.

// Once Bitcoin trades down to $36,000, place a limit order to buy 1 Bitcoin at $38,000
LimitIfTouchedOrder("BTCUSD", 1, 33000, 36000);
# Once Bitcoin trades down to $36,000, place a limit order to buy 1 Bitcoin at $38,000
self.limit_if_touched_order("BTCUSD", 1, 33000, 36000)
When the market price is at $55,000, a marketable buy limit if touched order is set with a trigger price at $33,000 and a limit price at $36,000. The trigger is hit, the limit is set, and the LIT order is filled when the price break below the trigger price.

To sell an asset with a LIT order that has a marketable limit price, set the trigger price above the current market price and set the limit price below the trigger price.

// Once Bitcoin trades up to $62,000, place a limit order to sell 1 Bitcoin at $59,000
LimitIfTouchedOrder("BTCUSD", -1, 62000, 59000);
# Once Bitcoin trades up to $62,000, place a limit order to sell 1 Bitcoin at $59,000
self.limit_if_touched_order("BTCUSD", -1, 62000, 59000)
When the asset is trading at $47,000, place a marketable sell limit-if-touched order with a trigger price at $62,000 and a limit price at $59,000. The trigger is hit, the limit is set, and the limit-if-touched order fills when the asset trades up to $62,000.

To buy an asset with a LIT order that has an unmarketable limit price, set the trigger price below the current market price and set the limit price below the trigger price.

// Once Bitcoin trades down to $46,000, place a limit order to buy 1 Bitcoin at $36,000
LimitIfTouchedOrder("BTCUSD", 1, 46000, 36000);
# Once Bitcoin trades down to $46,000, place a limit order to buy 1 Bitcoin at $36,000
self.limit_if_touched_order("BTCUSD", 1, 46000, 36000)
When the market price is at $56,000, set an unmarketable buy limit if touched order with a trigger price at $46,000 and a limit price at $36,000. The trigger is hit and the the limit is set when the asset trades down to $46,000. Then the limit-if-touched order fills when the asset trades down to $36,000.

To sell an asset with a LIT order that has an unmarketable limit price, set the trigger price above the current market price and set the limit price above the trigger price.

// Once Bitcoin trades up to $54,000, place a limit order to sell 1 Bitcoin at $62,000
LimitIfTouchedOrder("BTCUSD", -1, 54000, 62000);
# Once Bitcoin trades up to $54,000, place a limit order to sell 1 Bitcoin at $62,000
self.limit_if_touched_order("BTCUSD", -1, 54000, 62000)
When the market price is at $42,000, set a marketable sell limit if touched order with a trigger price at $54,000 and a limit price at $62,000. The trigger is hit and the the limit is set when the asset trades up to $54,000. The limit-if-touched order fills when the asset trades up to $62,000.

Monitor Order Fills

LIT orders fill when the security price touches the trigger price and is at least as favorable as the limit price. To monitor the fills of your order, save a reference to the order ticket.

// Once SPY trades down to $425, place a limit order to buy 10 shares at $415
var ticket = LimitIfTouchedOrder("SPY", 10, 425, 415);
Debug($"Quantity filled: {ticket.QuantityFilled}; Fill price: {ticket.AverageFillPrice}");
# Once SPY trades down to $425, place a limit order to buy 10 shares at $415
ticket = self.limit_if_touched_order("SPY", 10, 425, 415)
self.debug(f"Quantity filled: {ticket.quantity_filled}; Fill price: {ticket.average_fill_price}")

For more information about how LEAN models order fills in backtests, see Trade Fills.

Update Orders

You can update the quantity, trigger price, limit price, and tag of LIT orders until the order fills or the brokerage prevents modifications. To update an order, pass an UpdateOrderFields object to the Updateupdate method on the OrderTicket. If you don't have the order ticket, get it from the transaction manager. The Updateupdate method returns an OrderResponse to signal the success or failure of the update request.

// Create a new order and save the order ticket
var ticket = LimitIfTouchedOrder("SPY", 100, 350, 340, tag: "Original tag");

// Update the order
var updateOrderFields = new UpdateOrderFields()
{
    Quantity = 80,
    TriggerPrice = 380,
    LimitPrice = 370,
    Tag = "New tag"
}
var response = ticket.Update(updateOrderFields);

// Check the OrderResponse
if (response.IsSuccess)
{ 
    Debug("Order updated successfully");
}
# Create a new order and save the order ticket
ticket = self.limit_if_touched_order("SPY", 100, 350, 340, tag="Original tag")

# Update the order
update_order_fields = UpdateOrderFields()
update_order_fields.quantity = 80
update_order_fields.trigger_price = 380
update_order_fields.limit_price = 370
update_order_fields.tag = "New tag"
response = ticket.update(update_settings)

# Check the OrderResponse
if response.is_success:
    self.debug("Order updated successfully")

To update individual fields of an order, call any of the following methods:

  • UpdateLimitPrice
  • UpdateQuantity
  • UpdateTriggerPrice
  • UpdateTag
var limitResponse = ticket.UpdateLimitPrice(limitPrice, tag);

var quantityResponse = ticket.UpdateQuantity(quantity, tag);

var triggerResponse = ticket.UpdateTriggerPrice(triggerPrice, tag);

var tagResponse = ticket.UpdateTag(tag);

response = ticket.UpdateLimitPrice(limitPrice, tag)

response = ticket.UpdateQuantity(quantity, tag)

response = ticket.UpdateTriggerPrice(triggerPrice, tag)

response = ticket.UpdateTag(tag)

When you update an order, LEAN creates an UpdateOrderRequest object, which have the following attributes:

To get a list of UpdateOrderRequest objects for an order, call the UpdateRequests method.

var updateRequests = ticket.UpdateRequests();
update_requests = ticket.update_requests()

Cancel Orders

To cancel a LIT order, call the Cancel method on the OrderTicket. If you don't have the order ticket, get it from the transaction manager. The Cancel method returns an OrderResponse object to signal the success or failure of the cancel request.

var response = ticket.Cancel("Cancelled trade");
if (response.IsSuccess)
{
    Debug("Order successfully cancelled");
}
response = ticket.cancel("Cancelled Trade")
if response.is_success:
    self.debug("Order successfully cancelled")

When you cancel an order, LEAN creates a CancelOrderRequest, which have the following attributes:

To get the CancelOrderRequest for an order, call the CancelRequest method on the order ticket. The method returns nullNone if the order hasn't been cancelled.

var request = ticket.cancel_order_request();
request = ticket.cancel_order_request()

Brokerage Support

Each brokerage has a set of assets and order types they support. To avoid issues with LIT orders, set the brokerage model to a brokerage that supports them.

SetBrokerageModel(BrokerageName.QuantConnectBrokerage);
self.set_brokerage_model(BrokerageName.QuantConnectBrokerage)

To check if your brokerage has any special requirements for LIT orders, see the Orders section of the brokerage model documentation.

Requirements

LIT orders can be submitted at any time for all security types.

If your algorithm subscribes to extended market hours, they can be filled outside regular trading hours.

Example

The following backtest verifies the LimitIfTouchedOrder behavior. The following table shows the trades in the backtest:

Submitted TimeFilled TimeSymbolTrigger PriceLimit PriceFilled PriceQuantityTypeStatusValueTag
2021-07-01T09:31:00Z2021-07-01T09:38:00ZSPY429.00428.95428.9510Limit if touchedFilled4285.00Trigger Price: ¤429.00
Limit Price: ¤428.95
2021-07-02T09:31:00Z2021-07-02T09:49:00ZSPY431.70431.75431.84-10Limit if touchedFilled-4318.40Trigger Price: ¤431.70
Limit Price: ¤431.75
2021-07-02T09:31:00Z/SPY431.70400.00/10Limit if touchedSubmitted/Trigger Price: ¤431.70
Limit Price: ¤400.00
//SPY400.00400.00/10Limit if touchedSubmitted/Trigger Price: ¤400.00
Limit Price: ¤400.00

On July 1, 2021 at 9:31 AM Eastern Time (ET), the algorithm places a LIT order to buy SPY with a trigger price of $429 and a limit price of $428.95. At the time of the order submission, the low price was $428.80 and the bid close price was $429.10. The order fills at 9:38 AM ET at a price of $428.95. The fill model sets the limit price for buy orders when the low price is less than or equal to the trigger price, fills the order when the bid close price is less than or equal to the limit price, and sets the fill price to the minimum of the ask price and the limit price.

On July 2, 2021 at 9:31 AM ET, the algorithm places a LIT order to sell SPY with a trigger price of $431.70 and a limit price of $431.75. At the time of the order submission, the high price was $431.78 and the ask close price was $431.55. The order fills at 9:49 AM ET at a price of $431.84. The fill model sets the limit price for sell orders when the high price is greater than or equal to the trigger price, fills the order when the ask close price is greater than or equal to the limit price, and sets the fill price to the maximum of the bid price and the limit price.

On July 2, 2021, the algorithm places a third LIT order to buy SPY with a trigger price of $431.70 and a limit price of $400. The fill model sets the fill price, but it doesn't fill the order because the limit price is too low. On the same day, the algorithm places a fourth LIT order to buy SPY with a trigger price of $400 and a limit price of $400. The fill model doesn't set the limit price for this order because SPY doesn't touch the trigger price before the backtest ends.

To reproduce these results, backtest the following algorithm:

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: