From ee8d0e0aa47e1ccd6d453afba39839f651e83ba2 Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Thu, 24 Sep 2026 23:36:51 +0100 Subject: [PATCH] Add Order Factory page and split Contingent Orders for LEAN #9828 Contingent Orders becomes a landing page with one page per contingency type, sharing its sections through Resources includes. Fee estimates and buying power checks move to shared includes that use order requests, since the old initial margin check accepted every sell order and rejected positions that close an existing holding. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../01 Order Factory/01 Introduction.html | 1 + .../02 Create Order Requests.html | 79 +++++++++ .../03 Submit Order Requests.html | 24 +++ .../04 Estimate Order Fees.php | 4 + .../05 Check Buying Power.php | 4 + .../01 Order Factory/99 Examples.html | 62 +++++++ .../01 Order Factory/metadata.json | 12 ++ .../01 Introduction.html | 0 .../02 Properties.php | 0 .../03 Track Orders.php | 0 .../04 Update Orders.php | 0 .../05 Cancel Orders.html | 0 .../06 Order Response.php | 0 .../99 Examples.html | 0 .../metadata.json | 0 .../01 Introduction.html | 0 .../02 Get a Single Order Ticket.html | 0 .../03 Get Order Tickets.html | 0 .../04 Get a Single Order.html | 0 .../05 Get Orders.html | 0 .../06 Get Remaining Order Quantity.html | 0 .../07 Cancel Orders.html | 0 .../08 Live Trading Considerations.php | 0 .../99 Examples.html | 0 .../metadata.json | 0 .../13 Contingent Orders/00.html | 72 +++++++++ .../01 Bracket Orders/01 Introduction.html | 1 + .../02 Place Orders.html} | 8 +- .../01 Bracket Orders/03 Monitor Orders.php | 4 + .../01 Bracket Orders/04 Update Orders.php | 14 ++ .../01 Bracket Orders/05 Cancel Orders.php | 14 ++ .../01 Bracket Orders/06 Backtest Fills.php | 4 + .../01 Bracket Orders/07 Buying Power.php | 4 + .../08 Brokerage Support.php | 3 + .../{ => 01 Bracket Orders}/99 Examples.html | 0 .../01 Bracket Orders/metadata.json | 12 ++ .../13 Contingent Orders/01 Introduction.html | 9 -- .../01 Introduction.html | 1 + .../02 Place Orders.html} | 2 +- .../03 Monitor Orders.php | 4 + .../04 Update Orders.php | 14 ++ .../05 Cancel Orders.php | 14 ++ .../06 Backtest Fills.php | 4 + .../07 Buying Power.php | 4 + .../08 Brokerage Support.php | 3 + .../99 Examples.html | 48 ++++++ .../02 One Cancels Other Orders/metadata.json | 12 ++ .../01 Introduction.html | 1 + .../02 Place Orders.html} | 10 +- .../03 Monitor Orders.php | 4 + .../04 Update Orders.php | 14 ++ .../05 Cancel Orders.php | 14 ++ .../06 Backtest Fills.php | 4 + .../07 Buying Power.php | 4 + .../08 Brokerage Support.php | 3 + .../99 Examples.html | 45 ++++++ .../metadata.json | 12 ++ .../01 Introduction.html | 1 + .../02 Place Orders.html | 21 +++ .../03 Monitor Orders.php | 4 + .../04 Update Orders.php | 14 ++ .../05 Cancel Orders.php | 14 ++ .../06 Backtest Fills.php | 4 + .../07 Buying Power.php | 4 + .../08 Brokerage Support.php | 3 + .../99 Examples.html | 48 ++++++ .../04 One Updates Other Orders/metadata.json | 12 ++ .../01 Introduction.html | 4 + .../02 Relate Order Requests.html} | 11 +- .../03 Combo Orders.html} | 0 .../04 Brokerage Support.php | 3 + .../99 Examples.html | 62 +++++++ .../05 Custom Contingent Orders/metadata.json | 12 ++ .../05 One Updates Other Orders.html | 15 -- .../09 Update Orders.html | 16 -- .../10 Cancel Orders.html | 16 -- .../13 Contingent Orders/12 Buying Power.html | 1 - .../13 Contingent Orders/metadata.json | 12 -- .../01 Key Concepts/05 Estimate Fees.php | 4 + ...ees.html => 06 Zero Transaction Fees.html} | 0 ...html => 07 Negative Transaction Fees.html} | 0 .../01 Key Concepts/99 Examples.html | 73 ++++++++- .../02 Constant Model.html | 2 +- .../13 Get Initial Margin Requirements.html | 153 ------------------ .../13 Get Initial Margin Requirements.php | 4 + .../07 Buying Power/99 Examples.html | 93 ++++++++++- .../contingent-orders/backtest-fills.php | 6 + .../contingent-orders/brokerage-support.php | 0 .../contingent-orders/buying-power.php | 1 + .../contingent-orders/cancel-orders.php | 8 + .../contingent-orders/monitor-orders.php | 4 +- .../contingent-orders/update-orders.php | 8 + .../trading-and-orders/check-buying-power.php | 112 +++++++++++++ .../estimate-order-fees.php | 21 +++ 94 files changed, 1071 insertions(+), 243 deletions(-) create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/01 Introduction.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/02 Create Order Requests.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/03 Submit Order Requests.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/04 Estimate Order Fees.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/05 Check Buying Power.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/99 Examples.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/metadata.json rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/01 Introduction.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/02 Properties.php (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/03 Track Orders.php (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/04 Update Orders.php (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/05 Cancel Orders.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/06 Order Response.php (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/99 Examples.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{01 Order Tickets => 02 Order Tickets}/metadata.json (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/01 Introduction.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/02 Get a Single Order Ticket.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/03 Get Order Tickets.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/04 Get a Single Order.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/05 Get Orders.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/06 Get Remaining Order Quantity.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/07 Cancel Orders.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/08 Live Trading Considerations.php (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/99 Examples.html (100%) rename 03 Writing Algorithms/22 Trading and Orders/02 Order Management/{02 Transaction Manager => 03 Transaction Manager}/metadata.json (100%) create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/00.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/01 Introduction.html rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/{02 Bracket Orders.html => 01 Bracket Orders/02 Place Orders.html} (55%) create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/03 Monitor Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/04 Update Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/05 Cancel Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/06 Backtest Fills.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/07 Buying Power.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/08 Brokerage Support.php rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/{ => 01 Bracket Orders}/99 Examples.html (100%) create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/metadata.json delete mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Introduction.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/01 Introduction.html rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/{03 One Cancels Other Orders.html => 02 One Cancels Other Orders/02 Place Orders.html} (81%) create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/03 Monitor Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/04 Update Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/05 Cancel Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/06 Backtest Fills.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/07 Buying Power.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/08 Brokerage Support.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/99 Examples.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/metadata.json create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/01 Introduction.html rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/{04 One Triggers Other Orders.html => 03 One Triggers Other Orders/02 Place Orders.html} (50%) create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/03 Monitor Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/04 Update Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/05 Cancel Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/06 Backtest Fills.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/07 Buying Power.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/08 Brokerage Support.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/99 Examples.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/metadata.json create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/01 Introduction.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/02 Place Orders.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/03 Monitor Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/04 Update Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/05 Cancel Orders.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/06 Backtest Fills.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/07 Buying Power.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/08 Brokerage Support.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/99 Examples.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/metadata.json create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/01 Introduction.html rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/{06 Compose Contingent Orders.html => 05 Custom Contingent Orders/02 Relate Order Requests.html} (69%) rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/{07 Combo Orders.html => 05 Custom Contingent Orders/03 Combo Orders.html} (100%) create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/04 Brokerage Support.php create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/99 Examples.html create mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/metadata.json delete mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 One Updates Other Orders.html delete mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/09 Update Orders.html delete mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/10 Cancel Orders.html delete mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/12 Buying Power.html delete mode 100644 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/metadata.json create mode 100644 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/05 Estimate Fees.php rename 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/{05 Zero Transaction Fees.html => 06 Zero Transaction Fees.html} (100%) rename 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/{06 Negative Transaction Fees.html => 07 Negative Transaction Fees.html} (100%) delete mode 100644 03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.html create mode 100644 03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.php rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/11 Backtest Fills.html => Resources/order-types/contingent-orders/backtest-fills.php (92%) rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/13 Brokerage Support.php => Resources/order-types/contingent-orders/brokerage-support.php (100%) create mode 100644 Resources/order-types/contingent-orders/buying-power.php create mode 100644 Resources/order-types/contingent-orders/cancel-orders.php rename 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/08 Monitor Orders.html => Resources/order-types/contingent-orders/monitor-orders.php (60%) create mode 100644 Resources/order-types/contingent-orders/update-orders.php create mode 100644 Resources/trading-and-orders/check-buying-power.php create mode 100644 Resources/trading-and-orders/estimate-order-fees.php diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/01 Introduction.html new file mode 100644 index 0000000000..8413ebb33f --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/01 Introduction.html @@ -0,0 +1 @@ +

The order factory creates order requests without submitting them. Use order requests to estimate fees and check buying power before you place orders, to submit several orders together, and to build contingent orders. When you submit an order request, you get an order ticket to manage the order.

diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/02 Create Order Requests.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/02 Create Order Requests.html new file mode 100644 index 0000000000..7e7b8303d9 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/02 Create Order Requests.html @@ -0,0 +1,79 @@ +

To create an order request, call one of the methods of the OrderFactoryorder_factory member. Each method returns a SubmitOrderRequest object.

+ +
+
var request = OrderFactory.LimitOrder(_symbol, 100, limitPrice, tag: "Entry");
+
request = self.order_factory.limit_order(self._symbol, 100, limit_price, tag="Entry")
+
+ +

