У меня странная проблема с торговлей на Bitget с помощью CCXT.
Я разрабатываю бота на Python, который автоматизирует некоторые сигналы из группы телеграмм с моего ноутбука (Win 11, используя VS), и дело в том, что у меня код работает как положено, ордер на вход выполняется, тейк-профит тоже работает как положено. ... но затем, когда я развертываю код (или просто запускаю его в VS) на Intel NUC, на котором работают мои докер-контейнеры, он продолжает жаловаться на одностороннюю сторону и/или на несоответствие сторон. **Я «жестко» вошел в длинную позицию, выстрелил, купил, продал, но происходит то же самое.
Если я проверю код на третьей машине, он будет работать как положено (я скопировал код непосредственно с NUC, где получил ошибки).
Ниже приведен порядок входа:
Trying to execute order: (29, 5, 'LDOUSDT', 'short', 1.9725, 76.0, 15.0, 'Open', 'entry')
Order response: {'info': {'clientOid': '1191025251500830722', 'orderId': '1191025251484053505'}, 'id': '1191025251484053505', 'clientOrderId': '1191025251500830722', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'lastUpdateTimestamp': None, 'symbol': 'LDO/USDT:USDT', 'type': None, 'side': None, 'price': None, 'amount': None, 'cost': None, 'average': None, 'filled': None, 'remaining': None, 'timeInForce': None, 'postOnly': None, 'reduceOnly': None, 'stopPrice': None, 'triggerPrice': None, 'takeProfitPrice': None, 'stopLossPrice': None, 'status': None, 'fee': None, 'trades': [], 'fees': []}
Запись работает как положено на всех трёх машинах. У меня есть код, позволяющий попытаться получить прибыль (чтобы убедиться, что функция действительно работает):
Order: (31, 5, 'LDOUSDT', 'buy', 1.9338, 5.7, 15.0, 'Open', 'takeprofit')
{'code': '00000', 'msg': 'success', 'requestTime': '1719688487060', 'data': {'posMode': 'hedge_mode'}}
Take-profit order response: {'info': {'clientOid': '1191025332270542852', 'orderId': '1191025332270542849'}, 'id': '1191025332270542849', 'clientOrderId': '1191025332270542852', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'lastUpdateTimestamp': None, 'symbol': 'LDO/USDT:USDT', 'type': None, 'side': None, 'price': None, 'amount': None, 'cost': None, 'average': None, 'filled': None, 'remaining': None, 'timeInForce': None, 'postOnly': None, 'reduceOnly': None, 'stopPrice': None, 'triggerPrice': None, 'takeProfitPrice': None, 'stopLossPrice': None, 'status': None, 'fee': None, 'trades': [], 'fees': []}
Вышеупомянутое было выполнено на ноутбуке, где я написал код... затем попытался выполнить то же самое на Intel NUC:
Trying to execute order: (29, 5, 'LDOUSDT', 'short', 1.9725, 76.0, 15.0, 'Open', 'entry')
Order response: {'info': {'clientOid': '1191029181727256581', 'orderId': '1191029181710479368'}, 'id': '1191029181710479368', 'clientOrderId': '1191029181727256581', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'lastUpdateTimestamp': None, 'symbol': 'LDO/USDT:USDT', 'type': None, 'side': None, 'price': None, 'amount': None, 'cost': None, 'average': None, 'filled': None, 'remaining': None, 'timeInForce': None, 'postOnly': None, 'reduceOnly': None, 'stopPrice': None, 'triggerPrice': None, 'takeProfitPrice': None, 'stopLossPrice': None, 'status': None, 'fee': None, 'trades': [], 'fees': []}
Итак, вход сработал, как и ожидалось, ниже я дважды проверяю, находимся ли мы в режиме хеджирования:
Order: (31, 5, 'LDOUSDT', 'buy', 1.9338, 5.7, 15.0, 'Open', 'takeprofit')
{'code': '00000', 'msg': 'success', 'requestTime': '1719689424364', 'data': {'posMode': 'hedge_mode'}}
и наконец:
An error occurred: bitget {"code":"40774","msg":"The order type for unilateral position must also be the unilateral position type.","requestTime":1719689424722,"data":null}
Ниже приведен тот же код, который я тестировал на всех трех машинах. Он работает как на моем ноутбуке, так и на настольном компьютере, но не на NUC:
async def execute_order(userId, order):
"""Executes a futures order for a user based on the signal received, with specified leverage and margin mode."""
user = await get_user_data(userId)
print(f"User: {user}")
print(f"Trying to execute order: {order}")
if user:
apiKey = decrypt(user[2])
secret = decrypt(user[3])
password = decrypt(user[4])
bitget = ccxt.bitget({
'apiKey': apiKey,
'secret': secret,
'password': password
})
try:
symbol = order[2]
size = order[5]
price = order[4]
margin_coin = 'USDT' # Default margin coin
margin_mode = 'cross'
side = 'buy' if order[3] == 'long' else 'sell'
hold_side = 'long' if order[3] == 'long' else 'short'
pos_side = hold_side # Ensuring posSide matches the holdSide
bitget.options['defaultType'] = 'swap'
# Set position mode
bitget.set_position_mode('False', order[2])
# Set leverage
bitget.set_leverage(15, symbol, {
'marginMode': margin_mode,
'marginCoin': margin_coin,
'holdSide': hold_side
})
parms = {
'holdSide': hold_side,
'marginMode': margin_mode,
'marginCoin': margin_coin,
'posSide': pos_side,
'tradeSide': 'open',
'productType': 'USDT-FUTURES'
}
#print(f"Setting Leverage: {leverage_response}")
# Place the futures order
response = bitget.create_order(symbol, 'market', side, size, price, parms)
print(f"Order response: {response}")
#await telegram_notifier(f"Order executed for user {userId}: {response}")
except Exception as e:
error_message = f"An unexpected error occurred: {e}"
print(error_message)
#await telegram_notifier(f"Error executing futures order for user {userId}: {error_message}")
return None
async def take_profit(userId, tp_order):
"""Sets a take-profit order for the given futures position."""
user = await get_user_data(userId)
if user:
apiKey = decrypt(user[2])
secret = decrypt(user[3])
password = decrypt(user[4])
bitget = ccxt.bitget({
'apiKey': apiKey,
'secret': secret,
'password': password
})
bitget.options['defaultType'] = 'swap'
# Set position mode
hedge = bitget.set_position_mode('False', tp_order[2])
print(hedge)
try:
symbol = tp_order[2]
size = tp_order[5]
price = tp_order[4]
side = tp_order[3]
hold_side = 'long' if side == 'sell' else 'short' # Take profit on the opposite side
# Order parameters
type = 'market' # or 'limit'
amount = size # Amount you want to close, adjust as necessary
price = None # Relevant for limit orders
# Additional parameters specific to Bitget
params = {
'tdMode': 'cross', # or 'cross'
'reduceOnly': True, # This ensures that the order can only reduce a position
}
# Create the order
order = bitget.create_order(symbol, type, side, amount, price, params)
print(f"Take-profit order response: {order}")
if tp_order[8] == 'takeprofit-msl':
await update_stoploss_order_price(tp_order[1])
return None
except ccxt.BaseError as e:
error_message = f"An error occurred: {e}"
print(error_message)
#await telegram_notifier(f"Error setting take-profit order for user {userId}: {error_message}")
return None
Наиболее распространенное предложение, которое я нашел, — это использовать односторонний режим, но мне это действительно не хочется, особенно зная, что он работает на двух компьютерах, но не на NUC. Источник: Закройте позицию Bitget Futures с помощью ccxt и https://tickerly.net/errors/
Еще я пробовал просто жестко запрограммировать HoldSide, tradeSide и т. д., как это предложено в документации API Bitget, но затем он просто жалуется на несоответствие сторон, независимо от значения, если я не изменю Long/Short на Buy/Sell, где это просто утверждает, что значение недействительно.
async def take_profit(userId, tp_order):
"""Sets a take-profit order for the given futures position."""
user = await get_user_data(userId)
if user:
apiKey = decrypt(user[2])
secret = decrypt(user[3])
password = decrypt(user[4])
bitget = ccxt.bitget({
'apiKey': apiKey,
'secret': secret,
'password': password
})
bitget.options['defaultType'] = 'swap'
# Set position mode
hedge = bitget.set_position_mode('False', tp_order[2])
print(hedge)
try:
symbol = tp_order[2]
size = tp_order[5]
price = tp_order[4]
side = 'long'#tp_order[3]
hold_side = 'long' if side == 'sell' else 'short' # Take profit on the opposite side
# Order parameters
type = 'market' # or 'limit'
amount = size # Amount you want to close, adjust as necessary
price = None # Relevant for limit orders
# Additional parameters specific to Bitget
params = {
'tdMode': 'cross', # or 'cross'
'reduceOnly': True, # This ensures that the order can only reduce a position
}
# Create the order
order = bitget.create_order(symbol, type, side, amount, price, params)
print(f"Take-profit order response: {order}")
if tp_order[8] == 'takeprofit-msl':
await update_stoploss_order_price(tp_order[1])
return None
except ccxt.BaseError as e:
error_message = f"An error occurred: {e}"
print(error_message)
#await telegram_notifier(f"Error setting take-profit order for user {userId}: {error_message}")
return None
возвращает следующее:
Trying to execute order: (29, 5, 'LDOUSDT', 'short', 1.9725, 76.0, 15.0, 'Open', 'entry')
Order response: {'info': {'clientOid': '1191031910600159232', 'orderId': '1191031910583382017'}, 'id': '1191031910583382017', 'clientOrderId': '1191031910600159232', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'lastUpdateTimestamp': None, 'symbol': 'LDO/USDT:USDT', 'type': None, 'side': None, 'price': None, 'amount': None, 'cost': None, 'average': None, 'filled': None, 'remaining': None, 'timeInForce': None, 'postOnly': None, 'reduceOnly': None, 'stopPrice': None, 'triggerPrice': None, 'takeProfitPrice': None, 'stopLossPrice': None, 'status': None, 'fee': None, 'trades': [], 'fees': []}
Order: (31, 5, 'LDOUSDT', 'buy', 1.9338, 5.7, 15.0, 'Open', 'takeprofit')
{'code': '00000', 'msg': 'success', 'requestTime': '1719690075905', 'data': {'posMode': 'hedge_mode'}}
An error occurred: bitget {"code":"400172","msg":"side mismatch","requestTime":1719690076235,"data":null}
Вышеупомянутое должно быть несоответствием, поскольку оба короткие. Я пробовал ввести Long и все другие возможные значения, но проблема та же.
Как упоминалось ранее, я проверил документацию Bitgets API и попробовал дополнительные параметры, как они предлагают, но все равно ничего. Документация по API здесь: https://docs.ccxt.com/#/exchanges/bitget?id=createorder
Думаю, еще одним исключением было следующее:
Но когда я попробовал его использовать, он заявил, что открытой позиции нет.
Как я могу устранить эту неполадку?
Похоже, это ошибка в библиотеке CCXT при торговле односторонними позициями, здесь требуется ссылка на параметр tradeSide: https://github.com/ccxt/ccxt/issues/19140#issuecomment-1882527221
так как это мой код тейк-профита, у меня tradeSide
статический 'close'
Мой код работает следующим образом:
async def take_profit(userId, tp_order):
"""Sets a take-profit order for the given futures position."""
user = await get_user_data(userId)
if user:
apiKey = decrypt(user[2])
secret = decrypt(user[3])
password = decrypt(user[4])
bitget = ccxt.bitget({
'apiKey': apiKey,
'secret': secret,
'password': password
})
bitget.options['defaultType'] = 'swap'
# Set position mode
bitget.set_position_mode('False', tp_order[2])
try:
symbol = tp_order[2]
size = tp_order[5]
price = tp_order[4]
side = tp_order[3]
# Order parameters
type = 'market' # or 'limit'
amount = size # Amount you want to close, adjust as necessary
price = None # Relevant for limit orders
# Additional parameters specific to Bitget
params = {
'tdMode': 'cross', # or 'cross'
'reduceOnly': True, # This ensures that the order can only reduce a position
'tradeSide': 'close',
'productType': 'USDT-FUTURES'
}
# Create the order
order = bitget.create_order(symbol, type, side, amount, price, params)
print(f"Take-profit order response: {order}")
if tp_order[8] == 'takeprofit-msl':
await update_stoploss_order_price(tp_order[1])
return None
except ccxt.BaseError as e:
error_message = f"An error occurred: {e}"
print(error_message)
#await telegram_notifier(f"Error setting take-profit order for user {userId}: {error_message}")
return None
Обратите внимание, что сторона должна иметь значение «купить» для длинных позиций и «продать» для коротких. Я не уверен на 100%, почему простое прохождение длинной или короткой позиции не работает и приводит к «ошибке несоответствия сторон».