so I have tried all the possible combinations of parameters to use when trying to set the OCO parameters. However every time remove the aboveType/belowType, i am being sent a message that i need to include them OCO order failed: Mandatory parameter 'aboveType' was not sent, was empty/null, or malformed. π Full error response: {'code': -1102, 'msg': "Mandatory parameter 'aboveType' was not sent, was empty/null, or malformed."}
and when i include them, i receive this message:
OCO order failed: Not all sent parameters were read; read '9' parameter(s) but was sent '13'. π Full error response: {'code': -1104, 'msg': "Not all sent parameters were read; read '9' parameter(s) but was sent '13'."}
This is my full code can anyone help me ? I am using the latest version of python and my libraries are included at the beginning of the code for more information. All up-to-date ! Obviously I am using Websockets to not abuse from the API.
from binance.client import Client
from binance.enums import *
from binance import ThreadedWebsocketManager
from decimal import Decimal, ROUND_DOWN
from binance.exceptions import BinanceAPIException
import os
import time
import threading
import requests
import asyncio
# Testnet API keys (get from https://testnet.binance.vision/)
API_KEY = ''
API_SECRET = ''
# Use TESTNET URLs
BASE_URL = 'https://testnet.binance.vision'
client = Client(API_KEY, API_SECRET, testnet=True)
client.API_URL = BASE_URL
print(client.API_URL)
symbol = 'BNBFDUSD'
quote_asset = 'FDUSD'
base_asset = 'BNB'
tick_size = step_size = min_qty = None
last_price = None
min_notional = None
def get_symbol_filters(symbol):
global tick_size, step_size, min_qty, min_notional
min_notional = None # ensure default value
url = f"{BASE_URL}/api/v3/exchangeInfo"
response = requests.get(url)
data = response.json()
for s in data['symbols']:
if s['symbol'] == symbol:
for f in s['filters']:
if f['filterType'] == 'PRICE_FILTER':
tick_size = Decimal(f['tickSize'])
elif f['filterType'] == 'LOT_SIZE':
step_size = Decimal(f['stepSize'])
min_qty = Decimal(f['minQty'])
elif f['filterType'] == 'MIN_NOTIONAL':
min_notional = Decimal(f['minNotional'])
break
print(f"Filters for {symbol}:")
print(f" Tick size: {tick_size}")
print(f" Step size: {step_size}")
print(f" Min qty: {min_qty}")
print(f" Min notional: {min_notional if min_notional else 'N/A'}")
def round_step(value, step):
value = Decimal(value)
precision = abs(step.normalize().as_tuple().exponent)
return value.quantize(Decimal(f"1e-{precision}"), rounding=ROUND_DOWN)
def get_trade_quantity(price, spend_amount):
qty = Decimal(spend_amount) / Decimal(price)
qty = round_step(qty, step_size)
notional = qty * Decimal(price)
# Use min_notional from exchange filters if available, otherwise use $10 fallback
effective_min_notional = min_notional if min_notional else Decimal('10')
if notional < effective_min_notional:
raise Exception(f"Trade notional {notional} is below min notional {effective_min_notional}")
return max(qty, min_qty)
def handle_socket_message(msg):
global last_price
if msg['e'] == 'trade':
last_price = float(msg['p'])
print(f"Live price: {last_price}")
# Thread-safe wrapper for socket
def start_socket_in_thread():
def run_socket():
twm = ThreadedWebsocketManager(api_key=API_KEY, api_secret=API_SECRET)
twm.start()
twm.start_trade_socket(callback=handle_socket_message, symbol=symbol.lower())
# Keep the socket alive
twm.join() # Keeps the thread running
thread = threading.Thread(target=run_socket)
thread.daemon = True
thread.start()
async def wait_for_price():
while last_price is None:
await asyncio.sleep(0.5)
def place_oco_order(entry_price, quantity):
tp_price = round(entry_price + 0.20, 2)
stop_price = round(entry_price - 0.01, 2)
stop_limit_price = round(stop_price - 0.01, 2)
oco_params = {
'symbol': symbol,
'side': SIDE_SELL,
'quantity': str(quantity),
'price': str(tp_price), # Take profit
'stopPrice': str(stop_price), # Trigger
'stopLimitPrice': str(stop_limit_price), # Limit price after stop
'stopLimitTimeInForce': TIME_IN_FORCE_GTC
}
import json
print("\nπ€ Sending OCO order payload:")
print(json.dumps(oco_params, indent=2))
try:
order = client.create_oco_order(**oco_params)
print(f"β
OCO order placed:\n{json.dumps(order, indent=2)}")
except BinanceAPIException as e:
print(f"\nβ OCO order failed: {e.message}")
if hasattr(e, 'response'):
try:
print("π Full error response:")
print(e.response.json())
except Exception as ex:
print("Failed to parse full error JSON:", str(ex))
else:
print("No additional error response available.")
def market_buy(qty):
order = client.order_market_buy(symbol=symbol, quantity=str(qty))
print("Buy filled:", order)
return order
async def main():
get_symbol_filters(symbol)
balance = client.get_asset_balance(asset=quote_asset)
print(f"Current balance: {balance['free']} {quote_asset}")
spend = Decimal(input(f"How much {quote_asset} per trade (Max {balance['free']})? "))
# Start WebSocket in background thread
start_socket_in_thread()
await wait_for_price()
qty = get_trade_quantity(last_price, spend)
print(f"Placing buy at {last_price}, Qty: {qty}")
market_buy(qty)
await asyncio.sleep(2)
place_oco_order(last_price, qty)
await asyncio.sleep(5)
if __name__ == '__main__':
asyncio.run(main())
Can anyone help identify the solution ?
I tried to remove each parameter one by one but all of them are needed. I remember reading in some posts (i couldn't find the link again to show it to you), that aboveType/belowType are used in futures only. This is a python program for BNBFDUSD trading only on spot !!! I do not intend to take it to futures.
I escaped many issues using this post but i am stuck with the fictional 4 parameters that appear out of nowhere (unless i misunderstood something).