The order factory has a method for each order type. The following table shows the required arguments of each method:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodOrder Type
MarketOrder(symbol, quantity)market_order(symbol, quantity)Market
LimitOrder(symbol, quantity, limitPrice)limit_order(symbol, quantity, limit_price)Limit
LimitIfTouchedOrder(symbol, quantity, triggerPrice, limitPrice)limit_if_touched_order(symbol, quantity, trigger_price, limit_price)Limit if touched
StopMarketOrder(symbol, quantity, stopPrice)stop_market_order(symbol, quantity, stop_price)Stop market
StopLimitOrder(symbol, quantity, stopPrice, limitPrice)stop_limit_order(symbol, quantity, stop_price, limit_price)Stop limit
TrailingStopOrder(symbol, quantity, trailingAmount, trailingAsPercentage)trailing_stop_order(symbol, quantity, trailing_amount, trailing_as_percentage)Trailing stop
TrailingStopOrder(symbol, quantity, stopPrice, trailingAmount, trailingAsPercentage)trailing_stop_order(symbol, quantity, stop_price, trailing_amount, trailing_as_percentage)Trailing stop with an initial stop price
MarketOnOpenOrder(symbol, quantity)market_on_open_order(symbol, quantity)Market on open
MarketOnCloseOrder(symbol, quantity)market_on_close_order(symbol, quantity)Market on close
ComboMarketOrder(legs, quantity)combo_market_order(legs, quantity)Combo market
ComboLimitOrder(legs, quantity, limitPrice)combo_limit_order(legs, quantity, limit_price)Combo limit
ComboLegLimitOrder(legs, quantity)combo_leg_limit_order(legs, quantity)Combo leg limit
OptionStrategyOrder(strategy, quantity)option_strategy_order(strategy, quantity)Option strategy
ExerciseOption(optionSymbol, quantity)exercise_option(option_symbol, quantity)Option exercise
+ +

Every method also accepts the optional asynchronous, tag, and orderPropertiesorder_properties arguments.

+ +

The combo and Option strategy methods return a list with one order request for each leg. The order request stores the current time and a copy of the default order properties, unless you pass order properties. If the ticker of the security changed, the order request uses the current Symbol.

diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/03 Submit Order Requests.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/03 Submit Order Requests.html new file mode 100644 index 0000000000..6461ab7405 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/03 Submit Order Requests.html @@ -0,0 +1,24 @@ +

To submit order requests, pass a single request or a list of requests to the Orderorder method. The method returns a list with the order ticket of each order. For a combo order, include all the legs.

+ +
+
var tickets = Order(new List<SubmitOrderRequest>
+{
+    OrderFactory.MarketOrder(_spy, 10),
+    OrderFactory.LimitOrder(_aapl, -20, aaplLimitPrice)
+});
+
tickets = self.order([
+    self.order_factory.market_order(self._spy, 10),
+    self.order_factory.limit_order(self._aapl, -20, aapl_limit_price)
+])
+
+ +

LEAN runs the pre-order checks on every request before it submits any of them. If a request fails the checks, LEAN submits none of the orders and the method returns a list with a single invalid order ticket. LEAN checks the buying power of each order after you submit it.

+ +

LEAN applies the usual order adjustments when you submit the request. For example, LEAN converts a market order into a market on open order if the market is closed. LEAN also sets the initial stop price of a trailing stop order from the market price at that time.

+ +

You can submit each order request once. After you submit a request, its OrderIdorder_id property holds the order Id. To get the order ticket of a request, get it from the transaction manager.

+ +
+
var ticket = Transactions.GetOrderTicket(request.OrderId);
+
ticket = self.transactions.get_order_ticket(request.order_id)
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/04 Estimate Order Fees.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/04 Estimate Order Fees.php new file mode 100644 index 0000000000..98669b6640 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/04 Estimate Order Fees.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/05 Check Buying Power.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/05 Check Buying Power.php new file mode 100644 index 0000000000..4f06fa6612 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/05 Check Buying Power.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/99 Examples.html new file mode 100644 index 0000000000..0a3f2a0785 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/99 Examples.html @@ -0,0 +1,62 @@ +

The following examples demonstrate common practices for using the order factory.

+ +

Example 1: Skip Expensive Rebalance Orders

+

The following algorithm rebalances an equal-weight portfolio every month. For each security, it creates a market order request for the difference between the target and current quantities and estimates the fee. The algorithm drops the orders whose fee exceeds 0.1% of the order value and submits the rest together, with the sell orders first.

+
+
public class OrderFactoryExampleAlgorithm : QCAlgorithm
+{
+    private List<Symbol> _symbols;
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 1, 1);
+        SetEndDate(2024, 12, 31);
+        SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);
+        _symbols = new[] { "SPY", "TLT", "GLD" }.Select(ticker => AddEquity(ticker, Resolution.Daily).Symbol).ToList();
+        Schedule.On(DateRules.MonthStart(_symbols[0]), TimeRules.AfterMarketOpen(_symbols[0], 30), Rebalance);
+    }
+
+    private void Rebalance()
+    {
+        var requests = new List<SubmitOrderRequest>();
+        foreach (var symbol in _symbols)
+        {
+            var quantity = CalculateOrderQuantity(symbol, 1m / _symbols.Count);
+            if (quantity == 0) continue;
+            var security = Securities[symbol];
+            var request = OrderFactory.MarketOrder(symbol, quantity);
+            // Estimate the fee without submitting the order.
+            var fee = security.FeeModel.GetOrderFee(new OrderFeeParameters(security, QuantConnect.Orders.Order.CreateOrder(request))).Value.Amount;
+            if (fee <= 0.001m * Math.Abs(quantity) * security.Price)
+            {
+                requests.Add(request);
+            }
+        }
+        // Place the sell orders first to free up buying power.
+        Order(requests.OrderBy(request => request.Quantity));
+    }
+}
+
class OrderFactoryExampleAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 1, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
+        self._symbols = [self.add_equity(ticker, Resolution.DAILY).symbol for ticker in ["SPY", "TLT", "GLD"]]
+        self.schedule.on(self.date_rules.month_start(self._symbols[0]), self.time_rules.after_market_open(self._symbols[0], 30), self._rebalance)
+
+    def _rebalance(self) -> None:
+        requests = []
+        for symbol in self._symbols:
+            quantity = self.calculate_order_quantity(symbol, 1 / len(self._symbols))
+            if not quantity:
+                continue
+            security = self.securities[symbol]
+            request = self.order_factory.market_order(symbol, quantity)
+            # Estimate the fee without submitting the order.
+            fee = security.fee_model.get_order_fee(OrderFeeParameters(security, Order.create_order(request))).value.amount
+            if fee <= 0.001 * abs(quantity) * security.price:
+                requests.append(request)
+        # Place the sell orders first to free up buying power.
+        self.order(sorted(requests, key=lambda request: request.quantity))
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/metadata.json b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/metadata.json new file mode 100644 index 0000000000..e241ac6f30 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Factory/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "The order factory creates order requests without submitting them, so you can estimate their fees, submit them together, or build contingent orders.", + "keywords": "order factory, order requests, SubmitOrderRequest, submit orders together, estimate order fees, contingent orders", + "og:description": "The order factory creates order requests without submitting them, so you can estimate their fees, submit them together, or build contingent orders.", + "og:title": "Order Factory - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Order Factory - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-management/order-factory.png" + } +} diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/01 Introduction.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/01 Introduction.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/01 Introduction.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/02 Properties.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/02 Properties.php similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/02 Properties.php rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/02 Properties.php diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/03 Track Orders.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/03 Track Orders.php similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/03 Track Orders.php rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/03 Track Orders.php diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/04 Update Orders.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/04 Update Orders.php similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/04 Update Orders.php rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/04 Update Orders.php diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/05 Cancel Orders.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/05 Cancel Orders.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/05 Cancel Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/05 Cancel Orders.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/06 Order Response.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/06 Order Response.php similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/06 Order Response.php rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/06 Order Response.php diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/99 Examples.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/99 Examples.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/99 Examples.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/metadata.json b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/metadata.json similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/01 Order Tickets/metadata.json rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Order Tickets/metadata.json diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/01 Introduction.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/01 Introduction.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/01 Introduction.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/02 Get a Single Order Ticket.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/02 Get a Single Order Ticket.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/02 Get a Single Order Ticket.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/02 Get a Single Order Ticket.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/03 Get Order Tickets.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/03 Get Order Tickets.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/03 Get Order Tickets.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/03 Get Order Tickets.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/04 Get a Single Order.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/04 Get a Single Order.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/04 Get a Single Order.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/04 Get a Single Order.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/05 Get Orders.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/05 Get Orders.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/05 Get Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/05 Get Orders.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/06 Get Remaining Order Quantity.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/06 Get Remaining Order Quantity.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/06 Get Remaining Order Quantity.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/06 Get Remaining Order Quantity.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/07 Cancel Orders.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/07 Cancel Orders.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/07 Cancel Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/07 Cancel Orders.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/08 Live Trading Considerations.php b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/08 Live Trading Considerations.php similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/08 Live Trading Considerations.php rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/08 Live Trading Considerations.php diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/99 Examples.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/99 Examples.html rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/99 Examples.html diff --git a/03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/metadata.json b/03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/metadata.json similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/02 Order Management/02 Transaction Manager/metadata.json rename to 03 Writing Algorithms/22 Trading and Orders/02 Order Management/03 Transaction Manager/metadata.json diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/00.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/00.html new file mode 100644 index 0000000000..3254057c18 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/00.html @@ -0,0 +1,72 @@ +
+
+
+

Contingent orders are sets of orders with related lifecycles. When an order in the set fills or you cancel it, the brokerage triggers, cancels, or resizes the other orders in the set. The brokerage manages the whole set, so a fill and a cancel request can't race each other and leave a position without its exit orders. LEAN supports the following contingency types:

+ +
    +
  • One Cancels Other (OCO) orders cancel the rest of the set when one of them fills, even partially.
  • +
  • One Triggers Other (OTO) orders hold the child orders until the parent order completely fills.
  • +
  • One Updates Other (OUO) orders reduce the remaining quantity of the rest of the set when one of them partially fills.
  • +
+ +

You can combine these types. For example, a bracket order is an entry order that triggers a take-profit order and a stop-loss order, which cancel each other. The members of a set can be combo orders.

+
+ + +
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/01 Introduction.html new file mode 100644 index 0000000000..57a1dc9fbd --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/01 Introduction.html @@ -0,0 +1 @@ +

A bracket order is an entry order that triggers a take-profit order and a stop-loss order when it completely fills. The take-profit order and the stop-loss order are one cancels other orders, so when one of them fills, LEAN cancels the other one. Bracket orders set an upper and a lower bound on the exit price of a trade.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 Bracket Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/02 Place Orders.html similarity index 55% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 Bracket Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/02 Place Orders.html index bffe24ba97..46db9a122e 100644 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 Bracket Orders.html +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/02 Place Orders.html @@ -14,7 +14,7 @@
self.bracket_order(self._symbol, 100, take_profit_price, stop_loss_price, limit_price=limit_price, tag=tag, order_properties=order_properties)
-

