ccxt 4.0.98 → 4.0.99

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/dist/cjs/ccxt.js CHANGED
@@ -180,7 +180,7 @@ var woo$1 = require('./src/pro/woo.js');
180
180
 
181
181
  //-----------------------------------------------------------------------------
182
182
  // this is updated by vss.js when building
183
- const version = '4.0.98';
183
+ const version = '4.0.99';
184
184
  Exchange["default"].ccxtVersion = version;
185
185
  const exchanges = {
186
186
  'ace': ace,
@@ -203,6 +203,7 @@ class exmo extends exmo$1 {
203
203
  'precisionMode': number.TICK_SIZE,
204
204
  'exceptions': {
205
205
  'exact': {
206
+ '140434': errors.BadRequest,
206
207
  '40005': errors.AuthenticationError,
207
208
  '40009': errors.InvalidNonce,
208
209
  '40015': errors.ExchangeError,
@@ -1382,34 +1383,42 @@ class exmo extends exmo$1 {
1382
1383
  * @name exmo#createOrder
1383
1384
  * @description create a trade order
1384
1385
  * @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#80daa469-ec59-4d0a-b229-6a311d8dd1cd
1386
+ * @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#de6f4321-eeac-468c-87f7-c4ad7062e265 // stop market
1387
+ * @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#3561b86c-9ff1-436e-8e68-ac926b7eb523 // margin
1385
1388
  * @param {string} symbol unified symbol of the market to create an order in
1386
1389
  * @param {string} type 'market' or 'limit'
1387
1390
  * @param {string} side 'buy' or 'sell'
1388
1391
  * @param {float} amount how much of currency you want to trade in units of base currency
1389
1392
  * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1390
1393
  * @param {object} [params] extra parameters specific to the exmo api endpoint
1394
+ * @param {float} [params.stopPrice] the price at which a trigger order is triggered at
1395
+ * @param {string} [params.timeInForce] *spot only* 'fok', 'ioc' or 'post_only'
1396
+ * @param {boolean} [params.postOnly] *spot only* true for post only orders
1391
1397
  * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
1392
1398
  */
1393
1399
  await this.loadMarkets();
1394
1400
  const market = this.market(symbol);
1395
- const prefix = (type === 'market') ? (type + '_') : '';
1396
- const orderType = prefix + side;
1397
1401
  const isMarket = (type === 'market') && (price === undefined);
1402
+ let marginMode = undefined;
1403
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
1404
+ if (marginMode === 'cross') {
1405
+ throw new errors.BadRequest(this.id + ' only supports isolated margin');
1406
+ }
1407
+ const isSpot = (marginMode !== 'isolated');
1408
+ const triggerPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'stop_price']);
1398
1409
  const request = {
1399
1410
  'pair': market['id'],
1400
1411
  // 'leverage': 2,
1401
1412
  'quantity': this.amountToPrecision(market['symbol'], amount),
1402
1413
  // spot - buy, sell, market_buy, market_sell, market_buy_total, market_sell_total
1403
1414
  // margin - limit_buy, limit_sell, market_buy, market_sell, stop_buy, stop_sell, stop_limit_buy, stop_limit_sell, trailing_stop_buy, trailing_stop_sell
1404
- 'type': orderType,
1405
- 'price': isMarket ? 0 : this.priceToPrecision(market['symbol'], price),
1406
1415
  // 'stop_price': this.priceToPrecision (symbol, stopPrice),
1407
1416
  // 'distance': 0, // distance for trailing stop orders
1408
1417
  // 'expire': 0, // expiration timestamp in UTC timezone for the order, unless expire is 0
1409
1418
  // 'client_id': 123, // optional, must be a positive integer
1410
1419
  // 'comment': '', // up to 50 latin symbols, whitespaces, underscores
1411
1420
  };
1412
- let method = 'privatePostOrderCreate';
1421
+ let method = isSpot ? 'privatePostOrderCreate' : 'privatePostMarginUserOrderCreate';
1413
1422
  let clientOrderId = this.safeValue2(params, 'client_id', 'clientOrderId');
1414
1423
  if (clientOrderId !== undefined) {
1415
1424
  clientOrderId = this.safeInteger2(params, 'client_id', 'clientOrderId');
@@ -1419,19 +1428,68 @@ class exmo extends exmo$1 {
1419
1428
  else {
1420
1429
  request['client_id'] = clientOrderId;
1421
1430
  }
1422
- params = this.omit(params, ['client_id', 'clientOrderId']);
1423
1431
  }
1424
- if ((type === 'stop') || (type === 'stop_limit') || (type === 'trailing_stop')) {
1425
- const stopPrice = this.safeNumber2(params, 'stop_price', 'stopPrice');
1426
- if (stopPrice === undefined) {
1427
- throw new errors.InvalidOrder(this.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order');
1432
+ const leverage = this.safeNumber(params, 'leverage');
1433
+ if (!isSpot && (leverage === undefined)) {
1434
+ throw new errors.ArgumentsRequired(this.id + ' createOrder requires an extra param params["leverage"] for margin orders');
1435
+ }
1436
+ params = this.omit(params, ['stopPrice', 'stop_price', 'triggerPrice', 'timeInForce', 'client_id', 'clientOrderId']);
1437
+ if (triggerPrice !== undefined) {
1438
+ if (isSpot) {
1439
+ if (type === 'limit') {
1440
+ throw new errors.BadRequest(this.id + ' createOrder () cannot create stop limit orders for spot, only stop market');
1441
+ }
1442
+ else {
1443
+ method = 'privatePostStopMarketOrderCreate';
1444
+ request['type'] = side;
1445
+ request['trigger_price'] = this.priceToPrecision(symbol, triggerPrice);
1446
+ }
1447
+ }
1448
+ else {
1449
+ request['stop_price'] = this.priceToPrecision(symbol, triggerPrice);
1450
+ if (type === 'limit') {
1451
+ request['type'] = 'stop_limit_' + side;
1452
+ }
1453
+ else if (type === 'market') {
1454
+ request['type'] = 'stop_' + side;
1455
+ }
1456
+ else {
1457
+ request['type'] = type;
1458
+ }
1459
+ }
1460
+ }
1461
+ else {
1462
+ if (isSpot) {
1463
+ const execType = this.safeString(params, 'exec_type');
1464
+ let isPostOnly = undefined;
1465
+ [isPostOnly, params] = this.handlePostOnly(type === 'market', execType === 'post_only', params);
1466
+ const timeInForce = this.safeString(params, 'timeInForce');
1467
+ request['price'] = isMarket ? 0 : this.priceToPrecision(market['symbol'], price);
1468
+ if (type === 'limit') {
1469
+ request['type'] = side;
1470
+ }
1471
+ else if (type === 'market') {
1472
+ request['type'] = 'market_' + side;
1473
+ }
1474
+ if (isPostOnly) {
1475
+ request['exec_type'] = 'post_only';
1476
+ }
1477
+ else if (timeInForce !== undefined) {
1478
+ request['exec_type'] = timeInForce;
1479
+ }
1428
1480
  }
1429
1481
  else {
1430
- params = this.omit(params, ['stopPrice', 'stop_price']);
1431
- request['stop_price'] = this.priceToPrecision(symbol, stopPrice);
1432
- method = 'privatePostMarginUserOrderCreate';
1482
+ if (type === 'limit' || type === 'market') {
1483
+ request['type'] = type + '_' + side;
1484
+ }
1485
+ else {
1486
+ request['type'] = type;
1487
+ }
1433
1488
  }
1434
1489
  }
1490
+ if (price !== undefined) {
1491
+ request['price'] = this.priceToPrecision(market['symbol'], price);
1492
+ }
1435
1493
  const response = await this[method](this.extend(request, params));
1436
1494
  return this.parseOrder(response, market);
1437
1495
  }
@@ -2240,6 +2298,19 @@ class exmo extends exmo$1 {
2240
2298
  if (response === undefined) {
2241
2299
  return undefined; // fallback to default error handler
2242
2300
  }
2301
+ if ('error' in response) {
2302
+ // error: {
2303
+ // code: '140434',
2304
+ // msg: "Your margin balance is not sufficient to place the order for '5 TON'. Please top up your margin wallet by '2.5 USDT'."
2305
+ // }
2306
+ const errorCode = this.safeValue(response, 'error', {});
2307
+ const messageError = this.safeString(errorCode, 'msg');
2308
+ const code = this.safeString(errorCode, 'code');
2309
+ const feedback = this.id + ' ' + body;
2310
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
2311
+ this.throwBroadlyMatchedException(this.exceptions['broad'], messageError, feedback);
2312
+ throw new errors.ExchangeError(feedback);
2313
+ }
2243
2314
  if (('result' in response) || ('errmsg' in response)) {
2244
2315
  //
2245
2316
  // {"result":false,"error":"Error 50052: Insufficient funds"}
package/js/ccxt.d.ts CHANGED
@@ -4,7 +4,7 @@ import * as functions from './src/base/functions.js';
4
4
  import * as errors from './src/base/errors.js';
5
5
  import { Market, Trade, Fee, Ticker, OrderBook, Order, Transaction, Tickers, Currency, Balance, DepositAddress, WithdrawalResponse, DepositAddressResponse, OHLCV, Balances, PartialBalances, Dictionary, MinMax, Position } from './src/base/types.js';
6
6
  import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending } from './src/base/errors.js';
7
- declare const version = "4.0.97";
7
+ declare const version = "4.0.98";
8
8
  import ace from './src/ace.js';
9
9
  import alpaca from './src/alpaca.js';
10
10
  import ascendex from './src/ascendex.js';
package/js/ccxt.js CHANGED
@@ -38,7 +38,7 @@ import * as errors from './src/base/errors.js';
38
38
  import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending } from './src/base/errors.js';
39
39
  //-----------------------------------------------------------------------------
40
40
  // this is updated by vss.js when building
41
- const version = '4.0.98';
41
+ const version = '4.0.99';
42
42
  Exchange.ccxtVersion = version;
43
43
  //-----------------------------------------------------------------------------
44
44
  import ace from './src/ace.js';
package/js/src/exmo.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import Exchange from './abstract/exmo.js';
9
- import { ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, OnMaintenance, RateLimitExceeded, BadRequest, PermissionDenied } from './base/errors.js';
9
+ import { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, OnMaintenance, RateLimitExceeded, BadRequest, PermissionDenied } from './base/errors.js';
10
10
  import { Precise } from './base/Precise.js';
11
11
  import { TICK_SIZE } from './base/functions/number.js';
12
12
  import { sha512 } from './static_dependencies/noble-hashes/sha512.js';
@@ -206,6 +206,7 @@ export default class exmo extends Exchange {
206
206
  'precisionMode': TICK_SIZE,
207
207
  'exceptions': {
208
208
  'exact': {
209
+ '140434': BadRequest,
209
210
  '40005': AuthenticationError,
210
211
  '40009': InvalidNonce,
211
212
  '40015': ExchangeError,
@@ -1385,34 +1386,42 @@ export default class exmo extends Exchange {
1385
1386
  * @name exmo#createOrder
1386
1387
  * @description create a trade order
1387
1388
  * @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#80daa469-ec59-4d0a-b229-6a311d8dd1cd
1389
+ * @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#de6f4321-eeac-468c-87f7-c4ad7062e265 // stop market
1390
+ * @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#3561b86c-9ff1-436e-8e68-ac926b7eb523 // margin
1388
1391
  * @param {string} symbol unified symbol of the market to create an order in
1389
1392
  * @param {string} type 'market' or 'limit'
1390
1393
  * @param {string} side 'buy' or 'sell'
1391
1394
  * @param {float} amount how much of currency you want to trade in units of base currency
1392
1395
  * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1393
1396
  * @param {object} [params] extra parameters specific to the exmo api endpoint
1397
+ * @param {float} [params.stopPrice] the price at which a trigger order is triggered at
1398
+ * @param {string} [params.timeInForce] *spot only* 'fok', 'ioc' or 'post_only'
1399
+ * @param {boolean} [params.postOnly] *spot only* true for post only orders
1394
1400
  * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
1395
1401
  */
1396
1402
  await this.loadMarkets();
1397
1403
  const market = this.market(symbol);
1398
- const prefix = (type === 'market') ? (type + '_') : '';
1399
- const orderType = prefix + side;
1400
1404
  const isMarket = (type === 'market') && (price === undefined);
1405
+ let marginMode = undefined;
1406
+ [marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
1407
+ if (marginMode === 'cross') {
1408
+ throw new BadRequest(this.id + ' only supports isolated margin');
1409
+ }
1410
+ const isSpot = (marginMode !== 'isolated');
1411
+ const triggerPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'stop_price']);
1401
1412
  const request = {
1402
1413
  'pair': market['id'],
1403
1414
  // 'leverage': 2,
1404
1415
  'quantity': this.amountToPrecision(market['symbol'], amount),
1405
1416
  // spot - buy, sell, market_buy, market_sell, market_buy_total, market_sell_total
1406
1417
  // margin - limit_buy, limit_sell, market_buy, market_sell, stop_buy, stop_sell, stop_limit_buy, stop_limit_sell, trailing_stop_buy, trailing_stop_sell
1407
- 'type': orderType,
1408
- 'price': isMarket ? 0 : this.priceToPrecision(market['symbol'], price),
1409
1418
  // 'stop_price': this.priceToPrecision (symbol, stopPrice),
1410
1419
  // 'distance': 0, // distance for trailing stop orders
1411
1420
  // 'expire': 0, // expiration timestamp in UTC timezone for the order, unless expire is 0
1412
1421
  // 'client_id': 123, // optional, must be a positive integer
1413
1422
  // 'comment': '', // up to 50 latin symbols, whitespaces, underscores
1414
1423
  };
1415
- let method = 'privatePostOrderCreate';
1424
+ let method = isSpot ? 'privatePostOrderCreate' : 'privatePostMarginUserOrderCreate';
1416
1425
  let clientOrderId = this.safeValue2(params, 'client_id', 'clientOrderId');
1417
1426
  if (clientOrderId !== undefined) {
1418
1427
  clientOrderId = this.safeInteger2(params, 'client_id', 'clientOrderId');
@@ -1422,19 +1431,68 @@ export default class exmo extends Exchange {
1422
1431
  else {
1423
1432
  request['client_id'] = clientOrderId;
1424
1433
  }
1425
- params = this.omit(params, ['client_id', 'clientOrderId']);
1426
1434
  }
1427
- if ((type === 'stop') || (type === 'stop_limit') || (type === 'trailing_stop')) {
1428
- const stopPrice = this.safeNumber2(params, 'stop_price', 'stopPrice');
1429
- if (stopPrice === undefined) {
1430
- throw new InvalidOrder(this.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order');
1435
+ const leverage = this.safeNumber(params, 'leverage');
1436
+ if (!isSpot && (leverage === undefined)) {
1437
+ throw new ArgumentsRequired(this.id + ' createOrder requires an extra param params["leverage"] for margin orders');
1438
+ }
1439
+ params = this.omit(params, ['stopPrice', 'stop_price', 'triggerPrice', 'timeInForce', 'client_id', 'clientOrderId']);
1440
+ if (triggerPrice !== undefined) {
1441
+ if (isSpot) {
1442
+ if (type === 'limit') {
1443
+ throw new BadRequest(this.id + ' createOrder () cannot create stop limit orders for spot, only stop market');
1444
+ }
1445
+ else {
1446
+ method = 'privatePostStopMarketOrderCreate';
1447
+ request['type'] = side;
1448
+ request['trigger_price'] = this.priceToPrecision(symbol, triggerPrice);
1449
+ }
1450
+ }
1451
+ else {
1452
+ request['stop_price'] = this.priceToPrecision(symbol, triggerPrice);
1453
+ if (type === 'limit') {
1454
+ request['type'] = 'stop_limit_' + side;
1455
+ }
1456
+ else if (type === 'market') {
1457
+ request['type'] = 'stop_' + side;
1458
+ }
1459
+ else {
1460
+ request['type'] = type;
1461
+ }
1462
+ }
1463
+ }
1464
+ else {
1465
+ if (isSpot) {
1466
+ const execType = this.safeString(params, 'exec_type');
1467
+ let isPostOnly = undefined;
1468
+ [isPostOnly, params] = this.handlePostOnly(type === 'market', execType === 'post_only', params);
1469
+ const timeInForce = this.safeString(params, 'timeInForce');
1470
+ request['price'] = isMarket ? 0 : this.priceToPrecision(market['symbol'], price);
1471
+ if (type === 'limit') {
1472
+ request['type'] = side;
1473
+ }
1474
+ else if (type === 'market') {
1475
+ request['type'] = 'market_' + side;
1476
+ }
1477
+ if (isPostOnly) {
1478
+ request['exec_type'] = 'post_only';
1479
+ }
1480
+ else if (timeInForce !== undefined) {
1481
+ request['exec_type'] = timeInForce;
1482
+ }
1431
1483
  }
1432
1484
  else {
1433
- params = this.omit(params, ['stopPrice', 'stop_price']);
1434
- request['stop_price'] = this.priceToPrecision(symbol, stopPrice);
1435
- method = 'privatePostMarginUserOrderCreate';
1485
+ if (type === 'limit' || type === 'market') {
1486
+ request['type'] = type + '_' + side;
1487
+ }
1488
+ else {
1489
+ request['type'] = type;
1490
+ }
1436
1491
  }
1437
1492
  }
1493
+ if (price !== undefined) {
1494
+ request['price'] = this.priceToPrecision(market['symbol'], price);
1495
+ }
1438
1496
  const response = await this[method](this.extend(request, params));
1439
1497
  return this.parseOrder(response, market);
1440
1498
  }
@@ -2243,6 +2301,19 @@ export default class exmo extends Exchange {
2243
2301
  if (response === undefined) {
2244
2302
  return undefined; // fallback to default error handler
2245
2303
  }
2304
+ if ('error' in response) {
2305
+ // error: {
2306
+ // code: '140434',
2307
+ // msg: "Your margin balance is not sufficient to place the order for '5 TON'. Please top up your margin wallet by '2.5 USDT'."
2308
+ // }
2309
+ const errorCode = this.safeValue(response, 'error', {});
2310
+ const messageError = this.safeString(errorCode, 'msg');
2311
+ const code = this.safeString(errorCode, 'code');
2312
+ const feedback = this.id + ' ' + body;
2313
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
2314
+ this.throwBroadlyMatchedException(this.exceptions['broad'], messageError, feedback);
2315
+ throw new ExchangeError(feedback);
2316
+ }
2246
2317
  if (('result' in response) || ('errmsg' in response)) {
2247
2318
  //
2248
2319
  // {"result":false,"error":"Error 50052: Insufficient funds"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.0.98",
3
+ "version": "4.0.99",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",