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