To bracket other entry order types, create the entry order request with the order factory. Call its Bracketbracket method and pass the request to the Orderorder method. The Bracketbracket method accepts a stopLossLimitPricestop_loss_limit_price argument to use a stop limit order for the stop loss. To reduce the stop-loss quantity when the take-profit order partially fills, pass ContingencyType.OneUpdatesOtherContingencyType.ONE_UPDATES_OTHER as the contingencyTypecontingency_type argument.

+

To bracket other entry order types, create the entry order request with the order factory. Call its Bracketbracket method and pass the request to the Orderorder method. The Bracketbracket method accepts a stopLossLimitPricestop_loss_limit_price argument to use a stop limit order for the stop loss. To reduce the stop-loss quantity when the take-profit order partially fills, pass ContingencyType.OneUpdatesOtherContingencyType.ONE_UPDATES_OTHER as the contingencyTypecontingency_type argument.

var entry = OrderFactory.StopMarketOrder(_symbol, 100, price * 1.01m)
@@ -24,3 +24,9 @@
     price * 1.03, price * 0.99, stop_loss_limit_price=price * 0.985, contingency_type=ContingencyType.ONE_UPDATES_OTHER)
 tickets = self.order(entry)
+ +

The following images show the two outcomes of a bracket order. In the first image, the entry order fills and triggers the exit orders. Then the price rises to the take-profit price, so the take-profit order fills and LEAN cancels the stop-loss order:

+A bracket order has a buy limit entry at 47,000, a take-profit sell limit at 60,000, and a stop-loss sell stop at 40,000. The price falls to 47,000, the entry fills, and the exit orders start working. The price rises to 60,000, the take-profit order fills, and LEAN cancels the stop-loss order. + +

In the second image, the entry order fills and then the price falls to the stop price. The stop-loss order fills and LEAN cancels the take-profit order:

+A bracket order has a buy limit entry at 47,000, a take-profit sell limit at 60,000, and a stop-loss sell stop at 40,000. The price falls to 47,000, the entry fills, and the exit orders start working. The price falls to 40,000, the stop-loss order fills, and LEAN cancels the take-profit order. diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/03 Monitor Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/03 Monitor Orders.php new file mode 100644 index 0000000000..d44704cece --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/03 Monitor Orders.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/04 Update Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/04 Update Orders.php new file mode 100644 index 0000000000..927d26e81c --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/04 Update Orders.php @@ -0,0 +1,14 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/05 Cancel Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/05 Cancel Orders.php new file mode 100644 index 0000000000..97428a1520 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/05 Cancel Orders.php @@ -0,0 +1,14 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/06 Backtest Fills.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/06 Backtest Fills.php new file mode 100644 index 0000000000..e35f39465d --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/06 Backtest Fills.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/07 Buying Power.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/07 Buying Power.php new file mode 100644 index 0000000000..6e04424a23 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/07 Buying Power.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/08 Brokerage Support.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/08 Brokerage Support.php new file mode 100644 index 0000000000..34ddf010bb --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/08 Brokerage Support.php @@ -0,0 +1,3 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/99 Examples.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/99 Examples.html rename to 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/99 Examples.html diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/metadata.json b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/metadata.json new file mode 100644 index 0000000000..091a80a19d --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Bracket Orders/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "Bracket orders are entry orders that trigger a take-profit order and a stop-loss order, which cancel each other.", + "keywords": "bracket orders, otoco orders, take profit, stop loss, entry orders, BracketOrder, bracket_order", + "og:description": "Bracket orders are entry orders that trigger a take-profit order and a stop-loss order, which cancel each other.", + "og:title": "Bracket Orders - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Bracket Orders - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-types/contingent-orders/bracket-orders.png" + } +} diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Introduction.html deleted file mode 100644 index 511e9c7b13..0000000000 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/01 Introduction.html +++ /dev/null @@ -1,9 +0,0 @@ -

Contingent orders are sets of orders with related lifecycles. When an order in the set fills or you cancel it, the brokerage triggers, cancels, or resizes the other orders in the set. The brokerage manages the whole set, so a fill and a cancel request can't race each other and leave a position without its exit orders. LEAN supports the following contingency types:

- - - -

You can compose these types. For example, a bracket order is an entry order that triggers a take-profit order and a stop-loss order, which cancel each other. The members of a set can be combo orders.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/01 Introduction.html new file mode 100644 index 0000000000..9983df377a --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/01 Introduction.html @@ -0,0 +1 @@ +

One cancels other (OCO) orders are sets of orders that work at the same time. When one order in the set fills, even partially, LEAN cancels the rest of the set. For example, to exit a position, place a take-profit order and a stop-loss order as OCO orders.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Cancels Other Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/02 Place Orders.html similarity index 81% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Cancels Other Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/02 Place Orders.html index c42ac97901..0db16620cb 100644 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Cancels Other Orders.html +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/02 Place Orders.html @@ -1,4 +1,4 @@ -

To place a set of OCO orders, create an order request for each order with the order factory. Pass a list of the requests to the OneCancelsOtherOrderone_cancels_other_order method. All the orders start working right away. When one of them fills, even partially, LEAN cancels the rest of the set. The method returns a list with the order ticket of each order.

+

To place a set of OCO orders, create an order request for each order with the order factory. Pass a list of the requests to the OneCancelsOtherOrderone_cancels_other_order method. All the orders start working right away. When one of them fills, even partially, LEAN cancels the rest of the set. The method returns a list with the order ticket of each order.

// Exit an existing long position at the first price level the market reaches.
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/03 Monitor Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/03 Monitor Orders.php
new file mode 100644
index 0000000000..0b7e8a3808
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/03 Monitor Orders.php	
@@ -0,0 +1,4 @@
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/04 Update Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/04 Update Orders.php
new file mode 100644
index 0000000000..9f7a49677c
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/04 Update Orders.php	
@@ -0,0 +1,14 @@
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/05 Cancel Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/05 Cancel Orders.php
new file mode 100644
index 0000000000..50cfea7b38
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/05 Cancel Orders.php	
@@ -0,0 +1,14 @@
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/06 Backtest Fills.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/06 Backtest Fills.php
new file mode 100644
index 0000000000..e762891500
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/06 Backtest Fills.php	
@@ -0,0 +1,4 @@
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/07 Buying Power.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/07 Buying Power.php
new file mode 100644
index 0000000000..caf355b2a5
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/07 Buying Power.php	
@@ -0,0 +1,4 @@
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/08 Brokerage Support.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/08 Brokerage Support.php
new file mode 100644
index 0000000000..34ddf010bb
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/08 Brokerage Support.php	
@@ -0,0 +1,3 @@
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/99 Examples.html
new file mode 100644
index 0000000000..31f0e9b664
--- /dev/null
+++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/99 Examples.html	
@@ -0,0 +1,48 @@
+

The following examples demonstrate common practices for using one cancels other orders.

+ +

Example 1: Exit Each Trade at a Price Range

+

The following algorithm buys SPY each day at 10 AM Eastern Time when it has no position. After the market order fills, the algorithm places OCO exit orders. The take-profit order is 1% above the fill price and the stop-loss order is 1% below it. The first exit order that fills closes the position and cancels the other one.

+
+
public class OneCancelsOtherExampleAlgorithm : QCAlgorithm
+{
+    private Symbol _spy;
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 1, 1);
+        SetEndDate(2024, 3, 31);
+        _spy = AddEquity("SPY", Resolution.Minute).Symbol;
+        Schedule.On(DateRules.EveryDay(_spy), TimeRules.At(10, 0), Enter);
+    }
+
+    private void Enter()
+    {
+        if (Portfolio.Invested || Transactions.GetOpenOrders(_spy).Count > 0)
+        {
+            return;
+        }
+        var fillPrice = MarketOrder(_spy, 100).AverageFillPrice;
+        OneCancelsOtherOrder(new List<SubmitOrderRequest>
+        {
+            OrderFactory.LimitOrder(_spy, -100, Math.Round(fillPrice * 1.01m, 2), tag: "Take profit"),
+            OrderFactory.StopMarketOrder(_spy, -100, Math.Round(fillPrice * 0.99m, 2), tag: "Stop loss")
+        });
+    }
+}
+
class OneCancelsOtherExampleAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 1, 1)
+        self.set_end_date(2024, 3, 31)
+        self._spy = self.add_equity("SPY", Resolution.MINUTE).symbol
+        self.schedule.on(self.date_rules.every_day(self._spy), self.time_rules.at(10, 0), self._enter)
+
+    def _enter(self) -> None:
+        if self.portfolio.invested or self.transactions.get_open_orders(self._spy):
+            return
+        fill_price = self.market_order(self._spy, 100).average_fill_price
+        self.one_cancels_other_order([
+            self.order_factory.limit_order(self._spy, -100, round(fill_price * 1.01, 2), tag="Take profit"),
+            self.order_factory.stop_market_order(self._spy, -100, round(fill_price * 0.99, 2), tag="Stop loss")
+        ])
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/metadata.json b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/metadata.json new file mode 100644 index 0000000000..4f5b7bdc67 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/02 One Cancels Other Orders/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "One cancels other (OCO) orders are sets of orders where the first fill of an order cancels the rest of the set.", + "keywords": "one cancels other orders, oco orders, oca orders, take profit, stop loss, OneCancelsOtherOrder, one_cancels_other_order", + "og:description": "One cancels other (OCO) orders are sets of orders where the first fill of an order cancels the rest of the set.", + "og:title": "One Cancels Other Orders - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "One Cancels Other Orders - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-types/contingent-orders/one-cancels-other-orders.png" + } +} diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/01 Introduction.html new file mode 100644 index 0000000000..ac08daa867 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/01 Introduction.html @@ -0,0 +1 @@ +

One triggers other (OTO) orders are sets with a parent order and child orders. The brokerage holds the child orders until the parent order completely fills. For example, to exit a position only after you enter it, place the exit order as a child of the entry order.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Triggers Other Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/02 Place Orders.html similarity index 50% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Triggers Other Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/02 Place Orders.html index f6b728f45a..9b225a99c9 100644 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Triggers Other Orders.html +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/02 Place Orders.html @@ -1,4 +1,4 @@ -

