# Bracket orders

:::info

This article requires a thorough understanding of the Trading Platform components and their interactions.
Before continuing with this article, we recommend reading the [Core concepts] article for a better understanding.

:::

## Overview

**Bracket orders** (brackets) are orders that protect positions.
In other words, brackets help users limit their losses and secure their profits
by bracketing positions with two opposing [stop-loss] and [take-profit] orders.

The term **parent** refers to an order or position for which brackets are created.
Bracket orders are linked to the parent order/position via the [`parentId`] and [`parentType`] properties.
The quantity of the bracket order always matches the parent quantity.

Brackets always have the opposite side compared to their parent, for example:

- A buy order is bracketed by a sell-limit order or a sell-stop order.
- A sell order is bracketed by a buy-stop order or a buy-limit order.

Brackets can exist either in a pair as stop-loss and take-profit or independently.
By default, an order or position can have only one bracket order per side (one stop-loss and one take-profit).
However, if the [`supportMultipleExitLevels`] flag is enabled, users can add [multiple exit levels](#multiple-exit-levels).
To allow unpaired levels (only stop-loss or only take-profit for a level), enable [`supportUnpairedExitLevels`].

## UI interactions

Users can add brackets to a new or existing order or to a position.

## Order brackets

To enable adding order brackets in the UI, set the [`supportOrderBrackets`] flag to `true`.
Refer to the [Trading features configuration] section for more information about configuration flags.

### Place order with brackets

Users can place orders with two brackets or only one — either a stop-loss or take-profit.
When users place orders with brackets, the library calls the [`placeOrder`] method and passes a [`PreOrder`] object as a parameter.
This object contains the [`stopLoss`] and [`takeProfit`] fields.

Additionally, if a user places a [limit order] or [stop orders], the `PreOrder` object should contain the following fields:

- For limit order, the [`limitPrice`] field.
- For stop order, the [`stopPrice`] field.

#### Example
Consider the following example: a user places a [market order] with two brackets.

Expand to view the diagram illustrating the process of placing a market order with brackets.

The library calls the [`placeOrder`] method, requesting to create an order.
You should implement this method within the Broker API.
Refer to the [Order creation] section for a detailed explanation.

After your backend server handles the order creation, it responds to your Broker API implementation with updated information.
Your Broker API implementation then calls the [`orderUpdate`] method three times.

1. The first call provides the [`PlacedOrder`] object that contains information about the **parent order**.
    The [status][status-property] of the parent order should be [`Working`].
    Other object values must be identical to the data provided within the `placeOrder` method.

    ```json
    {
        "id": "1",
        "symbol": "NasdaqNM:AAPL",
        "qty": 100,
        "side": 1,   // Side.Buy
        "status": 6, // Status.Working
        "type": 2,   // Type.Market
        "takeProfit": 174.5,
        "stopLoss": 173.32
    }
    ```

  :::info

  For limit and stop orders, make sure to include the `limitPrice` and `stopPrice` fields respectively in the [`PlacedOrder`] object
  when updating the parent order using the [`orderUpdate`] method.

  :::

2. The second call provides the [`BracketOrder`] object that contains information about the **take-profit order**.
  The status of the take-profit order should be `Inactive`, and the `qty` and `symbol` values must be identical to the parent order values.
  The data object must also include:

    - The `parentId` field with a value **equal** to the `id` value of the parent order.
    - The `parentType` field, indicating that the parent type is **order**.
    - The `side` field with a value **opposite** to the `side` value of the parent order.
    - The `limitPrice` field with a value **equal** to the `takeProfit` value of the parent order.
    - The `type` value, indicating that the order type is **limit**.

    ```json
    {
      "id": "2",
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      "parentId": "1",
      "parentType": 1,  // ParentType.Order
      "side": -1,       // Side.Sell
      "status": 3,      // Status.Inactive
      "type": 1,        // Type.Limit
      "limitPrice": 174.5
    }
    ```

3. The third call provides the `BracketOrder` object that contains information about the **stop-loss order**.
  The status of the stop-loss order should be `Inactive`, and the `qty` and `symbol` values must be identical to the parent order values.
  The data object must also include:

    - The `parentId` field with a value **equal** to the `id` value of the parent order.
    - The `parentType` field, indicating that the parent type is **order**.
    - The `side` field with a value **opposite** to the `side` value of the parent order.
    - The `stopPrice` field with a value **equal** to the `stopLoss` value of the parent order.
    - The `type` value, indicating that the order type is **stop**.

    ```json
    {
      "id": "3",
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      "parentId": "1",
      "parentType": 1,  // ParentType.Order
      "side": -1,       // Side.Sell
      "status": 3,      // Status.Inactive
      "type": 3,        // Type.Stop
      "stopPrice": 173.32
    }
    ```

### Execute parent order

Bracket orders are linked to the parent order by the *Order-Sends-Order (OSO)* condition.
This means that once the parent order is executed and its status transitions to `Filled`,
the bracket order [statuses][status] should change to `Working`.

When the parent order is executed, it turns into a position.
Therefore, you should update the `parentId` and `parentType` fields in the bracket order objects to be associated with this new parent position.
Along with changing the order statuses, change the values of the following fields:

- [`parentId`] should be equal to the `id` value of the position that resulted from the execution of the parent order.
- [`parentType`] should be changed to `2`, indicating that the parent type is **position**.

#### Example
Consider the following example: a user has placed a [market order] with two brackets.
Following this, your backend server is responsible for executing the order, creating a position,
and updating the information within the bracket orders.

Expand to view the diagram illustrating the process of executing parent order.

Your Broker API implementation calls the [`executionUpdate`] and [`positionUpdate`] methods.
Refer to the [Execution update] section for a detailed explanation for these methods.

Then, your Broker API implementation calls the [`orderUpdate`] method three times to provide the library with updated information.

1. The first call provides updated information about the **parent order**.
    Its [status] should be `Filled`.

    ```json
    {
        "id": "1",
        "symbol": "NasdaqNM:AAPL",
        "qty": 100,
        "side": 1,    // Side.Buy
        // highlight-next-line
        "status": 2,  // Status.Filled
        "type": 2,    // Type.Market
        "takeProfit": 174.5,
        "stopLoss": 173.32
    }
    ```

2. The second call provides the `BracketOrder` object that contains updated information about the **take-profit order**.
  The data object must contain the following changed values, while other fields should remain the same:

    - The `parentId` field with a value **equal** to the `id` value of the position (`NasdaqNM:AAPL` in this example).
    - The `parentType` field, indicating that the parent type is **position**.
    - The `status` value, indicating that the order status is **working**.

    ```json
    {
      "id": "2",
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      // highlight-start
      "parentId": "NasdaqNM:AAPL",
      "parentType": 2,  // ParentType.Position
      "status": 6,      // Status.Working
      // highlight-end
      "side": -1,       // Side.Sell
      "type": 1,        // Type.Limit
      "limitPrice": 174.5
    }
    ```

3. The third call provides the `BracketOrder` object that contains information about the **stop-loss order**.
  The data object must contain the following changed values, while other fields should remain the same:
    - The `parentId` field with a value **equal** to the `id` value of the position.
    - The `parentType` field, indicating that the parent type is **position**.
    - The `status` value, indicating that the order status is **working**.

    ```json
    {
      "id": "3",
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      // highlight-start
      "parentId": "NasdaqNM:AAPL",
      "parentType": 2,  // ParentType.Position
      "status": 6,      // Status.Working
      // highlight-end
      "side": -1,       // Side.Sell
      "type": 3,        // Type.Stop
      "stopPrice": 173.32
    }
    ```

:::tip

To keep the UI data up-to-date, you should constantly provide updates of users' entity and P&L values whenever changes occur.
Refer to the [Equity update] section for more information.

:::

## Position brackets

To enable adding position brackets in the UI, configure the appropriate flags based on the [position type] (regular or individual).
For more details on configuration flags, check the [Trading features configuration] section.

- For regular positions, set [`supportPositionBrackets`] to `true`.
- For individual positions, set [`supportIndividualPositionBrackets`] to `true`.

:::warning

When `supportPositionBrackets` is true, the library prioritizes net positions.
This hides individual position lines on the chart, even if [position netting] is enabled.

If you want to display individual positions on the chart, ensure that:

- `supportPositionBrackets` is `false`
- `supportIndividualPositionBrackets` is `true`

:::

### Add and modify position brackets

By default, users can add two brackets at the same time or only one of them.
However, you can set the [`supportOnlyPairPositionBrackets`] flag to `true`, so users can add two brackets together only.

Whether adding new brackets or modifying existing ones, the library relies on specific Broker API methods.
Implement the method that corresponds to your [position type]:

- For regular positions, implement [`editPositionBrackets`].
- For individual positions: implement [`editIndividualPositionBrackets`].

In these methods, the library provides the `stopLoss` and `takeProfit` fields.
After that, the library expects you to call the [`positionUpdate`] (or [`individualPositionUpdate`]) method within 10 seconds.
Note that the library will return a [timeout issue] if it fails to receive a timely position update.

#### Example
Consider the following example: the user has an APPL position and decides to place two bracket orders for this position.

Expand to view the diagram illustrating the process of adding two bracket orders to the position.

The library calls the [`editPositionBrackets`] method, providing the `stopLoss` and `takeProfit` fields.
You should implement this method within your Broker API implementation
and handle the user's request to add bracket orders.
Note that the position update and order creation might be processed on external sources, such as exchanges.
However, your backend server is expected to manage this information and provide it in the format required by the library.

After your backend server handles the position update and order creation, it responds to your Broker API implementation with updated information.
Your Broker API implementation then calls the [`positionUpdate`] and [`orderUpdate`] methods.

1. The `positionUpdate` call updates a [`Position`] object with the `stopLoss` and `takeProfit` fields.

    ```json
    {
      "id": "NasdaqNM:AAPL",
      "qty": 100,
      "side": 1,  // Side.Buy
      "symbol": "NasdaqNM:AAPL",
        // highlight-start
      "takeProfit": 174.5,
      "stopLoss": 173.32
        // highlight-end
    }
    ```

2. The first `orderUpdate` call provides the `BracketOrder` object that contains information about the **take-profit order**.
  The status of the take-profit order should be `Working`, and the `qty` and `symbol` values must be identical to the parent position values.
  The data object must also include:

    - The `parentId` field with a value **equal** to the `id` value of the parent position.
    - The `parentType` field, indicating that the parent type is **position**.
    - The `side` field with a value **opposite** to the `side` value of the parent position.
    - The `limitPrice` field with a value **equal** to the `takeProfit` value of the parent position.
    - The `type` value, indicating that the order type is **limit**.

    ```json
    {
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      "id": "2",
      "parentId": "NasdaqNM:AAPL",
      "parentType": 2,  // ParentType.Position
      "side": -1,       // Side.Sell
      "status": 6,      // Status.Working
      "type": 1,        // Type.Limit
      "limitPrice": 174.5
    }
    ```

3. The second `orderUpdate` call provides the `BracketOrder` object that contains information about the **stop-loss order**.
  The status of the stop-loss order should be `Working`, and the `qty` and `symbol` values must be identical to the parent position values.
  The data object must also include:

    - The `parentId` field with a value **equal** to the `id` value of the parent position.
    - The `parentType` field, indicating that the parent type is **position**.
    - The `side` field with a value **opposite** to the `side` value of the parent position.
    - The `stopPrice` field with a value **equal** to the `stopLoss` value of the parent position.
    - The `type` value, indicating that the order type is **stop**.

    ```json
    {
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      "id": "3",
      "parentId": "NasdaqNM:AAPL",
      "parentType": 2,  // ParentType.Position
      "side": -1,       // Side.Sell
      "status": 6,      // Status.Working
      "type": 3,        // Type.Stop
      "stopPrice": 173.32
    }
    ```

### Execute bracket order

Bracket orders are linked to each other by the *One-Cancels-the-Other (OCO)* condition.
This means that when one of the bracket orders is executed, the other one gets canceled.
In this case, the position linked to the executed bracket order should change its quantity to zero, closing the position.

#### Example
Consider the following example: the user has a position with two bracket orders.
You broker server executes a stop-loss order and returns updated information.

Expand to view the diagram illustrating the process of executing a bracket order.

Your Broker API implementation then calls two consequent [`orderUpdate`] methods and then [`positionUpdate`].

1. The first `orderUpdate` call provides information about the executed **stop-loss order**.
  The status of the order should be `Filled`.

    ```json
    {
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      "id": "3",
      "parentId": "NasdaqNM:AAPL",
      "parentType": 2,  // ParentType.Position
      "side": -1,       // Side.Sell
      // highlight-next-line
      "status": 2,      // Status.Filled
      "type": 3,        // Type.Stop
      "stopPrice": 173.32
    }
    ```

2. The second `orderUpdate` call provides information about the canceled **stop-loss order**.
  The status of the order should be `Canceled`.

    ```json
    {
      "symbol": "NasdaqNM:AAPL",
      "qty": 100,
      "id": "3",
      "parentId": "NasdaqNM:AAPL",
      "parentType": 2,  // ParentType.Position
      "side": -1,       // Side.Sell
      // highlight-next-line
      "status": 1,      // Status.Canceled
      "type": 1,        // Type.Limit
      "limitPrice": 174.5
    }
    ```

3. The `positionUpdate` call changes the `qty` property to `0`.

    ```json
    {
      "id": "NasdaqNM:AAPL",
      // highlight-next-line
      "qty": 0,
      "side": 1,  // Side.Buy
      "symbol": "NasdaqNM:AAPL",
      "takeProfit": 174.5,
      "stopLoss": 173.32
    }
    ```

## Multiple exit levels

When [`supportMultipleExitLevels`] is enabled, users can protect orders and positions with multiple brackets at different price levels and quantities.
They can add levels using the *Add level* button in the [Order Ticket] or position dialog.

![Create multiple exit levels](/img/exit-levels.gif)

:::info

Unpaired levels enabled with [`supportUnpairedExitLevels`] can only be created in the [Order Ticket], by switching off one of the level's legs.
Chart trading, including one-click trading, adds paired levels only — users have to cancel one leg afterwards.

:::

### Data structure

When this feature is enabled, the library uses the `exitLevels` property on order and position-related objects ([`PreOrder`], [`PlacedOrder`], [`Position`], [`BracketOrder`]).
This property contains an array of [`ExitLevel`] objects.
Each object represents a separate bracket level with its own quantity and stop-loss/take-profit prices.

:::warning

By default, each item in the `exitLevels` array must include both `takeProfit` and `stopLoss` values.
If a user specifies only one side (for example, only a take-profit), the library automatically adds the other side.

When [`supportUnpairedExitLevels`] is enabled, an exit level can include only one side (either `takeProfit` or `stopLoss`).

:::

To distinguish between the different brackets, the [`BracketOrder`] object includes an `exitLevelId` property.
This ID should correspond to the `id` of the level defined in the `exitLevels` array.

### Backward compatibility

The `exitLevels` property is only used when there are **multiple** exit levels.
When a single bracket pair is present, the library continues to use the root-level `takeProfit` and `stopLoss` fields on [`PreOrder`], [`PlacedOrder`], and [`Position`] objects.
This design maintains backward compatibility for existing integrations.
If users dynamically switch between single and multiple exit levels, your implementation should handle both data structures accordingly.

### Limit number of levels

You can limit the maximum number of exit levels a user can create by returning the `maxExitLevelsCount` property from the [`getOrderDialogOptions`] method.

[Core concepts]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts.md
[Equity update]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts.md#3-equity-update
[Execution update]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts.md#2-execution-update
[limit order]: https://charting-library-docs.xstaging.tv/latest/resources/glossary.md#limit-order
[market order]: https://charting-library-docs.xstaging.tv/latest/resources/glossary.md#market-order
[Order creation]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts.md#1-order-creation
[Order Ticket]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/order-ticket.md
[`Position`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.Position
[position netting]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts/positions.md#position-netting
[position type]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts/positions.md#overview
[status]: https://charting-library-docs.xstaging.tv/latest/api/enums/Charting_Library.OrderStatus
[status-property]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PlacedOrder#status
[stop-loss]: https://charting-library-docs.xstaging.tv/latest/resources/glossary.md#stop-loss-order
[stop orders]: https://charting-library-docs.xstaging.tv/latest/resources/glossary.md#stop-order
[take-profit]: https://charting-library-docs.xstaging.tv/latest/resources/glossary.md#take-profit-order
[timeout issue]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/common-issues.md#timeout-issue
[Trading features configuration]: https://charting-library-docs.xstaging.tv/latest/trading_terminal/trading-concepts/trading-features-configuration.md

[`BracketOrder`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BracketOrder
[`editIndividualPositionBrackets`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerTerminal#editindividualpositionbrackets
[`editPositionBrackets`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerTerminal#editpositionbrackets
[`executionUpdate`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerConnectionAdapterHost#executionupdate
[`ExitLevel`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Broker.ExitLevel
[`getOrderDialogOptions`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerCommon#getorderdialogoptions
[`individualPositionUpdate`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerConnectionAdapterHost#individualpositionupdate
[`limitPrice`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PreOrder#limitprice
[`orderUpdate`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerConnectionAdapterHost#orderupdate
[`parentId`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BracketOrder#parentid
[`parentType`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BracketOrder#parenttype
[`placeOrder`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerTerminal#placeorder
[`PlacedOrder`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PlacedOrder
[`positionUpdate`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.IBrokerConnectionAdapterHost#positionupdate
[`PreOrder`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PreOrder
[`stopLoss`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PreOrder#stoploss
[`stopPrice`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PreOrder#stopprice
[`supportIndividualPositionBrackets`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BrokerConfigFlags#supportindividualpositionbrackets
[`supportMultipleExitLevels`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BrokerConfigFlags#supportmultipleexitlevels
[`supportOnlyPairPositionBrackets`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BrokerConfigFlags#supportindividualpositionbrackets
[`supportOrderBrackets`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BrokerConfigFlags#supportorderbrackets
[`supportPositionBrackets`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BrokerConfigFlags#supportpositionbrackets
[`supportUnpairedExitLevels`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.BrokerConfigFlags#supportunpairedexitlevels
[`takeProfit`]: https://charting-library-docs.xstaging.tv/latest/api/interfaces/Charting_Library.PreOrder#takeprofit
[`Working`]: https://charting-library-docs.xstaging.tv/latest/api/enums/Charting_Library.OrderStatus#working

---

## Sitemap

- [All documentation pages](https://charting-library-docs.xstaging.tv/llms.txt)
- [Full page map with headings](https://charting-library-docs.xstaging.tv/docs_map.md)
