Need help with a Simple TP + SL-> OSO + OCO

I am really running up a wall…all I want at this moment is a “simple” order that includes a stop loss and a take profit. I know I could create seperate orders but I rather have it combined where I know for sure that if the main order is indeed filled only then my stop and take profit is added to the system

I have the following code which nicely places all 3 orders but it rejects right away the bracket orders. I feel I am overlooking something simple but could really use a helping hand


def place_market_buy_with_tp_sl_oso(instrument_symbol, quantity, take_profit_points, stop_loss_points, current_price):
    """
    Places a market buy order with a take-profit and stop-loss using the `placeOSO` operation.

    Args:
        instrument_symbol (str): The instrument symbol (e.g., "MESM1").
        quantity (int): The quantity to trade.
        take_profit_points (float): The take-profit distance in points from the entry price.
        stop_loss_points (float): The stop-loss distance in points from the entry price.
        data_bento_price (float): The current market price from DataBento.

    Returns:
        tuple: (success, message, order_ids) - success is a boolean, message is a string, order_ids is a dictionary (or None)
    """


    # Calculate take profit and stop loss prices
    take_profit_price = current_price + take_profit_points
    stop_loss_price = current_price - stop_loss_points

    # Payload for the placeOSO operation
    oso_payload = {
        "accountSpec": USERNAME,         # Replace with your account username
        "accountId": account_id,         # Replace with your account ID
        "action": "Buy",                 #Buy or Sell
        "symbol": instrument_symbol,
        "orderQty": int(quantity),  # Ensure quantity is an integer
        "orderType": "Market",  # Initial market buy or sell order
        "isAutomated": True,  # Required for non-manual orders

        "bracket1": {  # Take-profit order 
            "action": "Sell",
            "orderType": "Stop",  
            "stopPrice": take_profit_price #Using Stop order requires setting the Stop price to be used instead of Limit
        },

        "bracket2": {  # Stop-loss order
            "action": "Sell",
            "orderType": "Stop",
            "stopPrice": stop_loss_price
        }
    }

    try:
        # Place the OSO order
        response = requests.post(ORDER_ENDPOINT, headers={
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json'
        }, json=oso_payload)

        response.raise_for_status() #Raise exception for bad status codes
        oso_data = response.json()

        if "orderId" in oso_data and "bracket1Id" in oso_data and "bracket2Id" in oso_data:
            order_ids = {
                "market_order_id": oso_data['orderId'],
                "take_profit_order_id": oso_data['bracket1Id'],
                "stop_loss_order_id": oso_data['bracket2Id']
            }
            message = f"Market buy, take-profit, and stop-loss placed successfully. IDs: {order_ids}"
            print(message) 
            return True, message, order_ids
        else:
            print(f"Error: Failed to place OSO order. Response: {oso_data}") #Log the full response for debugging
            return False, f"Failed to place OSO order. Response: {oso_data}", None

    except requests.exceptions.RequestException as e:
        print(f"Request failed: {e}") #Log the exception
        return False, f"Request failed: {e}", None
    except Exception as e:
        print(f"An error occurred: {e}") #Log the exception
        return False, f"An error occurred: {e}", None

I found my mistake…I had both bracktes set at stop sell and it should have been for the take profit part (in thise case for a long) a limit sell order at the tp level`

Payload for the placeOSO operation

oso_payload = {
    "accountSpec": USERNAME,         # Replace with your account username
    "accountId": account_id,         # Replace with your account ID
    "action": "Buy",                 #Buy or Sell
    "symbol": instrument_symbol,
    "orderQty": int(quantity),  # Ensure quantity is an integer
    "orderType": "Market",  # Initial market buy or sell order
    "isAutomated": True,  # Required for non-manual orders

    "bracket1": {  # Take-profit order 
        "action": "Sell",
        "orderType": "Stop",  
        "stopPrice": take_profit_price #Using Stop order requires setting the Stop price to be used instead of Limit
    },

    "bracket2": {  # Stop-loss order
        "action": "Sell",
        "orderType": "Stop",
        "stopPrice": stop_loss_price
    }
}

`

Should have been

oso_payload = {
        "accountSpec": USERNAME,         # Replace with your account username
        "accountId": account_id,         # Replace with your account ID
        "action": "Buy",                 #Buy or Sell
        "symbol": instrument_symbol,
        "orderQty": int(quantity),  # Ensure quantity is an integer
        "orderType": "Market",  # Initial market buy or sell order
        "isAutomated": True,  # Required for non-manual orders

        "bracket1": {  # Take-profit order 
            "action": "Sell",
            "orderType": "Limit",  
            "price": take_profit_price #Using Stop order requires setting the Stop price to be used instead of Limit
        },

        "bracket2": {  # Stop-loss order
            "action": "Sell",
            "orderType": "Stop",
            "stopPrice": stop_loss_price
        }
    }
1 Like