To place a set of OTO orders, create the parent and child order requests with the order factory and pass them to the OneTriggersOtherOrderone_triggers_other_order method. The brokerage holds the child orders until the parent order completely fills. If the parent order is canceled or invalid, LEAN cancels the child orders, even if the parent partially filled. The method returns a list with the order ticket of each order, starting with the parent.

+

To place a set of OTO orders, create the parent and child order requests with the order factory and pass them to the OneTriggersOtherOrderone_triggers_other_order method. The brokerage holds the child orders until the parent order completely fills. If the parent order is canceled or invalid, LEAN cancels the child orders, even if the parent partially filled. The method returns a list with the order ticket of each order, starting with the parent.

// Buy IBM and BAC after the SPY entry fills.
@@ -16,7 +16,7 @@
 ])
-

The child orders are independent of each other and can be for different securities. To relate the child orders, pass them through the OrderFactory.OneCancelsOtherorder_factory.one_cancels_other or OrderFactory.OneUpdatesOtherorder_factory.one_updates_other method first. A child order can trigger other orders in turn. To create a chain, call the Triggerstriggers method on the child order request.

+

The child orders are independent of each other and can be for different securities. To relate the child orders, pass them through the OrderFactory.OneCancelsOtherorder_factory.one_cancels_other or OrderFactory.OneUpdatesOtherorder_factory.one_updates_other method first, as described in Custom Contingent Orders. A child order can trigger other orders in turn. To create a chain, call the Triggerstriggers method on the child order request.

// The IBM order triggers the BAC order once it fills.
@@ -26,3 +26,9 @@
 child = self.order_factory.market_order(self._ibm, 10).triggers(self.order_factory.market_order(self._bac, 20))
 tickets = self.one_triggers_other_order(parent, [child])
+ +

The following images show the two outcomes of an OTO set. In the first image, the parent order fills and triggers the child order, which fills later:

+An OTO set has a parent buy limit order at 45,000 and a child sell limit order at 58,000. The brokerage holds the child order until the price falls to 45,000 and the parent fills. The price then rises to 58,000 and the child order fills. + +

In the second image, you cancel the parent order before it fills, so LEAN cancels the child order:

+An OTO set has a parent buy limit order at 45,000 and a child sell limit order at 58,000. The price stays above 45,000, you cancel the parent order, and LEAN cancels the held child order. diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/03 Monitor Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/03 Monitor Orders.php new file mode 100644 index 0000000000..2d281f03af --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/03 Monitor Orders.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/04 Update Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/04 Update Orders.php new file mode 100644 index 0000000000..1ede22ca9e --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/04 Update Orders.php @@ -0,0 +1,14 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/05 Cancel Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/05 Cancel Orders.php new file mode 100644 index 0000000000..26e907ee87 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/05 Cancel Orders.php @@ -0,0 +1,14 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/06 Backtest Fills.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/06 Backtest Fills.php new file mode 100644 index 0000000000..ff3b4f626d --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/06 Backtest Fills.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/07 Buying Power.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/07 Buying Power.php new file mode 100644 index 0000000000..7a651e589d --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/07 Buying Power.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/08 Brokerage Support.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/08 Brokerage Support.php new file mode 100644 index 0000000000..34ddf010bb --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/08 Brokerage Support.php @@ -0,0 +1,3 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/99 Examples.html new file mode 100644 index 0000000000..5531652dc3 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/99 Examples.html @@ -0,0 +1,45 @@ +

The following examples demonstrate common practices for using one triggers other orders.

+ +

Example 1: Trail the Exit After a Limit Entry

+

The following algorithm places a limit order to buy SPY 1% below the close price when it has no position. The limit order triggers a trailing stop order that sells the position. The trailing stop order starts to trail when the entry fills, so its initial stop price is 3% below the price at that time.

+
+
public class OneTriggersOtherExampleAlgorithm : QCAlgorithm
+{
+    private Symbol _spy;
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 1, 1);
+        SetEndDate(2024, 12, 31);
+        _spy = AddEquity("SPY", Resolution.Daily).Symbol;
+    }
+
+    public override void OnData(Slice slice)
+    {
+        if (Portfolio.Invested || Transactions.GetOpenOrders(_spy).Count > 0 || !slice.Bars.TryGetValue(_spy, out var bar))
+        {
+            return;
+        }
+        var entry = OrderFactory.LimitOrder(_spy, 100, Math.Round(bar.Close * 0.99m, 2));
+        OneTriggersOtherOrder(entry, new List<SubmitOrderRequest>
+        {
+            OrderFactory.TrailingStopOrder(_spy, -100, 0.03m, true)
+        });
+    }
+}
+
class OneTriggersOtherExampleAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 1, 1)
+        self.set_end_date(2024, 12, 31)
+        self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
+
+    def on_data(self, slice: Slice) -> None:
+        bar = slice.bars.get(self._spy)
+        if self.portfolio.invested or self.transactions.get_open_orders(self._spy) or not bar:
+            return
+        entry = self.order_factory.limit_order(self._spy, 100, round(bar.close * 0.99, 2))
+        self.one_triggers_other_order(entry, [
+            self.order_factory.trailing_stop_order(self._spy, -100, 0.03, True)
+        ])
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/metadata.json b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/metadata.json new file mode 100644 index 0000000000..66a16b65d7 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/03 One Triggers Other Orders/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "One triggers other (OTO) orders are sets where the brokerage holds the child orders until the parent order completely fills.", + "keywords": "one triggers other orders, oto orders, parent order, child orders, OneTriggersOtherOrder, one_triggers_other_order", + "og:description": "One triggers other (OTO) orders are sets where the brokerage holds the child orders until the parent order completely fills.", + "og:title": "One Triggers Other Orders - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "One Triggers Other Orders - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-types/contingent-orders/one-triggers-other-orders.png" + } +} diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/01 Introduction.html new file mode 100644 index 0000000000..89fe9811f3 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/01 Introduction.html @@ -0,0 +1 @@ +

One updates other (OUO) orders are sets of orders that work at the same time. When one order in the set partially fills, LEAN reduces the remaining quantity of the rest of the set by the same proportion. When one order completely fills, LEAN cancels the rest of the set. For example, to exit a position in parts without selling more than you hold, place the exit orders as OUO orders.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/02 Place Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/02 Place Orders.html new file mode 100644 index 0000000000..962b112f71 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/02 Place Orders.html @@ -0,0 +1,21 @@ +

To place a set of OUO orders, create an order request for each order with the order factory. Pass a list of the requests to the OneUpdatesOtherOrderone_updates_other_order method. All the orders start working right away. When one of them partially fills, LEAN reduces the remaining quantity of the rest of the set by the same proportion. For example, if a take-profit order for -100 shares fills -40 shares, LEAN reduces the stop-loss order from -100 shares to -60 shares. When one of the orders completely fills, LEAN cancels the rest of the set. The method returns a list with the order ticket of each order.

+ +
+
var tickets = OneUpdatesOtherOrder(new List<SubmitOrderRequest>
+{
+    OrderFactory.LimitOrder(_symbol, -100, price * 1.02m, tag: "Take profit"),
+    OrderFactory.StopMarketOrder(_symbol, -100, price * 0.99m, tag: "Stop loss")
+});
+
tickets = self.one_updates_other_order([
+    self.order_factory.limit_order(self._symbol, -100, price * 1.02, tag="Take profit"),
+    self.order_factory.stop_market_order(self._symbol, -100, price * 0.99, tag="Stop loss")
+])
+
+ +

LEAN rounds the new quantities to the lot size of the security. If a new quantity rounds to zero, LEAN cancels the order.

+ +

The following images show two outcomes of an OUO set that exits a long position of 100 shares. In both images, the take-profit order fills 40 shares, so LEAN reduces the stop-loss order to 60 shares. In the first image, the price falls to the stop price, so the stop-loss order fills 60 shares and LEAN cancels the take-profit order:

+An OUO set has a take-profit order to sell 100 shares at 60,000 and a stop-loss order to sell 100 shares at 40,000. The take-profit order fills 40 shares and LEAN reduces the stop-loss order to 60 shares. The price falls to 40,000, the stop-loss order fills 60 shares, and LEAN cancels the take-profit order. + +

In the second image, the price returns to the take-profit price. The take-profit order fills the other 60 shares and LEAN cancels the stop-loss order:

+An OUO set has a take-profit order to sell 100 shares at 60,000 and a stop-loss order to sell 100 shares at 40,000. The take-profit order fills 40 shares and LEAN reduces the stop-loss order to 60 shares. The price returns to 60,000, the take-profit order fills the other 60 shares, and LEAN cancels the stop-loss order. diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/03 Monitor Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/03 Monitor Orders.php new file mode 100644 index 0000000000..0b7e8a3808 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/03 Monitor Orders.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/04 Update Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/04 Update Orders.php new file mode 100644 index 0000000000..9f7a49677c --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/04 Update Orders.php @@ -0,0 +1,14 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/05 Cancel Orders.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/05 Cancel Orders.php new file mode 100644 index 0000000000..50cfea7b38 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/05 Cancel Orders.php @@ -0,0 +1,14 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/06 Backtest Fills.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/06 Backtest Fills.php new file mode 100644 index 0000000000..e762891500 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/06 Backtest Fills.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/07 Buying Power.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/07 Buying Power.php new file mode 100644 index 0000000000..caf355b2a5 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/07 Buying Power.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/08 Brokerage Support.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/08 Brokerage Support.php new file mode 100644 index 0000000000..34ddf010bb --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/08 Brokerage Support.php @@ -0,0 +1,3 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/99 Examples.html new file mode 100644 index 0000000000..fdf5608c88 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/99 Examples.html @@ -0,0 +1,48 @@ +

The following examples demonstrate common practices for using one updates other orders.

+ +

Example 1: Exit Illiquid Positions in Parts

+

The following algorithm buys IWM each day at 10 AM Eastern Time when it has no position. After the market order fills, the algorithm places a take-profit order and a stop-loss order as OUO orders. If the take-profit order partially fills, LEAN reduces the stop-loss quantity by the same proportion, so the exit orders never sell more than the position.

