Skip to content
All library documents

One-Cancels-the-Other Orders for a Single Stock Position

Code Lumibot

Summary

This example strategy demonstrates placing an entry market order followed by a one-cancels-the-other sell order. The OCO order pairs a take-profit limit price with a stop price, so execution of one exit is intended to cancel the other. The sample uses a configurable stock symbol, quantity, and price levels, and submits the orders on the strategy's first trading iteration.

The example is an API usage illustration rather than a trading system with a tested edge. It runs on a daily schedule and includes both a live broker setup and a historical backtest over a short date range, but reports no performance results. The code does not discuss order-fill timing, partial fills, broker-specific OCO behavior, position reconciliation, or risk sizing. Users need to verify those execution details for their brokerage and evaluate the chosen prices and quantity for their own strategy.

Key ideas

  • The strategy enters a stock position with a market buy order.
  • It submits paired take-profit and stop-loss exit prices as an OCO order.
  • The orders are submitted only during the first strategy iteration.
  • The example includes live trading and backtesting setup but provides no results.
  • Broker behavior, fills, and position risk require separate evaluation.

Tags

Full text
# stock_oco.py


```py
from datetime import datetime

from lumibot.entities import Order
from lumibot.strategies.strategy import Strategy

"""
Strategy Description

An example strategy for how to use OCO orders.
"""


class StockOco(Strategy):
    parameters = {
        "buy_symbol": "SPY",
        "take_profit_price": 405,
        "stop_loss_price": 395,
        "quantity": 10,
    }

    # =====Overloading lifecycle methods=============

    def initialize(self):
        # Set the initial variables or constants

        # Built in Variables
        self.sleeptime = "1D"

        # Our Own Variables
        self.counter = 0
        self.submitted_oco_order = None  # Useful for updating/cancelling orders


    def on_trading_iteration(self):
        """Buys the self.buy_symbol once, then never again"""

        buy_symbol = self.parameters["buy_symbol"]
        take_profit_price = self.parameters["take_profit_price"]
        stop_loss_price = self.parameters["stop_loss_price"]
        quantity = self.parameters["quantity"]

        # What to do each iteration
        current_value = self.get_last_price(buy_symbol)
        self.log_message(f"The value of {buy_symbol} is {current_value}")

        if self.first_iteration:
            # Market order
                main_order = self.create_order(
                    buy_symbol, quantity, Order.OrderSide.BUY,
                )
                self.submit_order(main_order)

                # OCO order
                order = self.create_order(
                    buy_symbol,
                    quantity,
                    Order.OrderSide.SELL,
                    limit_price=take_profit_price,
                    stop_price=stop_loss_price,
                    order_class=Order.OrderClass.OCO,
                )
                self.submitted_oco_order = self.submit_order(order)


if __name__ == "__main__":
    is_live = False

    if is_live:
        from credentials import ALPACA_CONFIG

        from lumibot.brokers import Alpaca

        broker = Alpaca(ALPACA_CONFIG)

        strategy = StockOco(broker=broker)
        strategy.run_live()

    else:
        from lumibot.backtesting import YahooDataBacktesting

        # Backtest this strategy
        backtesting_start = datetime(2023, 3, 3)
        backtesting_end = datetime(2023, 3, 10)

        results = StockOco.backtest(
            YahooDataBacktesting,
            backtesting_start,
            backtesting_end,
            benchmark_asset="SPY",
        )

```

Shown in full with attribution under the source's licence. Licence: GPL-3.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.