ccxt 4.2.35 → 4.2.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/src/binance.js CHANGED
@@ -4738,7 +4738,7 @@ export default class binance extends Exchange {
4738
4738
  }
4739
4739
  request['price'] = this.priceToPrecision(symbol, price);
4740
4740
  }
4741
- if (timeInForceIsRequired) {
4741
+ if (timeInForceIsRequired && (this.safeString(params, 'timeInForce') === undefined)) {
4742
4742
  request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
4743
4743
  }
4744
4744
  if (stopPriceIsRequired) {
@@ -5043,18 +5043,128 @@ export default class binance extends Exchange {
5043
5043
  // "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"},
5044
5044
  // "mmp": false
5045
5045
  // }
5046
- // {
5046
+ //
5047
5047
  // cancelOrders/createOrders
5048
- // "code": -4005,
5049
- // "msg": "Quantity greater than max quantity."
5050
- // },
5048
+ //
5049
+ // {
5050
+ // "code": -4005,
5051
+ // "msg": "Quantity greater than max quantity."
5052
+ // }
5053
+ //
5054
+ // createOrder: portfolio margin linear swap and future
5055
+ //
5056
+ // {
5057
+ // "symbol": "BTCUSDT",
5058
+ // "side": "BUY",
5059
+ // "executedQty": "0.000",
5060
+ // "orderId": 258649539704,
5061
+ // "goodTillDate": 0,
5062
+ // "avgPrice": "0",
5063
+ // "origQty": "0.010",
5064
+ // "clientOrderId": "x-xcKtGhcu02573c6f15e544e990057b",
5065
+ // "positionSide": "BOTH",
5066
+ // "cumQty": "0.000",
5067
+ // "updateTime": 1707110415436,
5068
+ // "type": "LIMIT",
5069
+ // "reduceOnly": false,
5070
+ // "price": "35000.00",
5071
+ // "cumQuote": "0.00000",
5072
+ // "selfTradePreventionMode": "NONE",
5073
+ // "timeInForce": "GTC",
5074
+ // "status": "NEW"
5075
+ // }
5076
+ //
5077
+ // createOrder: portfolio margin inverse swap and future
5078
+ //
5079
+ // {
5080
+ // "symbol": "ETHUSD_PERP",
5081
+ // "side": "BUY",
5082
+ // "cumBase": "0",
5083
+ // "executedQty": "0",
5084
+ // "orderId": 71275227732,
5085
+ // "avgPrice": "0.00",
5086
+ // "origQty": "1",
5087
+ // "clientOrderId": "x-xcKtGhcuca5af3acfb5044198c5398",
5088
+ // "positionSide": "BOTH",
5089
+ // "cumQty": "0",
5090
+ // "updateTime": 1707110994334,
5091
+ // "type": "LIMIT",
5092
+ // "pair": "ETHUSD",
5093
+ // "reduceOnly": false,
5094
+ // "price": "2000",
5095
+ // "timeInForce": "GTC",
5096
+ // "status": "NEW"
5097
+ // }
5098
+ //
5099
+ // createOrder: portfolio margin linear swap and future conditional
5100
+ //
5101
+ // {
5102
+ // "newClientStrategyId": "x-xcKtGhcu27f109953d6e4dc0974006",
5103
+ // "strategyId": 3645916,
5104
+ // "strategyStatus": "NEW",
5105
+ // "strategyType": "STOP",
5106
+ // "origQty": "0.010",
5107
+ // "price": "35000.00",
5108
+ // "reduceOnly": false,
5109
+ // "side": "BUY",
5110
+ // "positionSide": "BOTH",
5111
+ // "stopPrice": "45000.00",
5112
+ // "symbol": "BTCUSDT",
5113
+ // "timeInForce": "GTC",
5114
+ // "bookTime": 1707112625879,
5115
+ // "updateTime": 1707112625879,
5116
+ // "workingType": "CONTRACT_PRICE",
5117
+ // "priceProtect": false,
5118
+ // "goodTillDate": 0,
5119
+ // "selfTradePreventionMode": "NONE"
5120
+ // }
5121
+ //
5122
+ // createOrder: portfolio margin inverse swap and future conditional
5123
+ //
5124
+ // {
5125
+ // "newClientStrategyId": "x-xcKtGhcuc6b86f053bb34933850739",
5126
+ // "strategyId": 1423462,
5127
+ // "strategyStatus": "NEW",
5128
+ // "strategyType": "STOP",
5129
+ // "origQty": "1",
5130
+ // "price": "2000",
5131
+ // "reduceOnly": false,
5132
+ // "side": "BUY",
5133
+ // "positionSide": "BOTH",
5134
+ // "stopPrice": "3000",
5135
+ // "symbol": "ETHUSD_PERP",
5136
+ // "timeInForce": "GTC",
5137
+ // "bookTime": 1707113098840,
5138
+ // "updateTime": 1707113098840,
5139
+ // "workingType": "CONTRACT_PRICE",
5140
+ // "priceProtect": false
5141
+ // }
5142
+ //
5143
+ // createOrder: portfolio margin spot margin
5144
+ //
5145
+ // {
5146
+ // "clientOrderId": "x-R4BD3S82e9ef29d8346440f0b28b86",
5147
+ // "cummulativeQuoteQty": "0.00000000",
5148
+ // "executedQty": "0.00000000",
5149
+ // "fills": [],
5150
+ // "orderId": 24684460474,
5151
+ // "origQty": "0.00100000",
5152
+ // "price": "35000.00000000",
5153
+ // "selfTradePreventionMode": "EXPIRE_MAKER",
5154
+ // "side": "BUY",
5155
+ // "status": "NEW",
5156
+ // "symbol": "BTCUSDT",
5157
+ // "timeInForce": "GTC",
5158
+ // "transactTime": 1707113538870,
5159
+ // "type": "LIMIT"
5160
+ // }
5051
5161
  //
5052
5162
  const code = this.safeString(order, 'code');
5053
5163
  if (code !== undefined) {
5054
5164
  // cancelOrders/createOrders might have a partial success
5055
5165
  return this.safeOrder({ 'info': order, 'status': 'rejected' }, market);
5056
5166
  }
5057
- const status = this.parseOrderStatus(this.safeString(order, 'status'));
5167
+ const status = this.parseOrderStatus(this.safeString2(order, 'status', 'strategyStatus'));
5058
5168
  const marketId = this.safeString(order, 'symbol');
5059
5169
  const marketType = ('closePosition' in order) ? 'contract' : 'spot';
5060
5170
  const symbol = this.safeSymbol(marketId, market, undefined, marketType);
@@ -5081,11 +5191,9 @@ export default class binance extends Exchange {
5081
5191
  // Note this is not the actual cost, since Binance futures uses leverage to calculate margins.
5082
5192
  let cost = this.safeString2(order, 'cummulativeQuoteQty', 'cumQuote');
5083
5193
  cost = this.safeString(order, 'cumBase', cost);
5084
- const id = this.safeString(order, 'orderId');
5085
5194
  let type = this.safeStringLower(order, 'type');
5086
5195
  const side = this.safeStringLower(order, 'side');
5087
5196
  const fills = this.safeValue(order, 'fills', []);
5088
- const clientOrderId = this.safeString(order, 'clientOrderId');
5089
5197
  let timeInForce = this.safeString(order, 'timeInForce');
5090
5198
  if (timeInForce === 'GTX') {
5091
5199
  // GTX means "Good Till Crossing" and is an equivalent way of saying Post Only
@@ -5108,8 +5216,8 @@ export default class binance extends Exchange {
5108
5216
  }
5109
5217
  return this.safeOrder({
5110
5218
  'info': order,
5111
- 'id': id,
5112
- 'clientOrderId': clientOrderId,
5219
+ 'id': this.safeString2(order, 'orderId', 'strategyId'),
5220
+ 'clientOrderId': this.safeString2(order, 'clientOrderId', 'newClientStrategyId'),
5113
5221
  'timestamp': timestamp,
5114
5222
  'datetime': this.iso8601(timestamp),
5115
5223
  'lastTradeTimestamp': lastTradeTimestamp,
@@ -5223,50 +5331,105 @@ export default class binance extends Exchange {
5223
5331
  * @see https://binance-docs.github.io/apidocs/voptions/en/#new-order-trade
5224
5332
  * @see https://binance-docs.github.io/apidocs/spot/en/#new-order-using-sor-trade
5225
5333
  * @see https://binance-docs.github.io/apidocs/spot/en/#test-new-order-using-sor-trade
5334
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-um-order-trade
5335
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-cm-order-trade
5336
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-margin-order-trade
5337
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-um-conditional-order-trade
5338
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-cm-conditional-order-trade
5226
5339
  * @param {string} symbol unified symbol of the market to create an order in
5227
5340
  * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP'
5228
5341
  * @param {string} side 'buy' or 'sell'
5229
- * @param {float} amount how much of currency you want to trade in units of base currency
5230
- * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
5342
+ * @param {float} amount how much of you want to trade in units of the base currency
5343
+ * @param {float} [price] the price that the order is to be fullfilled, in units of the quote currency, ignored in market orders
5231
5344
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5345
+ * @param {string} [params.reduceOnly] for swap and future reduceOnly is a string 'true' or 'false' that cant be sent with close position set to true or in hedge mode. For spot margin and option reduceOnly is a boolean.
5232
5346
  * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
5233
5347
  * @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false
5234
5348
  * @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false
5235
5349
  * @param {float} [params.trailingPercent] the percent to trail away from the current market price
5236
5350
  * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
5351
+ * @param {float} [params.triggerPrice] the price that a trigger order is triggered at
5352
+ * @param {float} [params.stopLossPrice] the price that a stop loss order is triggered at
5353
+ * @param {float} [params.takeProfitPrice] the price that a take profit order is triggered at
5354
+ * @param {boolean} [params.portfolioMargin] set to true if you would like to create an order in a portfolio margin account
5237
5355
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
5238
5356
  */
5239
5357
  await this.loadMarkets();
5240
5358
  const market = this.market(symbol);
5241
5359
  const marketType = this.safeString(params, 'type', market['type']);
5242
- const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
5243
- const sor = this.safeValue2(params, 'sor', 'SOR', false);
5244
- params = this.omit(params, 'sor', 'SOR');
5360
+ let marginMode = undefined;
5361
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
5362
+ let isPortfolioMargin = undefined;
5363
+ [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'createOrder', 'papi', 'portfolioMargin', false);
5364
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
5365
+ const stopLossPrice = this.safeString(params, 'stopLossPrice');
5366
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
5367
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
5368
+ const isTrailingPercentOrder = trailingPercent !== undefined;
5369
+ const isStopLoss = stopLossPrice !== undefined;
5370
+ const isTakeProfit = takeProfitPrice !== undefined;
5371
+ const isConditional = (triggerPrice !== undefined) || isTrailingPercentOrder || isStopLoss || isTakeProfit;
5372
+ const sor = this.safeBool2(params, 'sor', 'SOR', false);
5373
+ const test = this.safeBool(params, 'test', false);
5374
+ params = this.omit(params, ['sor', 'SOR', 'test']);
5375
+ if (isPortfolioMargin) {
5376
+ params['portfolioMargin'] = isPortfolioMargin;
5377
+ }
5245
5378
  const request = this.createOrderRequest(symbol, type, side, amount, price, params);
5246
- let method = 'privatePostOrder';
5247
- if (sor) {
5248
- method = 'privatePostSorOrder';
5379
+ let response = undefined;
5380
+ if (market['option']) {
5381
+ response = await this.eapiPrivatePostOrder(request);
5382
+ }
5383
+ else if (sor) {
5384
+ if (test) {
5385
+ response = await this.privatePostSorOrderTest(request);
5386
+ }
5387
+ else {
5388
+ response = await this.privatePostSorOrder(request);
5389
+ }
5249
5390
  }
5250
5391
  else if (market['linear']) {
5251
- method = 'fapiPrivatePostOrder';
5392
+ if (isPortfolioMargin) {
5393
+ if (isConditional) {
5394
+ response = await this.papiPostUmConditionalOrder(request);
5395
+ }
5396
+ else {
5397
+ response = await this.papiPostUmOrder(request);
5398
+ }
5399
+ }
5400
+ else {
5401
+ response = await this.fapiPrivatePostOrder(request);
5402
+ }
5252
5403
  }
5253
5404
  else if (market['inverse']) {
5254
- method = 'dapiPrivatePostOrder';
5405
+ if (isPortfolioMargin) {
5406
+ if (isConditional) {
5407
+ response = await this.papiPostCmConditionalOrder(request);
5408
+ }
5409
+ else {
5410
+ response = await this.papiPostCmOrder(request);
5411
+ }
5412
+ }
5413
+ else {
5414
+ response = await this.dapiPrivatePostOrder(request);
5415
+ }
5255
5416
  }
5256
5417
  else if (marketType === 'margin' || marginMode !== undefined) {
5257
- method = 'sapiPostMarginOrder';
5258
- }
5259
- if (market['option']) {
5260
- method = 'eapiPrivatePostOrder';
5418
+ if (isPortfolioMargin) {
5419
+ response = await this.papiPostMarginOrder(request);
5420
+ }
5421
+ else {
5422
+ response = await this.sapiPostMarginOrder(request);
5423
+ }
5261
5424
  }
5262
- // support for testing orders
5263
- if (market['spot'] || marketType === 'margin') {
5264
- const test = this.safeBool(query, 'test', false);
5425
+ else {
5265
5426
  if (test) {
5266
- method += 'Test';
5427
+ response = await this.privatePostOrderTest(request);
5428
+ }
5429
+ else {
5430
+ response = await this.privatePostOrder(request);
5267
5431
  }
5268
5432
  }
5269
- const response = await this[method](request);
5270
5433
  return this.parseOrder(response, market);
5271
5434
  }
5272
5435
  createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
@@ -5274,16 +5437,13 @@ export default class binance extends Exchange {
5274
5437
  * @method
5275
5438
  * @ignore
5276
5439
  * @name binance#createOrderRequest
5277
- * @description helper function to build request
5440
+ * @description helper function to build the request
5278
5441
  * @param {string} symbol unified symbol of the market to create an order in
5279
- * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP'
5442
+ * @param {string} type 'market' or 'limit'
5280
5443
  * @param {string} side 'buy' or 'sell'
5281
- * @param {float} amount how much of currency you want to trade in units of base currency
5282
- * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
5283
- * @param {object} params extra parameters specific to the exchange API endpoint
5284
- * @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading
5285
- * @param {float} [params.trailingPercent] the percent to trail away from the current market price
5286
- * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
5444
+ * @param {float} amount how much you want to trade in units of the base currency
5445
+ * @param {float} [price] the price that the order is to be fullfilled, in units of the quote currency, ignored in market orders
5446
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
5287
5447
  * @returns {object} request to be sent to the exchange
5288
5448
  */
5289
5449
  const market = this.market(symbol);
@@ -5292,35 +5452,54 @@ export default class binance extends Exchange {
5292
5452
  const initialUppercaseType = type.toUpperCase();
5293
5453
  const isMarketOrder = initialUppercaseType === 'MARKET';
5294
5454
  const isLimitOrder = initialUppercaseType === 'LIMIT';
5295
- const postOnly = this.isPostOnly(isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params);
5296
- const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
5297
- const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
5298
- const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
5299
- const trailingDelta = this.safeValue(params, 'trailingDelta');
5300
- const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', this.numberToString(price));
5301
- const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
5302
- const isTrailingPercentOrder = trailingPercent !== undefined;
5303
- const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
5304
- const isTakeProfit = takeProfitPrice !== undefined;
5305
- params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent']);
5306
- const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
5307
5455
  const request = {
5308
5456
  'symbol': market['id'],
5309
5457
  'side': side.toUpperCase(),
5310
5458
  };
5311
- if (market['spot'] || marketType === 'margin') {
5312
- // only supported for spot/margin api (all margin markets are spot markets)
5313
- if (postOnly) {
5314
- type = 'LIMIT_MAKER';
5459
+ let isPortfolioMargin = undefined;
5460
+ [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'createOrder', 'papi', 'portfolioMargin', false);
5461
+ let marginMode = undefined;
5462
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
5463
+ if ((marketType === 'margin') || (marginMode !== undefined) || market['option']) {
5464
+ // for swap and future reduceOnly is a string that cant be sent with close position set to true or in hedge mode
5465
+ const reduceOnly = this.safeBool(params, 'reduceOnly', false);
5466
+ params = this.omit(params, 'reduceOnly');
5467
+ if (market['option']) {
5468
+ request['reduceOnly'] = reduceOnly;
5469
+ }
5470
+ else {
5471
+ if (reduceOnly) {
5472
+ request['sideEffectType'] = 'AUTO_REPAY';
5473
+ }
5315
5474
  }
5316
5475
  }
5317
- if (marketType === 'margin' || marginMode !== undefined) {
5318
- const reduceOnly = this.safeValue(params, 'reduceOnly');
5319
- if (reduceOnly) {
5320
- request['sideEffectType'] = 'AUTO_REPAY';
5321
- params = this.omit(params, 'reduceOnly');
5476
+ if (!isPortfolioMargin) {
5477
+ const postOnly = this.isPostOnly(isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params);
5478
+ if (market['spot'] || marketType === 'margin') {
5479
+ // only supported for spot/margin api (all margin markets are spot markets)
5480
+ if (postOnly) {
5481
+ type = 'LIMIT_MAKER';
5482
+ }
5483
+ if (marginMode === 'isolated') {
5484
+ request['isIsolated'] = true;
5485
+ }
5486
+ }
5487
+ if (market['contract'] && postOnly) {
5488
+ request['timeInForce'] = 'GTX';
5322
5489
  }
5323
5490
  }
5491
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
5492
+ const stopLossPrice = this.safeString(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
5493
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
5494
+ const trailingDelta = this.safeString(params, 'trailingDelta');
5495
+ const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', this.numberToString(price));
5496
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
5497
+ const isTrailingPercentOrder = trailingPercent !== undefined;
5498
+ const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
5499
+ const isTakeProfit = takeProfitPrice !== undefined;
5500
+ const isTriggerOrder = triggerPrice !== undefined;
5501
+ const isConditional = isTriggerOrder || isTrailingPercentOrder || isStopLoss || isTakeProfit;
5502
+ const isPortfolioMarginConditional = (isPortfolioMargin && isConditional);
5324
5503
  let uppercaseType = type.toUpperCase();
5325
5504
  let stopPrice = undefined;
5326
5505
  if (isTrailingPercentOrder) {
@@ -5350,24 +5529,14 @@ export default class binance extends Exchange {
5350
5529
  uppercaseType = market['contract'] ? 'TAKE_PROFIT' : 'TAKE_PROFIT_LIMIT';
5351
5530
  }
5352
5531
  }
5353
- if (marginMode === 'isolated') {
5354
- request['isIsolated'] = true;
5355
- }
5356
- if (clientOrderId === undefined) {
5357
- const broker = this.safeValue(this.options, 'broker', {});
5358
- const defaultId = (market['contract']) ? 'x-xcKtGhcu' : 'x-R4BD3S82';
5359
- const brokerId = this.safeString(broker, marketType, defaultId);
5360
- request['newClientOrderId'] = brokerId + this.uuid22();
5361
- }
5362
- else {
5363
- request['newClientOrderId'] = clientOrderId;
5364
- }
5365
5532
  if ((marketType === 'spot') || (marketType === 'margin')) {
5366
- request['newOrderRespType'] = this.safeValue(this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5533
+ request['newOrderRespType'] = this.safeString(this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5367
5534
  }
5368
5535
  else {
5369
5536
  // swap, futures and options
5370
- request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK"
5537
+ if (!isPortfolioMargin) {
5538
+ request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK"
5539
+ }
5371
5540
  }
5372
5541
  if (market['option']) {
5373
5542
  if (type === 'market') {
@@ -5375,7 +5544,7 @@ export default class binance extends Exchange {
5375
5544
  }
5376
5545
  }
5377
5546
  else {
5378
- const validOrderTypes = this.safeValue(market['info'], 'orderTypes');
5547
+ const validOrderTypes = this.safeList(market['info'], 'orderTypes');
5379
5548
  if (!this.inArray(uppercaseType, validOrderTypes)) {
5380
5549
  if (initialUppercaseType !== uppercaseType) {
5381
5550
  throw new InvalidOrder(this.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders');
@@ -5385,7 +5554,18 @@ export default class binance extends Exchange {
5385
5554
  }
5386
5555
  }
5387
5556
  }
5388
- request['type'] = uppercaseType;
5557
+ const clientOrderIdRequest = isPortfolioMarginConditional ? 'newClientStrategyId' : 'newClientOrderId';
5558
+ if (clientOrderId === undefined) {
5559
+ const broker = this.safeDict(this.options, 'broker', {});
5560
+ const defaultId = (market['contract']) ? 'x-xcKtGhcu' : 'x-R4BD3S82';
5561
+ const brokerId = this.safeString(broker, marketType, defaultId);
5562
+ request[clientOrderIdRequest] = brokerId + this.uuid22();
5563
+ }
5564
+ else {
5565
+ request[clientOrderIdRequest] = clientOrderId;
5566
+ }
5567
+ const typeRequest = isPortfolioMarginConditional ? 'strategyType' : 'type';
5568
+ request[typeRequest] = uppercaseType;
5389
5569
  // additional required fields depending on the order type
5390
5570
  let timeInForceIsRequired = false;
5391
5571
  let priceIsRequired = false;
@@ -5413,9 +5593,9 @@ export default class binance extends Exchange {
5413
5593
  //
5414
5594
  if (uppercaseType === 'MARKET') {
5415
5595
  if (market['spot']) {
5416
- const quoteOrderQty = this.safeValue(this.options, 'quoteOrderQty', true);
5596
+ const quoteOrderQty = this.safeBool(this.options, 'quoteOrderQty', true);
5417
5597
  if (quoteOrderQty) {
5418
- const quoteOrderQtyNew = this.safeValue2(query, 'quoteOrderQty', 'cost');
5598
+ const quoteOrderQtyNew = this.safeString2(params, 'quoteOrderQty', 'cost');
5419
5599
  const precision = market['precision']['price'];
5420
5600
  if (quoteOrderQtyNew !== undefined) {
5421
5601
  request['quoteOrderQty'] = this.decimalToPrecision(quoteOrderQtyNew, TRUNCATE, precision, this.precisionMode);
@@ -5466,7 +5646,7 @@ export default class binance extends Exchange {
5466
5646
  priceIsRequired = true;
5467
5647
  }
5468
5648
  else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) {
5469
- const closePosition = this.safeValue(query, 'closePosition');
5649
+ const closePosition = this.safeBool(params, 'closePosition');
5470
5650
  if (closePosition === undefined) {
5471
5651
  quantityIsRequired = true;
5472
5652
  }
@@ -5479,7 +5659,13 @@ export default class binance extends Exchange {
5479
5659
  }
5480
5660
  }
5481
5661
  if (quantityIsRequired) {
5482
- request['quantity'] = this.amountToPrecision(symbol, amount);
5662
+ // portfolio margin has a different amount precision
5663
+ if (isPortfolioMargin) {
5664
+ request['quantity'] = this.parseToNumeric(amount);
5665
+ }
5666
+ else {
5667
+ request['quantity'] = this.amountToPrecision(symbol, amount);
5668
+ }
5483
5669
  }
5484
5670
  if (priceIsRequired) {
5485
5671
  if (price === undefined) {
@@ -5490,9 +5676,6 @@ export default class binance extends Exchange {
5490
5676
  if (timeInForceIsRequired) {
5491
5677
  request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
5492
5678
  }
5493
- if (market['contract'] && postOnly) {
5494
- request['timeInForce'] = 'GTX';
5495
- }
5496
5679
  if (stopPriceIsRequired) {
5497
5680
  if (market['contract']) {
5498
5681
  if (stopPrice === undefined) {
@@ -5509,11 +5692,26 @@ export default class binance extends Exchange {
5509
5692
  request['stopPrice'] = this.priceToPrecision(symbol, stopPrice);
5510
5693
  }
5511
5694
  }
5695
+ if (!isPortfolioMargin) {
5696
+ const postOnly = this.isPostOnly(isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params);
5697
+ if (market['spot'] || marketType === 'margin') {
5698
+ // only supported for spot/margin api (all margin markets are spot markets)
5699
+ if (postOnly) {
5700
+ type = 'LIMIT_MAKER';
5701
+ }
5702
+ if (marginMode === 'isolated') {
5703
+ request['isIsolated'] = true;
5704
+ }
5705
+ }
5706
+ if (market['contract'] && postOnly) {
5707
+ request['timeInForce'] = 'GTX';
5708
+ }
5709
+ }
5512
5710
  // remove timeInForce from params because PO is only used by this.isPostOnly and it's not a valid value for Binance
5513
5711
  if (this.safeString(params, 'timeInForce') === 'PO') {
5514
- params = this.omit(params, ['timeInForce']);
5712
+ params = this.omit(params, 'timeInForce');
5515
5713
  }
5516
- const requestParams = this.omit(params, ['quoteOrderQty', 'cost', 'stopPrice', 'test', 'type', 'newClientOrderId', 'clientOrderId', 'postOnly']);
5714
+ const requestParams = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test']);
5517
5715
  return this.extend(request, requestParams);
5518
5716
  }
5519
5717
  async createMarketOrderWithCost(symbol, side, cost, params = {}) {