+
+
public class OneUpdatesOtherExampleAlgorithm : QCAlgorithm
+{
+    private Symbol _iwm;
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 1, 1);
+        SetEndDate(2024, 3, 31);
+        _iwm = AddEquity("IWM", Resolution.Minute).Symbol;
+        Schedule.On(DateRules.EveryDay(_iwm), TimeRules.At(10, 0), Enter);
+    }
+
+    private void Enter()
+    {
+        if (Portfolio.Invested || Transactions.GetOpenOrders(_iwm).Count > 0)
+        {
+            return;
+        }
+        var fillPrice = MarketOrder(_iwm, 500).AverageFillPrice;
+        OneUpdatesOtherOrder(new List<SubmitOrderRequest>
+        {
+            OrderFactory.LimitOrder(_iwm, -500, Math.Round(fillPrice * 1.01m, 2), tag: "Take profit"),
+            OrderFactory.StopMarketOrder(_iwm, -500, Math.Round(fillPrice * 0.99m, 2), tag: "Stop loss")
+        });
+    }
+}
+
class OneUpdatesOtherExampleAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 1, 1)
+        self.set_end_date(2024, 3, 31)
+        self._iwm = self.add_equity("IWM", Resolution.MINUTE).symbol
+        self.schedule.on(self.date_rules.every_day(self._iwm), self.time_rules.at(10, 0), self._enter)
+
+    def _enter(self) -> None:
+        if self.portfolio.invested or self.transactions.get_open_orders(self._iwm):
+            return
+        fill_price = self.market_order(self._iwm, 500).average_fill_price
+        self.one_updates_other_order([
+            self.order_factory.limit_order(self._iwm, -500, round(fill_price * 1.01, 2), tag="Take profit"),
+            self.order_factory.stop_market_order(self._iwm, -500, round(fill_price * 0.99, 2), tag="Stop loss")
+        ])
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/metadata.json b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/metadata.json new file mode 100644 index 0000000000..947c3399ea --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/04 One Updates Other Orders/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "One updates other (OUO) orders are sets of orders where a partial fill of an order reduces the quantity of the rest of the set.", + "keywords": "one updates other orders, ouo orders, partial fills, take profit, stop loss, OneUpdatesOtherOrder, one_updates_other_order", + "og:description": "One updates other (OUO) orders are sets of orders where a partial fill of an order reduces the quantity of the rest of the set.", + "og:title": "One Updates Other Orders - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "One Updates Other Orders - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-types/contingent-orders/one-updates-other-orders.png" + } +} diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/01 Introduction.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/01 Introduction.html new file mode 100644 index 0000000000..11dd5904f6 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/01 Introduction.html @@ -0,0 +1,4 @@ +

To build any combination of contingent orders, create order requests with the order factory, relate them, and then submit any request of the set. For example, you can place two entry orders that cancel each other, where each entry triggers its own bracket of exit orders.

+ +

The following image shows this example when the price breaks out upward. The long entry fills, so LEAN cancels the short entry and its exit orders. The take-profit order of the long entry fills later and LEAN cancels its stop-loss order:

+A long entry buy stop order at 55,000 and a short entry sell stop order at 45,000 cancel each other. Each entry has its own take-profit and stop-loss orders. The price rises to 55,000, the long entry fills, and LEAN cancels the short entry and its exits. The price rises to 65,000, the take-profit order fills, and LEAN cancels the stop-loss order at 45,000. diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/06 Compose Contingent Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/02 Relate Order Requests.html similarity index 69% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/06 Compose Contingent Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/02 Relate Order Requests.html index 43031aa897..1fd846d56d 100644 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/06 Compose Contingent Orders.html +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/02 Relate Order Requests.html @@ -1,4 +1,4 @@ -

The order factory creates SubmitOrderRequest objects without submitting them, so you can relate them before you place them. The order factory has a method for each order type, with the same arguments as the method that places the order. For example, OrderFactory.LimitOrderorder_factory.limit_order accepts the same arguments as LimitOrderlimit_order. To relate the order requests, use the following methods:

+

To relate the order requests, use the following methods:

@@ -27,7 +27,7 @@
-

The Triggerstriggers and Bracketbracket methods return the same request. The OneCancelsOtherone_cancels_other and OneUpdatesOtherone_updates_other methods return the list of requests. You can pass the result of one method to another to build any composition. To place the orders, pass any request of the set to the Orderorder method. The method places every order in the set and returns their order tickets, with each parent before the orders it triggers.

+

The Triggerstriggers and Bracketbracket methods return the same request. The OneCancelsOtherone_cancels_other and OneUpdatesOtherone_updates_other methods return the list of requests. You can pass the result of one method to another to build any composition. To place the orders, pass any request of the set to the Orderorder method. The method places every order in the set and returns their order tickets, with each parent before the orders it triggers. You can add each order request to one OCO or OUO set.

// A limit entry that triggers a take profit and a stop loss that cancel each other.
@@ -43,10 +43,3 @@
 entry.triggers(self.order_factory.one_cancels_other(take_profit, stop_loss))
 tickets = self.order(entry)
- -

You can submit each order request once. After you submit the request, its OrderIdorder_id property holds the order Id. To get the order ticket of a request, get it from the transaction manager.

- -
-
var stopLossTicket = Transactions.GetOrderTicket(stopLoss.OrderId);
-
stop_loss_ticket = self.transactions.get_order_ticket(stop_loss.order_id)
-
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/07 Combo Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/03 Combo Orders.html similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/07 Combo Orders.html rename to 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/03 Combo Orders.html diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/04 Brokerage Support.php b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/04 Brokerage Support.php new file mode 100644 index 0000000000..34ddf010bb --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/04 Brokerage Support.php @@ -0,0 +1,3 @@ + diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/99 Examples.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/99 Examples.html new file mode 100644 index 0000000000..943c29abcc --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/99 Examples.html @@ -0,0 +1,62 @@ +

The following examples demonstrate common practices for using custom contingent orders.

+ +

Example 1: Inside Day Breakout

+

The following algorithm trades a breakout after an inside day, which is a day with a range inside the range of the day before. It places a buy stop order at the high and a sell stop order at the low. The two entry orders cancel each other. Each entry triggers its own bracket order. The take profit is one range away and the stop loss is at the opposite side of the range.

+
+
public class CustomContingentOrdersExampleAlgorithm : QCAlgorithm
+{
+    private Symbol _spy;
+    private RollingWindow<TradeBar> _bars = new(2);
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 1, 1);
+        SetEndDate(2024, 12, 31);
+        _spy = AddEquity("SPY", Resolution.Daily).Symbol;
+    }
+
+    public override void OnData(Slice slice)
+    {
+        if (!slice.Bars.TryGetValue(_spy, out var bar))
+        {
+            return;
+        }
+        _bars.Add(bar);
+        if (!_bars.IsReady || Portfolio.Invested || Transactions.GetOpenOrders(_spy).Count > 0)
+        {
+            return;
+        }
+        var (today, yesterday) = (_bars[0], _bars[1]);
+        if (today.High >= yesterday.High || today.Low <= yesterday.Low)
+        {
+            return;
+        }
+        var range = today.High - today.Low;
+        var breakoutUp = OrderFactory.StopMarketOrder(_spy, 100, today.High).Bracket(today.High + range, today.Low);
+        var breakoutDown = OrderFactory.StopMarketOrder(_spy, -100, today.Low).Bracket(today.Low - range, today.High);
+        Order(OrderFactory.OneCancelsOther(breakoutUp, breakoutDown));
+    }
+}
+
class CustomContingentOrdersExampleAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 1, 1)
+        self.set_end_date(2024, 12, 31)
+        self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
+        self._bars = RollingWindow[TradeBar](2)
+
+    def on_data(self, slice: Slice) -> None:
+        bar = slice.bars.get(self._spy)
+        if not bar:
+            return
+        self._bars.add(bar)
+        if not self._bars.is_ready or self.portfolio.invested or self.transactions.get_open_orders(self._spy):
+            return
+        today, yesterday = self._bars[0], self._bars[1]
+        if today.high >= yesterday.high or today.low <= yesterday.low:
+            return
+        range_ = today.high - today.low
+        breakout_up = self.order_factory.stop_market_order(self._spy, 100, today.high).bracket(today.high + range_, today.low)
+        breakout_down = self.order_factory.stop_market_order(self._spy, -100, today.low).bracket(today.low - range_, today.high)
+        self.order(self.order_factory.one_cancels_other(breakout_up, breakout_down))
+
diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/metadata.json b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/metadata.json new file mode 100644 index 0000000000..3650bac605 --- /dev/null +++ b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 Custom Contingent Orders/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "Custom contingent orders combine order requests into any set of one triggers other, one cancels other, and one updates other orders.", + "keywords": "custom contingent orders, order factory, triggers, bracket, one cancels other, one updates other, combo orders, otoco", + "og:description": "Custom contingent orders combine order requests into any set of one triggers other, one cancels other, and one updates other orders.", + "og:title": "Custom Contingent Orders - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Custom Contingent Orders - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-types/contingent-orders/custom-contingent-orders.png" + } +} diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 One Updates Other Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 One Updates Other Orders.html deleted file mode 100644 index 6e0eaac040..0000000000 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/05 One Updates Other Orders.html +++ /dev/null @@ -1,15 +0,0 @@ -

To place a set of OUO orders, create an order request for each order with the order factory. Pass a list of the requests to the OneUpdatesOtherOrderone_updates_other_order method. All the orders start working right away. When one of them partially fills, LEAN reduces the remaining quantity of the rest of the set by the same proportion. For example, if a take-profit order for -100 shares fills -40 shares, LEAN reduces the stop-loss order from -100 shares to -60 shares. When one of the orders completely fills, LEAN cancels the rest of the set. The method returns a list with the order ticket of each order.

- -
-
var tickets = OneUpdatesOtherOrder(new List<SubmitOrderRequest>
-{
-    OrderFactory.LimitOrder(_symbol, -100, price * 1.02m, tag: "Take profit"),
-    OrderFactory.StopMarketOrder(_symbol, -100, price * 0.99m, tag: "Stop loss")
-});
-
tickets = self.one_updates_other_order([
-    self.order_factory.limit_order(self._symbol, -100, price * 1.02, tag="Take profit"),
-    self.order_factory.stop_market_order(self._symbol, -100, price * 0.99, tag="Stop loss")
-])
-
- -

