ccxt 4.2.35 → 4.2.37

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.
@@ -4735,7 +4735,7 @@ class binance extends binance$1 {
4735
4735
  }
4736
4736
  request['price'] = this.priceToPrecision(symbol, price);
4737
4737
  }
4738
- if (timeInForceIsRequired) {
4738
+ if (timeInForceIsRequired && (this.safeString(params, 'timeInForce') === undefined)) {
4739
4739
  request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
4740
4740
  }
4741
4741
  if (stopPriceIsRequired) {
@@ -5040,20 +5040,156 @@ class binance extends binance$1 {
5040
5040
  // "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"},
5041
5041
  // "mmp": false
5042
5042
  // }
5043
- // {
5043
+ //
5044
5044
  // cancelOrders/createOrders
5045
- // "code": -4005,
5046
- // "msg": "Quantity greater than max quantity."
5047
- // },
5045
+ //
5046
+ // {
5047
+ // "code": -4005,
5048
+ // "msg": "Quantity greater than max quantity."
5049
+ // }
5050
+ //
5051
+ // createOrder, fetchOpenOrders: portfolio margin linear swap and future
5052
+ //
5053
+ // {
5054
+ // "symbol": "BTCUSDT",
5055
+ // "side": "BUY",
5056
+ // "executedQty": "0.000",
5057
+ // "orderId": 258649539704,
5058
+ // "goodTillDate": 0,
5059
+ // "avgPrice": "0",
5060
+ // "origQty": "0.010",
5061
+ // "clientOrderId": "x-xcKtGhcu02573c6f15e544e990057b",
5062
+ // "positionSide": "BOTH",
5063
+ // "cumQty": "0.000",
5064
+ // "updateTime": 1707110415436,
5065
+ // "type": "LIMIT",
5066
+ // "reduceOnly": false,
5067
+ // "price": "35000.00",
5068
+ // "cumQuote": "0.00000",
5069
+ // "selfTradePreventionMode": "NONE",
5070
+ // "timeInForce": "GTC",
5071
+ // "status": "NEW"
5072
+ // }
5073
+ //
5074
+ // createOrder, fetchOpenOrders: portfolio margin inverse swap and future
5075
+ //
5076
+ // {
5077
+ // "symbol": "ETHUSD_PERP",
5078
+ // "side": "BUY",
5079
+ // "cumBase": "0",
5080
+ // "executedQty": "0",
5081
+ // "orderId": 71275227732,
5082
+ // "avgPrice": "0.00",
5083
+ // "origQty": "1",
5084
+ // "clientOrderId": "x-xcKtGhcuca5af3acfb5044198c5398",
5085
+ // "positionSide": "BOTH",
5086
+ // "cumQty": "0",
5087
+ // "updateTime": 1707110994334,
5088
+ // "type": "LIMIT",
5089
+ // "pair": "ETHUSD",
5090
+ // "reduceOnly": false,
5091
+ // "price": "2000",
5092
+ // "timeInForce": "GTC",
5093
+ // "status": "NEW"
5094
+ // }
5095
+ //
5096
+ // createOrder, fetchOpenOrders: portfolio margin linear swap and future conditional
5097
+ //
5098
+ // {
5099
+ // "newClientStrategyId": "x-xcKtGhcu27f109953d6e4dc0974006",
5100
+ // "strategyId": 3645916,
5101
+ // "strategyStatus": "NEW",
5102
+ // "strategyType": "STOP",
5103
+ // "origQty": "0.010",
5104
+ // "price": "35000.00",
5105
+ // "reduceOnly": false,
5106
+ // "side": "BUY",
5107
+ // "positionSide": "BOTH",
5108
+ // "stopPrice": "45000.00",
5109
+ // "symbol": "BTCUSDT",
5110
+ // "timeInForce": "GTC",
5111
+ // "bookTime": 1707112625879,
5112
+ // "updateTime": 1707112625879,
5113
+ // "workingType": "CONTRACT_PRICE",
5114
+ // "priceProtect": false,
5115
+ // "goodTillDate": 0,
5116
+ // "selfTradePreventionMode": "NONE"
5117
+ // }
5118
+ //
5119
+ // createOrder, fetchOpenOrders: portfolio margin inverse swap and future conditional
5120
+ //
5121
+ // {
5122
+ // "newClientStrategyId": "x-xcKtGhcuc6b86f053bb34933850739",
5123
+ // "strategyId": 1423462,
5124
+ // "strategyStatus": "NEW",
5125
+ // "strategyType": "STOP",
5126
+ // "origQty": "1",
5127
+ // "price": "2000",
5128
+ // "reduceOnly": false,
5129
+ // "side": "BUY",
5130
+ // "positionSide": "BOTH",
5131
+ // "stopPrice": "3000",
5132
+ // "symbol": "ETHUSD_PERP",
5133
+ // "timeInForce": "GTC",
5134
+ // "bookTime": 1707113098840,
5135
+ // "updateTime": 1707113098840,
5136
+ // "workingType": "CONTRACT_PRICE",
5137
+ // "priceProtect": false
5138
+ // }
5139
+ //
5140
+ // createOrder, cancelAllOrders: portfolio margin spot margin
5141
+ //
5142
+ // {
5143
+ // "clientOrderId": "x-R4BD3S82e9ef29d8346440f0b28b86",
5144
+ // "cummulativeQuoteQty": "0.00000000",
5145
+ // "executedQty": "0.00000000",
5146
+ // "fills": [],
5147
+ // "orderId": 24684460474,
5148
+ // "origQty": "0.00100000",
5149
+ // "price": "35000.00000000",
5150
+ // "selfTradePreventionMode": "EXPIRE_MAKER",
5151
+ // "side": "BUY",
5152
+ // "status": "NEW",
5153
+ // "symbol": "BTCUSDT",
5154
+ // "timeInForce": "GTC",
5155
+ // "transactTime": 1707113538870,
5156
+ // "type": "LIMIT"
5157
+ // }
5158
+ //
5159
+ // fetchOpenOrders: portfolio margin spot margin
5160
+ //
5161
+ // {
5162
+ // "symbol": "BTCUSDT",
5163
+ // "orderId": 24700763749,
5164
+ // "clientOrderId": "x-R4BD3S826f724c2a4af6425f98c7b6",
5165
+ // "price": "35000.00000000",
5166
+ // "origQty": "0.00100000",
5167
+ // "executedQty": "0.00000000",
5168
+ // "cummulativeQuoteQty": "0.00000000",
5169
+ // "status": "NEW",
5170
+ // "timeInForce": "GTC",
5171
+ // "type": "LIMIT",
5172
+ // "side": "BUY",
5173
+ // "stopPrice": "0.00000000",
5174
+ // "icebergQty": "0.00000000",
5175
+ // "time": 1707199187679,
5176
+ // "updateTime": 1707199187679,
5177
+ // "isWorking": true,
5178
+ // "accountId": 200180970,
5179
+ // "selfTradePreventionMode": "EXPIRE_MAKER",
5180
+ // "preventedMatchId": null,
5181
+ // "preventedQuantity": null
5182
+ // }
5048
5183
  //
5049
5184
  const code = this.safeString(order, 'code');
5050
5185
  if (code !== undefined) {
5051
5186
  // cancelOrders/createOrders might have a partial success
5052
5187
  return this.safeOrder({ 'info': order, 'status': 'rejected' }, market);
5053
5188
  }
5054
- const status = this.parseOrderStatus(this.safeString(order, 'status'));
5189
+ const status = this.parseOrderStatus(this.safeString2(order, 'status', 'strategyStatus'));
5055
5190
  const marketId = this.safeString(order, 'symbol');
5056
- const marketType = ('closePosition' in order) ? 'contract' : 'spot';
5191
+ const isContract = ('positionSide' in order) || ('cumQuote' in order);
5192
+ const marketType = isContract ? 'contract' : 'spot';
5057
5193
  const symbol = this.safeSymbol(marketId, market, undefined, marketType);
5058
5194
  const filled = this.safeString(order, 'executedQty', '0');
5059
5195
  const timestamp = this.safeIntegerN(order, ['time', 'createTime', 'workingTime', 'transactTime', 'updateTime']); // order of the keys matters here
@@ -5078,11 +5214,9 @@ class binance extends binance$1 {
5078
5214
  // Note this is not the actual cost, since Binance futures uses leverage to calculate margins.
5079
5215
  let cost = this.safeString2(order, 'cummulativeQuoteQty', 'cumQuote');
5080
5216
  cost = this.safeString(order, 'cumBase', cost);
5081
- const id = this.safeString(order, 'orderId');
5082
5217
  let type = this.safeStringLower(order, 'type');
5083
5218
  const side = this.safeStringLower(order, 'side');
5084
5219
  const fills = this.safeValue(order, 'fills', []);
5085
- const clientOrderId = this.safeString(order, 'clientOrderId');
5086
5220
  let timeInForce = this.safeString(order, 'timeInForce');
5087
5221
  if (timeInForce === 'GTX') {
5088
5222
  // GTX means "Good Till Crossing" and is an equivalent way of saying Post Only
@@ -5105,8 +5239,8 @@ class binance extends binance$1 {
5105
5239
  }
5106
5240
  return this.safeOrder({
5107
5241
  'info': order,
5108
- 'id': id,
5109
- 'clientOrderId': clientOrderId,
5242
+ 'id': this.safeString2(order, 'orderId', 'strategyId'),
5243
+ 'clientOrderId': this.safeString2(order, 'clientOrderId', 'newClientStrategyId'),
5110
5244
  'timestamp': timestamp,
5111
5245
  'datetime': this.iso8601(timestamp),
5112
5246
  'lastTradeTimestamp': lastTradeTimestamp,
@@ -5220,50 +5354,105 @@ class binance extends binance$1 {
5220
5354
  * @see https://binance-docs.github.io/apidocs/voptions/en/#new-order-trade
5221
5355
  * @see https://binance-docs.github.io/apidocs/spot/en/#new-order-using-sor-trade
5222
5356
  * @see https://binance-docs.github.io/apidocs/spot/en/#test-new-order-using-sor-trade
5357
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-um-order-trade
5358
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-cm-order-trade
5359
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-margin-order-trade
5360
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-um-conditional-order-trade
5361
+ * @see https://binance-docs.github.io/apidocs/pm/en/#new-cm-conditional-order-trade
5223
5362
  * @param {string} symbol unified symbol of the market to create an order in
5224
5363
  * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP'
5225
5364
  * @param {string} side 'buy' or 'sell'
5226
- * @param {float} amount how much of currency you want to trade in units of base currency
5227
- * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
5365
+ * @param {float} amount how much of you want to trade in units of the base currency
5366
+ * @param {float} [price] the price that the order is to be fullfilled, in units of the quote currency, ignored in market orders
5228
5367
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5368
+ * @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.
5229
5369
  * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
5230
5370
  * @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false
5231
5371
  * @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false
5232
5372
  * @param {float} [params.trailingPercent] the percent to trail away from the current market price
5233
5373
  * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
5374
+ * @param {float} [params.triggerPrice] the price that a trigger order is triggered at
5375
+ * @param {float} [params.stopLossPrice] the price that a stop loss order is triggered at
5376
+ * @param {float} [params.takeProfitPrice] the price that a take profit order is triggered at
5377
+ * @param {boolean} [params.portfolioMargin] set to true if you would like to create an order in a portfolio margin account
5234
5378
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
5235
5379
  */
5236
5380
  await this.loadMarkets();
5237
5381
  const market = this.market(symbol);
5238
5382
  const marketType = this.safeString(params, 'type', market['type']);
5239
- const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
5240
- const sor = this.safeValue2(params, 'sor', 'SOR', false);
5241
- params = this.omit(params, 'sor', 'SOR');
5383
+ let marginMode = undefined;
5384
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
5385
+ let isPortfolioMargin = undefined;
5386
+ [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'createOrder', 'papi', 'portfolioMargin', false);
5387
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
5388
+ const stopLossPrice = this.safeString(params, 'stopLossPrice');
5389
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
5390
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
5391
+ const isTrailingPercentOrder = trailingPercent !== undefined;
5392
+ const isStopLoss = stopLossPrice !== undefined;
5393
+ const isTakeProfit = takeProfitPrice !== undefined;
5394
+ const isConditional = (triggerPrice !== undefined) || isTrailingPercentOrder || isStopLoss || isTakeProfit;
5395
+ const sor = this.safeBool2(params, 'sor', 'SOR', false);
5396
+ const test = this.safeBool(params, 'test', false);
5397
+ params = this.omit(params, ['sor', 'SOR', 'test']);
5398
+ if (isPortfolioMargin) {
5399
+ params['portfolioMargin'] = isPortfolioMargin;
5400
+ }
5242
5401
  const request = this.createOrderRequest(symbol, type, side, amount, price, params);
5243
- let method = 'privatePostOrder';
5244
- if (sor) {
5245
- method = 'privatePostSorOrder';
5402
+ let response = undefined;
5403
+ if (market['option']) {
5404
+ response = await this.eapiPrivatePostOrder(request);
5405
+ }
5406
+ else if (sor) {
5407
+ if (test) {
5408
+ response = await this.privatePostSorOrderTest(request);
5409
+ }
5410
+ else {
5411
+ response = await this.privatePostSorOrder(request);
5412
+ }
5246
5413
  }
5247
5414
  else if (market['linear']) {
5248
- method = 'fapiPrivatePostOrder';
5415
+ if (isPortfolioMargin) {
5416
+ if (isConditional) {
5417
+ response = await this.papiPostUmConditionalOrder(request);
5418
+ }
5419
+ else {
5420
+ response = await this.papiPostUmOrder(request);
5421
+ }
5422
+ }
5423
+ else {
5424
+ response = await this.fapiPrivatePostOrder(request);
5425
+ }
5249
5426
  }
5250
5427
  else if (market['inverse']) {
5251
- method = 'dapiPrivatePostOrder';
5428
+ if (isPortfolioMargin) {
5429
+ if (isConditional) {
5430
+ response = await this.papiPostCmConditionalOrder(request);
5431
+ }
5432
+ else {
5433
+ response = await this.papiPostCmOrder(request);
5434
+ }
5435
+ }
5436
+ else {
5437
+ response = await this.dapiPrivatePostOrder(request);
5438
+ }
5252
5439
  }
5253
5440
  else if (marketType === 'margin' || marginMode !== undefined) {
5254
- method = 'sapiPostMarginOrder';
5255
- }
5256
- if (market['option']) {
5257
- method = 'eapiPrivatePostOrder';
5441
+ if (isPortfolioMargin) {
5442
+ response = await this.papiPostMarginOrder(request);
5443
+ }
5444
+ else {
5445
+ response = await this.sapiPostMarginOrder(request);
5446
+ }
5258
5447
  }
5259
- // support for testing orders
5260
- if (market['spot'] || marketType === 'margin') {
5261
- const test = this.safeBool(query, 'test', false);
5448
+ else {
5262
5449
  if (test) {
5263
- method += 'Test';
5450
+ response = await this.privatePostOrderTest(request);
5451
+ }
5452
+ else {
5453
+ response = await this.privatePostOrder(request);
5264
5454
  }
5265
5455
  }
5266
- const response = await this[method](request);
5267
5456
  return this.parseOrder(response, market);
5268
5457
  }
5269
5458
  createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
@@ -5271,16 +5460,13 @@ class binance extends binance$1 {
5271
5460
  * @method
5272
5461
  * @ignore
5273
5462
  * @name binance#createOrderRequest
5274
- * @description helper function to build request
5463
+ * @description helper function to build the request
5275
5464
  * @param {string} symbol unified symbol of the market to create an order in
5276
- * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP'
5465
+ * @param {string} type 'market' or 'limit'
5277
5466
  * @param {string} side 'buy' or 'sell'
5278
- * @param {float} amount how much of currency you want to trade in units of base currency
5279
- * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
5280
- * @param {object} params extra parameters specific to the exchange API endpoint
5281
- * @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading
5282
- * @param {float} [params.trailingPercent] the percent to trail away from the current market price
5283
- * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
5467
+ * @param {float} amount how much you want to trade in units of the base currency
5468
+ * @param {float} [price] the price that the order is to be fullfilled, in units of the quote currency, ignored in market orders
5469
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
5284
5470
  * @returns {object} request to be sent to the exchange
5285
5471
  */
5286
5472
  const market = this.market(symbol);
@@ -5289,35 +5475,39 @@ class binance extends binance$1 {
5289
5475
  const initialUppercaseType = type.toUpperCase();
5290
5476
  const isMarketOrder = initialUppercaseType === 'MARKET';
5291
5477
  const isLimitOrder = initialUppercaseType === 'LIMIT';
5292
- const postOnly = this.isPostOnly(isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params);
5293
- const triggerPrice = this.safeValue2(params, 'triggerPrice', 'stopPrice');
5294
- const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
5295
- const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
5296
- const trailingDelta = this.safeValue(params, 'trailingDelta');
5297
- const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', this.numberToString(price));
5298
- const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
5299
- const isTrailingPercentOrder = trailingPercent !== undefined;
5300
- const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
5301
- const isTakeProfit = takeProfitPrice !== undefined;
5302
- params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent']);
5303
- const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
5304
5478
  const request = {
5305
5479
  'symbol': market['id'],
5306
5480
  'side': side.toUpperCase(),
5307
5481
  };
5308
- if (market['spot'] || marketType === 'margin') {
5309
- // only supported for spot/margin api (all margin markets are spot markets)
5310
- if (postOnly) {
5311
- type = 'LIMIT_MAKER';
5482
+ let isPortfolioMargin = undefined;
5483
+ [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'createOrder', 'papi', 'portfolioMargin', false);
5484
+ let marginMode = undefined;
5485
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
5486
+ if ((marketType === 'margin') || (marginMode !== undefined) || market['option']) {
5487
+ // for swap and future reduceOnly is a string that cant be sent with close position set to true or in hedge mode
5488
+ const reduceOnly = this.safeBool(params, 'reduceOnly', false);
5489
+ params = this.omit(params, 'reduceOnly');
5490
+ if (market['option']) {
5491
+ request['reduceOnly'] = reduceOnly;
5312
5492
  }
5313
- }
5314
- if (marketType === 'margin' || marginMode !== undefined) {
5315
- const reduceOnly = this.safeValue(params, 'reduceOnly');
5316
- if (reduceOnly) {
5317
- request['sideEffectType'] = 'AUTO_REPAY';
5318
- params = this.omit(params, 'reduceOnly');
5493
+ else {
5494
+ if (reduceOnly) {
5495
+ request['sideEffectType'] = 'AUTO_REPAY';
5496
+ }
5319
5497
  }
5320
5498
  }
5499
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
5500
+ const stopLossPrice = this.safeString(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
5501
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
5502
+ const trailingDelta = this.safeString(params, 'trailingDelta');
5503
+ const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', this.numberToString(price));
5504
+ const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
5505
+ const isTrailingPercentOrder = trailingPercent !== undefined;
5506
+ const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
5507
+ const isTakeProfit = takeProfitPrice !== undefined;
5508
+ const isTriggerOrder = triggerPrice !== undefined;
5509
+ const isConditional = isTriggerOrder || isTrailingPercentOrder || isStopLoss || isTakeProfit;
5510
+ const isPortfolioMarginConditional = (isPortfolioMargin && isConditional);
5321
5511
  let uppercaseType = type.toUpperCase();
5322
5512
  let stopPrice = undefined;
5323
5513
  if (isTrailingPercentOrder) {
@@ -5347,24 +5537,14 @@ class binance extends binance$1 {
5347
5537
  uppercaseType = market['contract'] ? 'TAKE_PROFIT' : 'TAKE_PROFIT_LIMIT';
5348
5538
  }
5349
5539
  }
5350
- if (marginMode === 'isolated') {
5351
- request['isIsolated'] = true;
5352
- }
5353
- if (clientOrderId === undefined) {
5354
- const broker = this.safeValue(this.options, 'broker', {});
5355
- const defaultId = (market['contract']) ? 'x-xcKtGhcu' : 'x-R4BD3S82';
5356
- const brokerId = this.safeString(broker, marketType, defaultId);
5357
- request['newClientOrderId'] = brokerId + this.uuid22();
5358
- }
5359
- else {
5360
- request['newClientOrderId'] = clientOrderId;
5361
- }
5362
5540
  if ((marketType === 'spot') || (marketType === 'margin')) {
5363
- request['newOrderRespType'] = this.safeValue(this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5541
+ request['newOrderRespType'] = this.safeString(this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5364
5542
  }
5365
5543
  else {
5366
5544
  // swap, futures and options
5367
- request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK"
5545
+ if (!isPortfolioMargin) {
5546
+ request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK"
5547
+ }
5368
5548
  }
5369
5549
  if (market['option']) {
5370
5550
  if (type === 'market') {
@@ -5372,7 +5552,7 @@ class binance extends binance$1 {
5372
5552
  }
5373
5553
  }
5374
5554
  else {
5375
- const validOrderTypes = this.safeValue(market['info'], 'orderTypes');
5555
+ const validOrderTypes = this.safeList(market['info'], 'orderTypes');
5376
5556
  if (!this.inArray(uppercaseType, validOrderTypes)) {
5377
5557
  if (initialUppercaseType !== uppercaseType) {
5378
5558
  throw new errors.InvalidOrder(this.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders');
@@ -5382,7 +5562,31 @@ class binance extends binance$1 {
5382
5562
  }
5383
5563
  }
5384
5564
  }
5385
- request['type'] = uppercaseType;
5565
+ const clientOrderIdRequest = isPortfolioMarginConditional ? 'newClientStrategyId' : 'newClientOrderId';
5566
+ if (clientOrderId === undefined) {
5567
+ const broker = this.safeDict(this.options, 'broker', {});
5568
+ const defaultId = (market['contract']) ? 'x-xcKtGhcu' : 'x-R4BD3S82';
5569
+ const brokerId = this.safeString(broker, marketType, defaultId);
5570
+ request[clientOrderIdRequest] = brokerId + this.uuid22();
5571
+ }
5572
+ else {
5573
+ request[clientOrderIdRequest] = clientOrderId;
5574
+ }
5575
+ let postOnly = undefined;
5576
+ if (!isPortfolioMargin) {
5577
+ postOnly = this.isPostOnly(isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params);
5578
+ if (market['spot'] || marketType === 'margin') {
5579
+ // only supported for spot/margin api (all margin markets are spot markets)
5580
+ if (postOnly) {
5581
+ uppercaseType = 'LIMIT_MAKER';
5582
+ }
5583
+ if (marginMode === 'isolated') {
5584
+ request['isIsolated'] = true;
5585
+ }
5586
+ }
5587
+ }
5588
+ const typeRequest = isPortfolioMarginConditional ? 'strategyType' : 'type';
5589
+ request[typeRequest] = uppercaseType;
5386
5590
  // additional required fields depending on the order type
5387
5591
  let timeInForceIsRequired = false;
5388
5592
  let priceIsRequired = false;
@@ -5410,9 +5614,9 @@ class binance extends binance$1 {
5410
5614
  //
5411
5615
  if (uppercaseType === 'MARKET') {
5412
5616
  if (market['spot']) {
5413
- const quoteOrderQty = this.safeValue(this.options, 'quoteOrderQty', true);
5617
+ const quoteOrderQty = this.safeBool(this.options, 'quoteOrderQty', true);
5414
5618
  if (quoteOrderQty) {
5415
- const quoteOrderQtyNew = this.safeValue2(query, 'quoteOrderQty', 'cost');
5619
+ const quoteOrderQtyNew = this.safeString2(params, 'quoteOrderQty', 'cost');
5416
5620
  const precision = market['precision']['price'];
5417
5621
  if (quoteOrderQtyNew !== undefined) {
5418
5622
  request['quoteOrderQty'] = this.decimalToPrecision(quoteOrderQtyNew, number.TRUNCATE, precision, this.precisionMode);
@@ -5463,7 +5667,7 @@ class binance extends binance$1 {
5463
5667
  priceIsRequired = true;
5464
5668
  }
5465
5669
  else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) {
5466
- const closePosition = this.safeValue(query, 'closePosition');
5670
+ const closePosition = this.safeBool(params, 'closePosition');
5467
5671
  if (closePosition === undefined) {
5468
5672
  quantityIsRequired = true;
5469
5673
  }
@@ -5476,7 +5680,13 @@ class binance extends binance$1 {
5476
5680
  }
5477
5681
  }
5478
5682
  if (quantityIsRequired) {
5479
- request['quantity'] = this.amountToPrecision(symbol, amount);
5683
+ // portfolio margin has a different amount precision
5684
+ if (isPortfolioMargin) {
5685
+ request['quantity'] = this.parseToNumeric(amount);
5686
+ }
5687
+ else {
5688
+ request['quantity'] = this.amountToPrecision(symbol, amount);
5689
+ }
5480
5690
  }
5481
5691
  if (priceIsRequired) {
5482
5692
  if (price === undefined) {
@@ -5484,12 +5694,6 @@ class binance extends binance$1 {
5484
5694
  }
5485
5695
  request['price'] = this.priceToPrecision(symbol, price);
5486
5696
  }
5487
- if (timeInForceIsRequired) {
5488
- request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
5489
- }
5490
- if (market['contract'] && postOnly) {
5491
- request['timeInForce'] = 'GTX';
5492
- }
5493
5697
  if (stopPriceIsRequired) {
5494
5698
  if (market['contract']) {
5495
5699
  if (stopPrice === undefined) {
@@ -5506,11 +5710,17 @@ class binance extends binance$1 {
5506
5710
  request['stopPrice'] = this.priceToPrecision(symbol, stopPrice);
5507
5711
  }
5508
5712
  }
5713
+ if (timeInForceIsRequired && (this.safeString(params, 'timeInForce') === undefined)) {
5714
+ request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
5715
+ }
5716
+ if (!isPortfolioMargin && market['contract'] && postOnly) {
5717
+ request['timeInForce'] = 'GTX';
5718
+ }
5509
5719
  // remove timeInForce from params because PO is only used by this.isPostOnly and it's not a valid value for Binance
5510
5720
  if (this.safeString(params, 'timeInForce') === 'PO') {
5511
- params = this.omit(params, ['timeInForce']);
5721
+ params = this.omit(params, 'timeInForce');
5512
5722
  }
5513
- const requestParams = this.omit(params, ['quoteOrderQty', 'cost', 'stopPrice', 'test', 'type', 'newClientOrderId', 'clientOrderId', 'postOnly']);
5723
+ const requestParams = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test']);
5514
5724
  return this.extend(request, requestParams);
5515
5725
  }
5516
5726
  async createMarketOrderWithCost(symbol, side, cost, params = {}) {
@@ -5776,21 +5986,28 @@ class binance extends binance$1 {
5776
5986
  /**
5777
5987
  * @method
5778
5988
  * @name binance#fetchOpenOrders
5989
+ * @description fetch all unfilled currently open orders
5779
5990
  * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade
5780
5991
  * @see https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data
5781
5992
  * @see https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data
5782
5993
  * @see https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data
5783
- * @description fetch all unfilled currently open orders
5784
5994
  * @see https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data
5785
5995
  * @see https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data
5786
5996
  * @see https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data
5787
5997
  * @see https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data
5788
5998
  * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-orders-user_data
5999
+ * @see https://binance-docs.github.io/apidocs/pm/en/#query-all-current-um-open-orders-user_data
6000
+ * @see https://binance-docs.github.io/apidocs/pm/en/#query-all-current-cm-open-orders-user_data
6001
+ * @see https://binance-docs.github.io/apidocs/pm/en/#query-all-current-um-open-conditional-orders-user_data
6002
+ * @see https://binance-docs.github.io/apidocs/pm/en/#query-all-current-cm-open-conditional-orders-user_data
6003
+ * @see https://binance-docs.github.io/apidocs/pm/en/#query-current-margin-open-order-user_data
5789
6004
  * @param {string} symbol unified market symbol
5790
6005
  * @param {int} [since] the earliest time in ms to fetch open orders for
5791
6006
  * @param {int} [limit] the maximum number of open orders structures to retrieve
5792
6007
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5793
6008
  * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
6009
+ * @param {boolean} [params.portfolioMargin] set to true if you would like to fetch open orders in the portfolio margin account
6010
+ * @param {boolean} [params.stop] set to true if you would like to fetch portfolio margin account conditional orders
5794
6011
  * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
5795
6012
  */
5796
6013
  await this.loadMarkets();
@@ -5798,14 +6015,16 @@ class binance extends binance$1 {
5798
6015
  let type = undefined;
5799
6016
  const request = {};
5800
6017
  let marginMode = undefined;
5801
- let query = undefined;
5802
- [marginMode, query] = this.handleMarginModeAndParams('fetchOpenOrders', params);
6018
+ [marginMode, params] = this.handleMarginModeAndParams('fetchOpenOrders', params);
6019
+ let isPortfolioMargin = undefined;
6020
+ [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'fetchOpenOrders', 'papi', 'portfolioMargin', false);
6021
+ const isConditional = this.safeBool2(params, 'stop', 'conditional');
5803
6022
  if (symbol !== undefined) {
5804
6023
  market = this.market(symbol);
5805
6024
  request['symbol'] = market['id'];
5806
6025
  const defaultType = this.safeString2(this.options, 'fetchOpenOrders', 'defaultType', 'spot');
5807
6026
  const marketType = ('type' in market) ? market['type'] : defaultType;
5808
- type = this.safeString(query, 'type', marketType);
6027
+ type = this.safeString(params, 'type', marketType);
5809
6028
  }
5810
6029
  else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) {
5811
6030
  const symbols = this.symbols;
@@ -5815,11 +6034,11 @@ class binance extends binance$1 {
5815
6034
  }
5816
6035
  else {
5817
6036
  const defaultType = this.safeString2(this.options, 'fetchOpenOrders', 'defaultType', 'spot');
5818
- type = this.safeString(query, 'type', defaultType);
6037
+ type = this.safeString(params, 'type', defaultType);
5819
6038
  }
5820
6039
  let subType = undefined;
5821
- [subType, query] = this.handleSubTypeAndParams('fetchOpenOrders', market, query);
5822
- const requestParams = this.omit(query, 'type');
6040
+ [subType, params] = this.handleSubTypeAndParams('fetchOpenOrders', market, params);
6041
+ params = this.omit(params, ['type', 'stop', 'conditional']);
5823
6042
  let response = undefined;
5824
6043
  if (type === 'option') {
5825
6044
  if (since !== undefined) {
@@ -5828,25 +6047,50 @@ class binance extends binance$1 {
5828
6047
  if (limit !== undefined) {
5829
6048
  request['limit'] = limit;
5830
6049
  }
5831
- response = await this.eapiPrivateGetOpenOrders(this.extend(request, requestParams));
6050
+ response = await this.eapiPrivateGetOpenOrders(this.extend(request, params));
5832
6051
  }
5833
6052
  else if (this.isLinear(type, subType)) {
5834
- response = await this.fapiPrivateGetOpenOrders(this.extend(request, requestParams));
6053
+ if (isPortfolioMargin) {
6054
+ if (isConditional) {
6055
+ response = await this.papiGetUmConditionalOpenOrders(this.extend(request, params));
6056
+ }
6057
+ else {
6058
+ response = await this.papiGetUmOpenOrders(this.extend(request, params));
6059
+ }
6060
+ }
6061
+ else {
6062
+ response = await this.fapiPrivateGetOpenOrders(this.extend(request, params));
6063
+ }
5835
6064
  }
5836
6065
  else if (this.isInverse(type, subType)) {
5837
- response = await this.dapiPrivateGetOpenOrders(this.extend(request, requestParams));
6066
+ if (isPortfolioMargin) {
6067
+ if (isConditional) {
6068
+ response = await this.papiGetCmConditionalOpenOrders(this.extend(request, params));
6069
+ }
6070
+ else {
6071
+ response = await this.papiGetCmOpenOrders(this.extend(request, params));
6072
+ }
6073
+ }
6074
+ else {
6075
+ response = await this.dapiPrivateGetOpenOrders(this.extend(request, params));
6076
+ }
5838
6077
  }
5839
6078
  else if (type === 'margin' || marginMode !== undefined) {
5840
- if (marginMode === 'isolated') {
5841
- request['isIsolated'] = true;
5842
- if (symbol === undefined) {
5843
- throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires a symbol argument for isolated markets');
6079
+ if (isPortfolioMargin) {
6080
+ response = await this.papiGetMarginOpenOrders(this.extend(request, params));
6081
+ }
6082
+ else {
6083
+ if (marginMode === 'isolated') {
6084
+ request['isIsolated'] = true;
6085
+ if (symbol === undefined) {
6086
+ throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires a symbol argument for isolated markets');
6087
+ }
5844
6088
  }
6089
+ response = await this.sapiGetMarginOpenOrders(this.extend(request, params));
5845
6090
  }
5846
- response = await this.sapiGetMarginOpenOrders(this.extend(request, requestParams));
5847
6091
  }
5848
6092
  else {
5849
- response = await this.privateGetOpenOrders(this.extend(request, requestParams));
6093
+ response = await this.privateGetOpenOrders(this.extend(request, params));
5850
6094
  }
5851
6095
  return this.parseOrders(response, market, since, limit);
5852
6096
  }
@@ -5964,46 +6208,82 @@ class binance extends binance$1 {
5964
6208
  /**
5965
6209
  * @method
5966
6210
  * @name binance#cancelAllOrders
6211
+ * @description cancel all open orders in a market
5967
6212
  * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-all-open-orders-on-a-symbol-trade
5968
6213
  * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-all-open-orders-trade
5969
6214
  * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-all-open-orders-trade
5970
6215
  * @see https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-on-specific-symbol-trade
5971
6216
  * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade
5972
- * @description cancel all open orders in a market
6217
+ * @see https://binance-docs.github.io/apidocs/pm/en/#cancel-all-um-open-orders-trade
6218
+ * @see https://binance-docs.github.io/apidocs/pm/en/#cancel-all-cm-open-orders-trade
6219
+ * @see https://binance-docs.github.io/apidocs/pm/en/#cancel-all-um-open-conditional-orders-trade
6220
+ * @see https://binance-docs.github.io/apidocs/pm/en/#cancel-all-cm-open-conditional-orders-trade
6221
+ * @see https://binance-docs.github.io/apidocs/pm/en/#cancel-margin-account-all-open-orders-on-a-symbol-trade
5973
6222
  * @param {string} symbol unified market symbol of the market to cancel orders in
5974
6223
  * @param {object} [params] extra parameters specific to the exchange API endpoint
5975
6224
  * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
6225
+ * @param {boolean} [params.portfolioMargin] set to true if you would like to cancel orders in a portfolio margin account
6226
+ * @param {boolean} [params.stop] set to true if you would like to cancel portfolio margin account conditional orders
5976
6227
  * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
5977
6228
  */
5978
6229
  if (symbol === undefined) {
5979
- throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
6230
+ throw new errors.ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
5980
6231
  }
5981
6232
  await this.loadMarkets();
5982
6233
  const market = this.market(symbol);
5983
6234
  const request = {
5984
6235
  'symbol': market['id'],
5985
6236
  };
6237
+ let isPortfolioMargin = undefined;
6238
+ [isPortfolioMargin, params] = this.handleOptionAndParams2(params, 'cancelAllOrders', 'papi', 'portfolioMargin', false);
6239
+ const isConditional = this.safeBool2(params, 'stop', 'conditional');
5986
6240
  const type = this.safeString(params, 'type', market['type']);
5987
- params = this.omit(params, ['type']);
5988
- const [marginMode, query] = this.handleMarginModeAndParams('cancelAllOrders', params);
6241
+ params = this.omit(params, ['type', 'stop', 'conditional']);
6242
+ let marginMode = undefined;
6243
+ [marginMode, params] = this.handleMarginModeAndParams('cancelAllOrders', params);
5989
6244
  let response = undefined;
5990
6245
  if (market['option']) {
5991
- response = await this.eapiPrivateDeleteAllOpenOrders(this.extend(request, query));
6246
+ response = await this.eapiPrivateDeleteAllOpenOrders(this.extend(request, params));
5992
6247
  }
5993
6248
  else if (market['linear']) {
5994
- response = await this.fapiPrivateDeleteAllOpenOrders(this.extend(request, query));
6249
+ if (isPortfolioMargin) {
6250
+ if (isConditional) {
6251
+ response = await this.papiDeleteUmConditionalAllOpenOrders(this.extend(request, params));
6252
+ }
6253
+ else {
6254
+ response = await this.papiDeleteUmAllOpenOrders(this.extend(request, params));
6255
+ }
6256
+ }
6257
+ else {
6258
+ response = await this.fapiPrivateDeleteAllOpenOrders(this.extend(request, params));
6259
+ }
5995
6260
  }
5996
6261
  else if (market['inverse']) {
5997
- response = await this.dapiPrivateDeleteAllOpenOrders(this.extend(request, query));
6262
+ if (isPortfolioMargin) {
6263
+ if (isConditional) {
6264
+ response = await this.papiDeleteCmConditionalAllOpenOrders(this.extend(request, params));
6265
+ }
6266
+ else {
6267
+ response = await this.papiDeleteCmAllOpenOrders(this.extend(request, params));
6268
+ }
6269
+ }
6270
+ else {
6271
+ response = await this.dapiPrivateDeleteAllOpenOrders(this.extend(request, params));
6272
+ }
5998
6273
  }
5999
6274
  else if ((type === 'margin') || (marginMode !== undefined)) {
6000
- if (marginMode === 'isolated') {
6001
- request['isIsolated'] = true;
6275
+ if (isPortfolioMargin) {
6276
+ response = await this.papiDeleteMarginAllOpenOrders(this.extend(request, params));
6277
+ }
6278
+ else {
6279
+ if (marginMode === 'isolated') {
6280
+ request['isIsolated'] = true;
6281
+ }
6282
+ response = await this.sapiDeleteMarginOpenOrders(this.extend(request, params));
6002
6283
  }
6003
- response = await this.sapiDeleteMarginOpenOrders(this.extend(request, query));
6004
6284
  }
6005
6285
  else {
6006
- response = await this.privateDeleteOpenOrders(this.extend(request, query));
6286
+ response = await this.privateDeleteOpenOrders(this.extend(request, params));
6007
6287
  }
6008
6288
  if (Array.isArray(response)) {
6009
6289
  return this.parseOrders(response, market);