Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
])</pre>
</div>

<p>The child orders are independent of each other and can be for different securities. To relate the child orders, pass them through the <code class="csharp">OrderFactory.OneCancelsOther</code><code class="python">order_factory.one_cancels_other</code> or <code class="csharp">OrderFactory.OneUpdatesOther</code><code class="python">order_factory.one_updates_other</code> method first, as described in <a href='/docs/v2/writing-algorithms/trading-and-orders/order-types/contingent-orders/custom-contingent-orders'>Custom Contingent Orders</a>. A child order can trigger other orders in turn. To create a chain, call the <code class="csharp">Triggers</code><code class="python">triggers</code> method on the child order request.</p>
<p>The child orders are independent of each other and can be for different securities. To relate the child orders, pass them through the <code class="csharp">OrderFactory.OneCancelsOther</code><code class="python">order_factory.one_cancels_other</code> or <code class="csharp">OrderFactory.OneUpdatesOther</code><code class="python">order_factory.one_updates_other</code> method first, as described in <a href='/docs/v2/writing-algorithms/trading-and-orders/order-types/contingent-orders/custom-contingent-orders'>Custom Contingent Orders</a>. A child order can trigger its own child orders, which are grandchild orders of the parent. To create a chain, call the <code class="csharp">Triggers</code><code class="python">triggers</code> method on the child order request.</p>

<div class="section-example-container">
<pre class="csharp">// The IBM order triggers the BAC order once it fills.
Expand All @@ -27,6 +27,8 @@
tickets = self.one_triggers_other_order(parent, [child])</pre>
</div>

<p>The brokerage holds the grandchild order until the child order completely fills. The method returns the order tickets in the order parent, child, and grandchild, with each parent before the orders it triggers. If you cancel the parent, LEAN cancels the child and the grandchild.</p>

<p>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:</p>
<img class="docs-image" src="https://cdn.quantconnect.com/i/tu/oto-child-filled.webp" alt="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.">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,57 @@ <h4>Example 1: Trail the Exit After a Limit Entry</h4>
self.order_factory.trailing_stop_order(self._spy, -100, 0.03, True)
])</pre>
</div>

<h4>Example 2: Enter, Take Profit, and Re-Enter</h4>
<p>The following algorithm trades SPY in a price range with a chain of three orders. The parent buys SPY 1% below the close price. When the parent fills, its child sells the position 1% above the close price. When the child fills, the grandchild buys SPY again at the entry price. While the algorithm holds the position of the grandchild, it places a new take-profit order.</p>
<div class="section-example-container">
<pre class="csharp">public class OneTriggersOtherChainExampleAlgorithm : 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 (Transactions.GetOpenOrders(_spy).Count &gt; 0 || !slice.Bars.TryGetValue(_spy, out var bar))
{
return;
}
var entryPrice = Math.Round(bar.Close * 0.99m, 2);
var exitPrice = Math.Round(bar.Close * 1.01m, 2);
if (Portfolio[_spy].Invested)
{
LimitOrder(_spy, -Portfolio[_spy].Quantity, exitPrice);
return;
}
// The take profit triggers the re-entry, which is a grandchild of the entry.
var takeProfit = OrderFactory.LimitOrder(_spy, -100, exitPrice).Triggers(OrderFactory.LimitOrder(_spy, 100, entryPrice));
OneTriggersOtherOrder(OrderFactory.LimitOrder(_spy, 100, entryPrice), new List&lt;SubmitOrderRequest&gt; { takeProfit });
}
}</pre>
<pre class="python">class OneTriggersOtherChainExampleAlgorithm(QCAlgorithm):

def initialize(self) -&gt; 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) -&gt; None:
bar = slice.bars.get(self._spy)
if self.transactions.get_open_orders(self._spy) or not bar:
return
entry_price = round(bar.close * 0.99, 2)
exit_price = round(bar.close * 1.01, 2)
if self.portfolio[self._spy].invested:
self.limit_order(self._spy, -self.portfolio[self._spy].quantity, exit_price)
return
# The take profit triggers the re-entry, which is a grandchild of the entry.
take_profit = self.order_factory.limit_order(self._spy, -100, exit_price).triggers(
self.order_factory.limit_order(self._spy, 100, entry_price))
self.one_triggers_other_order(self.order_factory.limit_order(self._spy, 100, entry_price), [take_profit])</pre>
</div>