LEAN rounds the new quantities to the lot size of the security. If a new quantity rounds to zero, LEAN cancels the order.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/09 Update Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/09 Update Orders.html deleted file mode 100644 index e3145bcb40..0000000000 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/09 Update Orders.html +++ /dev/null @@ -1,16 +0,0 @@ -

You can update any open contingent order, including a child order that waits for its parent to fill. To update an order, pass an UpdateOrderFields object to the Updateupdate method on the OrderTicket, or call one of its update methods. An update doesn't release a held order. If you give a held limit order a marketable price, the order fills only after its parent fills.

- -
-
// Move the take profit of a bracket order while the entry waits to fill.
-var response = tickets[1].UpdateLimitPrice(price * 1.03m, "Updated take profit");
-if (response.IsSuccess)
-{
-    Debug("Take profit updated successfully");
-}
-
# Move the take profit of a bracket order while the entry waits to fill.
-response = tickets[1].update_limit_price(price * 1.03, "Updated take profit")
-if response.is_success:
-    self.debug("Take profit updated successfully")
-
- -

Some brokerages don't support updates to contingent orders or to their quantity. To change these orders, cancel the set and place it again.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/10 Cancel Orders.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/10 Cancel Orders.html deleted file mode 100644 index 1f45fc9d97..0000000000 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/10 Cancel Orders.html +++ /dev/null @@ -1,16 +0,0 @@ -

To cancel a contingent order, call the Cancelcancel method on the OrderTicket. LEAN also cancels the orders that depend on it. If you cancel a parent order, LEAN cancels the orders it triggers and the orders they trigger in turn. If you cancel a member of an OCO or OUO set, LEAN cancels the rest of the set. This rule applies to working orders and to orders that wait for their parent to fill. The parent of the set keeps working.

- -
-
// Cancel the entry of a bracket order, which also cancels the take profit and the stop loss.
-var response = tickets[0].Cancel("Cancel bracket");
-if (response.IsSuccess)
-{
-    Debug("Bracket order successfully cancelled");
-}
-
# Cancel the entry of a bracket order, which also cancels the take profit and the stop loss.
-response = tickets[0].cancel("Cancel bracket")
-if response.is_success:
-    self.debug("Bracket order successfully cancelled")
-
- -

The message of the cancel order event of each dependent order names the order that caused the cancellation.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/12 Buying Power.html b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/12 Buying Power.html deleted file mode 100644 index cf9d17957e..0000000000 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/12 Buying Power.html +++ /dev/null @@ -1 +0,0 @@ -

When you place a set of contingent orders, LEAN checks the buying power of the orders that start working right away. LEAN checks the buying power of a child order when its parent fills, so you can place child orders larger than your current buying power. In cash accounts, LEAN reserves the buying power of only the largest order in each set of OCO or OUO orders.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/metadata.json b/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/metadata.json deleted file mode 100644 index 0430ac6846..0000000000 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "metadata", - "values": { - "description": "Contingent orders are sets of orders with related lifecycles, such as bracket, one cancels other, one triggers other, and one updates other orders.", - "keywords": "contingent orders, bracket orders, one cancels other, oco orders, one triggers other, oto orders, one updates other, ouo orders, otoco, take profit, stop loss, order factory", - "og:description": "Contingent orders are sets of orders with related lifecycles, such as bracket, one cancels other, one triggers other, and one updates other orders.", - "og:title": "Contingent Orders - Documentation QuantConnect.com", - "og:type": "website", - "og:site_name": "Contingent Orders - QuantConnect.com", - "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/order-types/contingent-orders.png" - } -} diff --git a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/05 Estimate Fees.php b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/05 Estimate Fees.php new file mode 100644 index 0000000000..1b6749fdea --- /dev/null +++ b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/05 Estimate Fees.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/05 Zero Transaction Fees.html b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/06 Zero Transaction Fees.html similarity index 100% rename from 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/05 Zero Transaction Fees.html rename to 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/06 Zero Transaction Fees.html diff --git a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/06 Negative Transaction Fees.html b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/07 Negative Transaction Fees.html similarity index 100% rename from 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/06 Negative Transaction Fees.html rename to 03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/07 Negative Transaction Fees.html diff --git a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/99 Examples.html b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/99 Examples.html index 5bfb28fb9a..c7d6c9cefe 100644 --- a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/99 Examples.html +++ b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/01 Key Concepts/99 Examples.html @@ -1,5 +1,5 @@

- The following examples demonstrate common practices for implementing a custom fee model. + The following examples demonstrate common practices for implementing custom fee models and estimating fees.

Example 1: Fixed Fees @@ -59,6 +59,77 @@

+

+ Example 2: Buy When Fees Are Low +

+

+ The following algorithm saves $100 each week to buy SPY. Interactive Brokers charges at least $1 for each order, so small orders are expensive. Each week, the algorithm estimates the fee of an order with its savings. It places the order only when the fee is 0.1% of the order value or less. +

+
+
public class EstimateFeesAlgorithm : QCAlgorithm
+{
+    private Symbol _spy;
+    private int _weeks;
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 1, 1);
+        SetEndDate(2024, 12, 31);
+        SetCash(5000);
+        SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);
+        _spy = AddEquity("SPY", Resolution.Daily).Symbol;
+        Schedule.On(DateRules.WeekStart(_spy), TimeRules.AfterMarketOpen(_spy, 30), Buy);
+    }
+
+    private void Buy()
+    {
+        _weeks++;
+        var security = Securities[_spy];
+        if (security.Price == 0)
+        {
+            return;
+        }
+        var quantity = Math.Floor(_weeks * 100m / security.Price);
+        if (quantity == 0)
+        {
+            return;
+        }
+        var request = OrderFactory.MarketOrder(_spy, quantity);
+        // Estimate the fee without submitting the order.
+        var fee = security.FeeModel.GetOrderFee(new OrderFeeParameters(security, QuantConnect.Orders.Order.CreateOrder(request))).Value.Amount;
+        if (fee <= 0.001m * quantity * security.Price)
+        {
+            Order(request);
+            _weeks = 0;
+        }
+    }
+}
+
class EstimateFeesAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 1, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(5000)
+        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
+        self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
+        self._weeks = 0
+        self.schedule.on(self.date_rules.week_start(self._spy), self.time_rules.after_market_open(self._spy, 30), self._buy)
+
+    def _buy(self) -> None:
+        self._weeks += 1
+        security = self.securities[self._spy]
+        if not security.price:
+            return
+        quantity = int(self._weeks * 100 / security.price)
+        if not quantity:
+            return
+        request = self.order_factory.market_order(self._spy, quantity)
+        # Estimate the fee without submitting the order.
+        fee = security.fee_model.get_order_fee(OrderFeeParameters(security, Order.create_order(request))).value.amount
+        if fee <= 0.001 * quantity * security.price:
+            self.order(request)
+            self._weeks = 0
+

Other Examples

diff --git a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/02 Supported Models/02 Constant Model.html b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/02 Supported Models/02 Constant Model.html index 2c84569ee5..e9a6f59092 100644 --- a/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/02 Supported Models/02 Constant Model.html +++ b/03 Writing Algorithms/24 Reality Modeling/04 Transaction Fees/02 Supported Models/02 Constant Model.html @@ -1,4 +1,4 @@ -

The ConstantFeeModel applies the absolute value of a constant fee to each order. It's the default fee model of the DefaultBrokerageModel if you trade Forex, CFD, or Crypto assets. Use this model to set zero transaction fees.

+

The ConstantFeeModel applies the absolute value of a constant fee to each order. It's the default fee model of the DefaultBrokerageModel if you trade Forex, CFD, or Crypto assets. Use this model to set zero transaction fees.

security.SetFeeModel(new ConstantFeeModel(0.05m));
diff --git a/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.html b/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.html deleted file mode 100644 index f9d97bef0f..0000000000 --- a/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.html +++ /dev/null @@ -1,153 +0,0 @@ -

The following sections explain how to check if you have enough margin remaining to cover the initial margin requirements of various order types.

- -

Check Requirements of Regular Orders

-

Follow these steps to check if you have enough margin remaining to cover the initial margin requirements of an order:

- -
    -
  1. Create an InitialMarginParameters object with the security and quantity you want to trade.
  2. -
    -
    public override void OnData(Slice slice)
    -{
    -    var security = Securities["SPY"];
    -    var quantity = 100m;
    -    var parameter = new InitialMarginParameters(security, quantity);
    -
    def on_data(self, slice: Slice) -> None:
    -    security = self.securities["SPY"]
    -    quantity = 100
    -    parameter = InitialMarginParameters(security, quantity)
    -
    - -
  3. Call the GetInitialMarginRequirementget_initial_margin_requirement method of the security's buying power model with the InitialMarginParameters.
  4. -
    -
        var initialMargin = security.BuyingPowerModel.GetInitialMarginRequirement(parameter);
    -
        initial_margin = security.buying_power_model.get_initial_margin_requirement(parameter)
    -
    - -

    The GetInitialMarginRequirementget_initial_margin_requirement method returns an InitialMargin object, which have the following properties:

    -
    - -
  5. Compare the margin you have remaining against the initial margin requirement of the order.
  6. -
    -
        if (Portfolio.MarginRemaining >= initialMargin.Value)
    -    {
    -        MarketOrder(security.Symbol, quantity);
    -    }
    -    else
    -    {
    -        Debug("You don't have sufficient margin for this order.");
    -    }
    -}
    -
        if self.portfolio.margin_remaining >= initial_margin.value:
    -        self.market_order(security.symbol, quantity)
    -    else:
    -        self.debug("You don't have sufficient margin for this order.")
    -
    -
- -

Check Requirements of Option Strategy Orders

-

Follow these steps to check if you have enough margin remaining to cover the initial margin requirements of an Option strategy:

- -
    -
  1. Create an OptionStrategy object with the strategy you want to trade and its buying power model.
  2. -

    For example, create a Bull Put Spread strategy.

    -
    -
    private Symbol _symbol;
    -            
    -public override void Initialize()
    -{
    -    // Subscribe to option data and cache the canonical symbol to obtain the option data
    -    _symbol = AddOption("SPY").Symbol;
    -}
    -
    -public override void OnData(Slice slice)
    -{
    -    // Trade on updated option chain data
    -    if (!slice.OptionChains.TryGetValue(_symbol, out var chain))
    -    {
    -        return;
    -    }
    -
    -    var itmStrike = chain.Max(x => x.Strike);
    -    var otmStrike = chain.Min(x => x.Strike);
    -    var expiry = chain.Min(x => x.Expiry);
    -
    -    var optionStrategy = OptionStrategies.BullPutSpread(_symbol, itmStrike, otmStrike, expiry);
    -
    def initialize(self) -> None:
    -    # Subscribe to option data and cache the canonical symbol to obtain the option data
    -    self._symbol = self.add_option("SPY").symbol
    -    
    -def on_data(self, slice: Slice) > None:
    -    # Trade on updated option chain data
    -    chain = slice.option_chains.get(self._symbol)
    -    if not chain:
    -        return
    -    
    -    itm_strike = max(x.strike for x in chain)
    -    otm_strike = min(x.strike for x in chain)
    -    expiry = min(x.expiry for x in chain)
    -
    -    option_strategy = OptionStrategies.bull_put_spread(self._symbol, itm_strike, otm_strike, expiry)
    -
    - -
  3. Create an OptionStrategyPositionGroupBuyingPowerModel object of the strategy.
  4. -
    -
        var buyingPowerModel = new OptionStrategyPositionGroupBuyingPowerModel(optionStrategy);
    -
        buying_power_model = OptionStrategyPositionGroupBuyingPowerModel(option_strategy)
    -
    - -
  5. Create a list of Position objects from the strategy legs.
  6. -
    -
        var positions = optionStrategy.OptionLegs.Select(leg =>
    -    {
    -        var symbol = QuantConnect.Symbol.CreateOption(_symbol.Underlying, _symbol.ID.Market, _symbol.ID.OptionStyle, leg.Right, leg.Strike, leg.Expiration);
    -        return new Position(symbol, leg.Quantity, 1);
    -    });
    -
        def get_symbol(leg):
    -        return Symbol.create_option(
    -            self._symbol.underlying, self._symbol.id.market, self._symbol.id.option_style, 
    -            leg.right, leg.strike, leg.expiration
    -        )
    -
    -    positions = [Position(get_symbol(leg), leg.quantity, 1) for leg in option_strategy.option_legs]
    -
    - -
  7. Create a PositionGroupInitialMarginParameters objects with the portfolio and the position group.
  8. -
    -
        var positionGroup = new PositionGroup(buyingPowerModel, 1, positions.ToArray());
    -    var parameters = new PositionGroupInitialMarginParameters(Portfolio, positionGroup);
    -
        position_group = PositionGroup(buying_power_model, 1, positions)
    -    parameters = PositionGroupInitialMarginParameters(self.portfolio, position_group)
    -
    - -
  9. Call the GetInitialMarginRequirementget_initial_margin_requirement method of the strategy's buying power model with the PositionGroupInitialMarginParameters.
  10. -
    -
        var initialMargin = buyingPowerModel.GetInitialMarginRequirement(parameters);
    -
        initial_margin = buying_power_model.get_initial_margin_requirement(parameters)
    -
    - -

    The GetInitialMarginRequirementget_initial_margin_requirement method returns an InitialMargin object, which have the following properties:

    -
    - -
  11. Compare the margin you have remaining against the initial margin requirement of the order.
  12. -

    - In this case, the initialMargin.Valueinitial_margin.value is the initial margin requirement for a trade size of 1. - For different trade sizes, multiply the initialMargin.Valueinitial_margin.value by the quantity. -

    -
    -
        var strategyQuantity = 2; 
    -    if (Portfolio.MarginRemaining >= strategyQuantity * initialMargin.Value)
    -    {
    -        Buy(optionStrategy, quantity);
    -    }
    -    else
    -    {
    -        Debug("You don't have sufficient margin for this order.");
    -    }
    -}
    -
        strategy_quantity = 2
    -    if self.portfolio.margin_remaining >= strategy_quantity * initial_margin.value:
    -        self.buy(option_strategy, strategy_quantity)
    -    else:
    -        self.debug("You don't have sufficient margin for this order.")
    -
    -
diff --git a/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.php b/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.php new file mode 100644 index 0000000000..1ced55802b --- /dev/null +++ b/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/13 Get Initial Margin Requirements.php @@ -0,0 +1,4 @@ + diff --git a/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/99 Examples.html b/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/99 Examples.html index 9d55215be3..6f7b620d0c 100644 --- a/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/99 Examples.html +++ b/03 Writing Algorithms/24 Reality Modeling/07 Buying Power/99 Examples.html @@ -1,11 +1,11 @@

- The following examples demonstrate some common practices for implementing a custom buying power model. + The following examples demonstrate some common practices for implementing custom buying power models and checking buying power.

Example 1: Always Sufficient Buying Power

- The following algorithm trades protective call strategy. Sometimes, the brokerage's margin requirement differs from the algorithm's default. To avoid errors on order submission at the algorithm level, we can use the + The following algorithm trades a protective put strategy. Sometimes, the brokerage's margin requirement differs from the algorithm's default. To avoid errors on order submission at the algorithm level, we can use the SecurityPositionGroupModel.Null @@ -30,7 +30,7 @@

SetStartDate(2024, 9, 1); SetEndDate(2024, 12, 31); Settings.SeedInitialPrices = true; - AddSecurityInitializer(security =ggt; + AddSecurityInitializer(security => { // Do not allow buying power for options; only a hedging strategy with 0 margin is allowed. security.SetBuyingPowerModel(new NullBuyingPowerModel()); @@ -173,7 +173,7 @@

public override decimal GetLeverage(Security security) { - return base.GetLeverage(security); + return base.GetLeverage(security); } public override void SetLeverage(Security security, decimal leverage) @@ -304,6 +304,91 @@

+

+ Example 3: Size Option Spreads to Buying Power +

+

+ The following algorithm sells a weekly SPY bull put spread. Before it places the spread, it checks the buying power for quantities from 20 down to 1. It places the largest quantity that the portfolio can afford. +

+
+
public class SizeOptionSpreadAlgorithm : QCAlgorithm
+{
+    private Symbol _spy;
+    private Symbol _option;
+
+    public override void Initialize()
+    {
+        SetStartDate(2024, 9, 1);
+        SetEndDate(2024, 12, 31);
+        SetCash(10000);
+        _spy = AddEquity("SPY", dataNormalizationMode: DataNormalizationMode.Raw).Symbol;
+        var option = AddOption("SPY");
+        option.SetFilter(universe => universe.IncludeWeeklys().PutsOnly().Strikes(-10, 0).Expiration(0, 7));
+        _option = option.Symbol;
+    }
+
+    public override void OnData(Slice slice)
+    {
+        // Sell the shares of an assignment.
+        if (Portfolio[_spy].Invested)
+        {
+            Liquidate(_spy);
+            return;
+        }
+        if (Portfolio.Invested || !slice.OptionChains.TryGetValue(_option, out var chain))
+        {
+            return;
+        }
+        var expiry = chain.Max(x => x.Expiry);
+        var strikes = chain.Where(x => x.Expiry == expiry).Select(x => x.Strike).Distinct().OrderByDescending(x => x).ToList();
+        if (strikes.Count < 6)
+        {
+            return;
+        }
+        var strategy = OptionStrategies.BullPutSpread(_option, strikes[0], strikes[5], expiry);
+        for (var quantity = 20; quantity > 0; quantity--)
+        {
+            var requests = OrderFactory.OptionStrategyOrder(strategy, quantity);
+            var orders = requests.Select(request => QuantConnect.Orders.Order.CreateOrder(request)).ToList();
+            if (Portfolio.HasSufficientBuyingPowerForOrder(orders).IsSufficient)
+            {
+                Order(requests);
+                return;
+            }
+        }
+    }
+}
+
class SizeOptionSpreadAlgorithm(QCAlgorithm):
+
+    def initialize(self) -> None:
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(10000)
+        self._spy = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW).symbol
+        option = self.add_option("SPY")
+        option.set_filter(lambda universe: universe.include_weeklys().puts_only().strikes(-10, 0).expiration(0, 7))
+        self._option = option.symbol
+
+    def on_data(self, slice: Slice) -> None:
+        # Sell the shares of an assignment.
+        if self.portfolio[self._spy].invested:
+            self.liquidate(self._spy)
+            return
+        chain = slice.option_chains.get(self._option)
+        if self.portfolio.invested or not chain:
+            return
+        expiry = max(x.expiry for x in chain)
+        strikes = sorted({x.strike for x in chain if x.expiry == expiry}, reverse=True)
+        if len(strikes) < 6:
+            return
+        strategy = OptionStrategies.bull_put_spread(self._option, strikes[0], strikes[5], expiry)
+        for quantity in range(20, 0, -1):
+            requests = self.order_factory.option_strategy_order(strategy, quantity)
+            orders = [Order.create_order(request) for request in requests]
+            if self.portfolio.has_sufficient_buying_power_for_order(orders).is_sufficient:
+                self.order(requests)
+                return
+

Other Examples

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/11 Backtest Fills.html b/Resources/order-types/contingent-orders/backtest-fills.php similarity index 92% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/11 Backtest Fills.html rename to Resources/order-types/contingent-orders/backtest-fills.php index bfec85afc6..0411b54b50 100644 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/11 Backtest Fills.html +++ b/Resources/order-types/contingent-orders/backtest-fills.php @@ -1,10 +1,16 @@

In backtests, LEAN simulates how the brokerage manages the set with the following rules:

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

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/13 Brokerage Support.php b/Resources/order-types/contingent-orders/brokerage-support.php similarity index 100% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/13 Brokerage Support.php rename to Resources/order-types/contingent-orders/brokerage-support.php diff --git a/Resources/order-types/contingent-orders/buying-power.php b/Resources/order-types/contingent-orders/buying-power.php new file mode 100644 index 0000000000..95e3dcdff0 --- /dev/null +++ b/Resources/order-types/contingent-orders/buying-power.php @@ -0,0 +1 @@ +

When you place a set of contingent orders, LEAN checks the buying power of the orders that start working right away. LEAN checks the buying power of a child order when its parent fills, so you can place child orders larger than your current buying power. In cash accounts, LEAN reserves the buying power of only the largest order in each set of OCO or OUO orders.

diff --git a/Resources/order-types/contingent-orders/cancel-orders.php b/Resources/order-types/contingent-orders/cancel-orders.php new file mode 100644 index 0000000000..f53b5f2d1f --- /dev/null +++ b/Resources/order-types/contingent-orders/cancel-orders.php @@ -0,0 +1,8 @@ +

To cancel an order in the set, call the Cancelcancel method on the OrderTicket. LEAN also cancels the orders that depend on it. If you cancel a parent order, LEAN cancels the orders it triggers and the orders they trigger in turn. If you cancel a member of an OCO or OUO set, LEAN cancels the rest of the set. This rule applies to working orders and to orders that wait for their parent to fill. The parent of the set keeps working.

+ +
+
+
+
+ +

The message of the cancel order event of each dependent order names the order that caused the cancellation.

diff --git a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/08 Monitor Orders.html b/Resources/order-types/contingent-orders/monitor-orders.php similarity index 60% rename from 03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/08 Monitor Orders.html rename to Resources/order-types/contingent-orders/monitor-orders.php index 16d63e2a83..b31082ad09 100644 --- a/03 Writing Algorithms/22 Trading and Orders/03 Order Types/13 Contingent Orders/08 Monitor Orders.html +++ b/Resources/order-types/contingent-orders/monitor-orders.php @@ -1,4 +1,4 @@ -

Each contingent order has its own order ticket, which fills and closes independently. A child order that waits for its parent to fill has the OrderStatus.SubmittedOrderStatus.SUBMITTED status. To check if the brokerage still holds the order, use the IsWaitingForTriggeris_waiting_for_trigger property of the Contingencycontingency on the order ticket.

+

Each order in the set has its own order ticket, which fills and closes independently. To get the relationships of an order, use the Contingencycontingency property of the order ticket. A child order that waits for its parent to fill has the OrderStatus.SubmittedOrderStatus.SUBMITTED status. To check if the brokerage still holds the order, use the IsWaitingForTriggeris_waiting_for_trigger property of the contingency.

foreach (var ticket in tickets)
@@ -15,4 +15,4 @@
 

The Linkslinks property holds a ContingencyLink object for each relationship of the order, which has the following attributes:

-

The GetOpenOrdersRemainingQuantityget_open_orders_remaining_quantity method of the transaction manager excludes the orders that wait for their parent to fill. At most one order of an OCO or OUO set fills, so the method includes only the largest remaining quantity of each set.

+

The GetOpenOrdersRemainingQuantityget_open_orders_remaining_quantity method of the transaction manager excludes the orders that wait for their parent to fill. At most one order of an OCO or OUO set fills, so the method includes only the largest remaining quantity of each set.

diff --git a/Resources/order-types/contingent-orders/update-orders.php b/Resources/order-types/contingent-orders/update-orders.php new file mode 100644 index 0000000000..1d769805b6 --- /dev/null +++ b/Resources/order-types/contingent-orders/update-orders.php @@ -0,0 +1,8 @@ +

You can update any open order in the set, including a child order that waits for its parent to fill. To update an order, pass an UpdateOrderFields object to the Updateupdate method on the OrderTicket, or call one of its update methods. An update doesn't release a held order. If you give a held limit order a marketable price, the order fills only after its parent fills.

+ +
+
+
+
+ +

Some brokerages don't support updates to contingent orders or to their quantity. To change these orders, cancel the set and place it again.

diff --git a/Resources/trading-and-orders/check-buying-power.php b/Resources/trading-and-orders/check-buying-power.php new file mode 100644 index 0000000000..ff3678e99d --- /dev/null +++ b/Resources/trading-and-orders/check-buying-power.php @@ -0,0 +1,112 @@ +order factory"; +$buyingPowerText = isset($linkBuyingPower) && !$linkBuyingPower ? "buying power" : "buying power"; +?> +

The following sections explain how to check if you have enough to cover the initial margin requirements of an order before you place it.

+ +

Check Requirements of Regular Orders

+

To check if you have enough buying power for a regular order, create an order request with the and convert it into an Order object. Then compare the absolute initial margin that the order requires with the buying power of your portfolio in the direction of the order. The initial margin is negative for sell orders and includes the modeled order fees. The buying power in the direction of the order includes the margin that the order frees when it reduces or reverses a position.

+ +
+
var security = Securities[_symbol];
+var request = OrderFactory.MarketOrder(_symbol, 100);
+var order = QuantConnect.Orders.Order.CreateOrder(request);
+var initialMargin = security.BuyingPowerModel.GetInitialMarginRequiredForOrder(
+    new InitialMarginRequiredForOrderParameters(Portfolio.CashBook, security, order)).Value;
+if (Math.Abs(initialMargin) <= Portfolio.GetBuyingPower(_symbol, order.Direction))
+{
+    Order(request);
+}
+
security = self.securities[self._symbol]
+request = self.order_factory.market_order(self._symbol, 100)
+order = Order.create_order(request)
+initial_margin = security.buying_power_model.get_initial_margin_required_for_order(
+    InitialMarginRequiredForOrderParameters(self.portfolio.cash_book, security, order)).value
+if abs(initial_margin) <= self.portfolio.get_buying_power(self._symbol, order.direction):
+    self.order(request)
+
+ +

The HasSufficientBuyingPowerForOrderhas_sufficient_buying_power_for_order method of the security buying power model requires an order ticket, so it only works for orders that you already submitted. When you submit the order, LEAN runs its own buying power check.

+ +

Check Requirements of Option Strategy Orders

+

To check if you have enough buying power for an Option strategy order, follow these steps:

+ +
    +
  1. Create an OptionStrategy object with the strategy you want to trade.
  2. +

    For example, create a Bull Put Spread strategy.

    +
    +
    private Symbol _symbol;
    +
    +public override void Initialize()
    +{
    +    // Subscribe to option data and cache the canonical symbol to obtain the option data
    +    _symbol = AddOption("SPY").Symbol;
    +}
    +
    +public override void OnData(Slice slice)
    +{
    +    // Trade on updated option chain data
    +    if (!slice.OptionChains.TryGetValue(_symbol, out var chain))
    +    {
    +        return;
    +    }
    +
    +    var itmStrike = chain.Max(x => x.Strike);
    +    var otmStrike = chain.Min(x => x.Strike);
    +    var expiry = chain.Min(x => x.Expiry);
    +
    +    var optionStrategy = OptionStrategies.BullPutSpread(_symbol, itmStrike, otmStrike, expiry);
    +
    def initialize(self) -> None:
    +    # Subscribe to option data and cache the canonical symbol to obtain the option data
    +    self._symbol = self.add_option("SPY").symbol
    +
    +def on_data(self, slice: Slice) -> None:
    +    # Trade on updated option chain data
    +    chain = slice.option_chains.get(self._symbol)
    +    if not chain:
    +        return
    +
    +    itm_strike = max(x.strike for x in chain)
    +    otm_strike = min(x.strike for x in chain)
    +    expiry = min(x.expiry for x in chain)
    +
    +    option_strategy = OptionStrategies.bull_put_spread(self._symbol, itm_strike, otm_strike, expiry)
    +
    + +
  3. Create the order requests of the strategy legs with the and convert each request into an Order object.
  4. +
    +
        var requests = OrderFactory.OptionStrategyOrder(optionStrategy, 2);
    +    var orders = requests.Select(request => QuantConnect.Orders.Order.CreateOrder(request)).ToList();
    +
        requests = self.order_factory.option_strategy_order(option_strategy, 2)
    +    orders = [Order.create_order(request) for request in requests]
    +
    + +
  5. Call the HasSufficientBuyingPowerForOrderhas_sufficient_buying_power_for_order method of the portfolio with the list of orders.
  6. +
    +
        var result = Portfolio.HasSufficientBuyingPowerForOrder(orders);
    +
        result = self.portfolio.has_sufficient_buying_power_for_order(orders)
    +
    + +

    The HasSufficientBuyingPowerForOrderhas_sufficient_buying_power_for_order method returns a HasSufficientBuyingPowerForOrderResult object, which has the following properties:

    +
    + +
  7. If the result is sufficient, submit the order requests.
  8. +
    +
        if (result.IsSufficient)
    +    {
    +        Order(requests);
    +    }
    +    else
    +    {
    +        Debug($"You don't have sufficient margin for this order: {result.Reason}");
    +    }
    +}
    +
        if result.is_sufficient:
    +        self.order(requests)
    +    else:
    +        self.debug(f"You don't have sufficient margin for this order: {result.reason}")
    +
    +
+ +

The method combines the orders with your current holdings into position groups, so it accounts for strategy orders that reduce or close a position. If the strategy has a single leg, such as a naked put, follow the steps in the preceding section.

diff --git a/Resources/trading-and-orders/estimate-order-fees.php b/Resources/trading-and-orders/estimate-order-fees.php new file mode 100644 index 0000000000..3979c329e4 --- /dev/null +++ b/Resources/trading-and-orders/estimate-order-fees.php @@ -0,0 +1,21 @@ +order factory"; +$feeModelText = isset($linkFeeModel) && !$linkFeeModel ? "fee model" : "fee model"; +?> +

To estimate the modeled fee of an order before you place it, create an order request with the and convert it into an Order object with the QuantConnect.Orders.Order.CreateOrderOrder.create_order method. Then pass the order and its security to the of the security. The conversion doesn't submit the order.

+ +
+
var security = Securities[_symbol];
+var request = OrderFactory.LimitOrder(_symbol, 100, limitPrice);
+var order = QuantConnect.Orders.Order.CreateOrder(request);
+var fee = security.FeeModel.GetOrderFee(new OrderFeeParameters(security, order)).Value;
+Debug($"Estimated fee: {fee.Amount} {fee.Currency}");
+
security = self.securities[self._symbol]
+request = self.order_factory.limit_order(self._symbol, 100, limit_price)
+order = Order.create_order(request)
+fee = security.fee_model.get_order_fee(OrderFeeParameters(security, order)).value
+self.debug(f"Estimated fee: {fee.amount} {fee.currency}")
+
+ +

The estimate is a modeled fee. The fee model calculates it inside your algorithm with the current order and security values. In live trading, LEAN doesn't request the estimate from the brokerage. The fee that the brokerage charges can differ from the modeled fee, especially if the fee depends on the fill price or the fill quantity. To place the order after the estimate, pass the same request to the Orderorder method.