Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ccxt/ccxt
Browse files Browse the repository at this point in the history
  • Loading branch information
kroitor committed Jan 9, 2024
2 parents 5b65f53 + 3e33c2a commit 43aaacc
Show file tree
Hide file tree
Showing 279 changed files with 9,604 additions and 2,325 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Current feature list:

## Sponsored Promotion

[![BitMart Trading Journey Through CCXT – Win VIP Fee Rates and Dive into a $30,000 Rewards Pool](https://github-production-user-asset-6210df.s3.amazonaws.com/1294454/287287291-697bdaf6-6ded-4c53-abb5-511a37ffd1bb.jpg)](https://www.bitmart.com/activity/CCXT-Promotion?r=rQCFLh)
[![CCXT_APP_basic_mode_banner](https://github.com/ccxt/ccxt/assets/43336371/c112c89d-567a-4b03-bb4d-1ca7a07ae2f7)](https://x.woo.org/en/ccxt-competition-1)

## See Also

Expand Down Expand Up @@ -209,13 +209,13 @@ console.log(version, Object.keys(exchanges));

All-in-one browser bundle (dependencies included), served from a CDN of your choice:

* jsDelivr: https://cdn.jsdelivr.net/npm/[email protected].4/dist/ccxt.browser.js
* unpkg: https://unpkg.com/[email protected].4/dist/ccxt.browser.js
* jsDelivr: https://cdn.jsdelivr.net/npm/[email protected].11/dist/ccxt.browser.js
* unpkg: https://unpkg.com/[email protected].11/dist/ccxt.browser.js

CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.

```HTML
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected].4/dist/ccxt.browser.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected].11/dist/ccxt.browser.js"></script>
```

Creates a global `ccxt` object:
Expand Down
24 changes: 20 additions & 4 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ function run_tests {
if [ -z "$rest_pid" ]; then
if [ -z "$rest_args" ] || { [ -n "$rest_args" ] && [ "$rest_args" != "skip" ]; }; then
# shellcheck disable=SC2086
node test-commonjs.cjs && node run-tests --js --python-async --php-async $rest_args &
node test-commonjs.cjs && node run-tests --js --python-async --php-async --useProxy $rest_args &
local rest_pid=$!
fi
fi
if [ -z "$ws_pid" ]; then
if [ -z "$ws_args" ] || { [ -n "$ws_args" ] && [ "$ws_args" != "skip" ]; }; then
# shellcheck disable=SC2086
node run-tests --ws --js --python-async --php-async $ws_args &
node run-tests --ws --js --python-async --php-async --useProxy $ws_args &
local ws_pid=$!
fi
fi
Expand Down Expand Up @@ -176,12 +176,28 @@ if [ ${#REST_EXCHANGES[@]} -eq 0 ] && [ ${#WS_EXCHANGES[@]} -eq 0 ]; then
exit
fi

# run base tests (base js,py,php, brokerId and static-tests)
npm run test-base
# run base tests (base js,py,php, brokerId )
# npm run test-base
npm run test-js-base && npm run test-python-base && npm run test-php-base && npm run id-tests

# rest_args=${REST_EXCHANGES[*]} || "skip"
rest_args=$(IFS=" " ; echo "${REST_EXCHANGES[*]}") || "skip"
# ws_args=${WS_EXCHANGES[*]} || "skip"
ws_args=$(IFS=" " ; echo "${WS_EXCHANGES[*]}") || "skip"


#request static tests
for exchange in "${REST_EXCHANGES[@]}"; do
npm run request-js -- $exchange
npm run request-py -- $exchange
npm run request-php -- $exchange
done

#response static tests
for exchange in "${REST_EXCHANGES[@]}"; do
npm run response-js -- $exchange
npm run response-py -- $exchange
npm run response-php -- $exchange
done

run_tests "$rest_args" "$ws_args"
1 change: 1 addition & 0 deletions ccxt.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
require_once PATH_TO_CCXT . 'OnMaintenance.php';
require_once PATH_TO_CCXT . 'InvalidNonce.php';
require_once PATH_TO_CCXT . 'RequestTimeout.php';
require_once PATH_TO_CCXT . 'ExchangeClosedByUser.php';


require_once PATH_TO_WS_CCXT . 'ClientTrait.php';
Expand Down
1,209 changes: 948 additions & 261 deletions dist/ccxt.browser.js

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions dist/ccxt.browser.min.js

Large diffs are not rendered by default.

1,209 changes: 948 additions & 261 deletions dist/ccxt.bundle.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/cjs/ccxt.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ var woo$1 = require('./src/pro/woo.js');

//-----------------------------------------------------------------------------
// this is updated by vss.js when building
const version = '4.2.4';
const version = '4.2.11';
Exchange["default"].ccxtVersion = version;
const exchanges = {
'ace': ace,
Expand Down
8 changes: 7 additions & 1 deletion dist/cjs/src/alpaca.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,16 @@ class alpaca extends alpaca$1 {
//
const marketId = this.safeString(asset, 'symbol');
const parts = marketId.split('/');
const assetClass = this.safeString(asset, 'class');
const baseId = this.safeString(parts, 0);
const quoteId = this.safeString(parts, 1);
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
let quote = this.safeCurrencyCode(quoteId);
// Us equity markets do not include quote in symbol.
// We can safely coerce us_equity quote to USD
if (quote === undefined && assetClass === 'us_equity') {
quote = 'USD';
}
const symbol = base + '/' + quote;
const status = this.safeString(asset, 'status');
const active = (status === 'active');
Expand Down
65 changes: 55 additions & 10 deletions dist/cjs/src/base/Exchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -1231,10 +1231,15 @@ class Exchange {
const closedClients = [];
for (let i = 0; i < clients.length; i++) {
const client = clients[i];
delete this.clients[client.url];
client.error = new errors.ExchangeClosedByUser(this.id + ' closedByUser');
closedClients.push(client.close());
}
return Promise.all(closedClients);
await Promise.all(closedClients);
for (let i = 0; i < clients.length; i++) {
const client = clients[i];
delete this.clients[client.url];
}
return;
}
async loadOrderBook(client, messageHash, symbol, limit = undefined, params = {}) {
if (!(symbol in this.orderbooks)) {
Expand Down Expand Up @@ -1290,6 +1295,17 @@ class Exchange {
axolotl(payload, hexKey, ed25519) {
return crypto.axolotl(payload, hexKey, ed25519);
}
fixStringifiedJsonMembers(content) {
// used for instance in bingx
// when stringified json has members with their values also stringified, like:
// '{"code":0, "data":{"order":{"orderId":1742968678528512345,"symbol":"BTC-USDT", "takeProfit":"{\"type\":\"TAKE_PROFIT\",\"stopPrice\":43320.1}","reduceOnly":false}}}'
// we can fix with below manipulations
// @ts-ignore
let modifiedContent = content.replaceAll('\\', '');
modifiedContent = modifiedContent.replaceAll('"{', '{');
modifiedContent = modifiedContent.replaceAll('}"', '}');
return modifiedContent;
}
/* eslint-enable */
// ------------------------------------------------------------------------
// ########################################################################
Expand Down Expand Up @@ -2857,11 +2873,11 @@ class Exchange {
}
return result;
}
parseBidsAsks(bidasks, priceKey = 0, amountKey = 1) {
parseBidsAsks(bidasks, priceKey = 0, amountKey = 1, countOrIdKey = 2) {
bidasks = this.toArray(bidasks);
const result = [];
for (let i = 0; i < bidasks.length; i++) {
result.push(this.parseBidAsk(bidasks[i], priceKey, amountKey));
result.push(this.parseBidAsk(bidasks[i], priceKey, amountKey, countOrIdKey));
}
return result;
}
Expand Down Expand Up @@ -3030,9 +3046,9 @@ class Exchange {
const value = this.safeString2(dictionary, key1, key2);
return this.parseNumber(value, d);
}
parseOrderBook(orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1) {
const bids = this.parseBidsAsks(this.safeValue(orderbook, bidsKey, []), priceKey, amountKey);
const asks = this.parseBidsAsks(this.safeValue(orderbook, asksKey, []), priceKey, amountKey);
parseOrderBook(orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1, countOrIdKey = 2) {
const bids = this.parseBidsAsks(this.safeValue(orderbook, bidsKey, []), priceKey, amountKey, countOrIdKey);
const asks = this.parseBidsAsks(this.safeValue(orderbook, asksKey, []), priceKey, amountKey, countOrIdKey);
return {
'symbol': symbol,
'bids': this.sortBy(bids, 0, true),
Expand Down Expand Up @@ -3347,10 +3363,15 @@ class Exchange {
async fetchBidsAsks(symbols = undefined, params = {}) {
throw new errors.NotSupported(this.id + ' fetchBidsAsks() is not supported yet');
}
parseBidAsk(bidask, priceKey = 0, amountKey = 1) {
parseBidAsk(bidask, priceKey = 0, amountKey = 1, countOrIdKey = 2) {
const price = this.safeNumber(bidask, priceKey);
const amount = this.safeNumber(bidask, amountKey);
return [price, amount];
const countOrId = this.safeInteger(bidask, countOrIdKey);
const bidAsk = [price, amount];
if (countOrId !== undefined) {
bidAsk.push(countOrId);
}
return bidAsk;
}
safeCurrency(currencyId, currency = undefined) {
if ((currencyId === undefined) && (currency !== undefined)) {
Expand Down Expand Up @@ -3398,7 +3419,7 @@ class Exchange {
}
}
}
else if (delimiter !== undefined) {
else if (delimiter !== undefined && delimiter !== '') {
const parts = marketId.split(delimiter);
const partsLength = parts.length;
if (partsLength === 2) {
Expand Down Expand Up @@ -3559,6 +3580,30 @@ class Exchange {
}
return [value, params];
}
handleOptionAndParams2(params, methodName, methodName2, optionName, defaultValue = undefined) {
// This method can be used to obtain method specific properties, i.e: this.handleOptionAndParams (params, 'fetchPosition', 'marginMode', 'isolated')
const defaultOptionName = 'default' + this.capitalize(optionName); // we also need to check the 'defaultXyzWhatever'
// check if params contain the key
let value = this.safeValue2(params, optionName, defaultOptionName);
if (value !== undefined) {
params = this.omit(params, [optionName, defaultOptionName]);
}
else {
// check if exchange has properties for this method
const exchangeWideMethodOptions = this.safeValue2(this.options, methodName, methodName2);
if (exchangeWideMethodOptions !== undefined) {
// check if the option is defined inside this method's props
value = this.safeValue2(exchangeWideMethodOptions, optionName, defaultOptionName);
}
if (value === undefined) {
// if it's still undefined, check if global exchange-wide option exists
value = this.safeValue2(this.options, optionName, defaultOptionName);
}
// if it's still undefined, use the default value
value = (value !== undefined) ? value : defaultValue;
}
return [value, params];
}
handleOption(methodName, optionName, defaultValue = undefined) {
// eslint-disable-next-line no-unused-vars
const [result, empty] = this.handleOptionAndParams({}, methodName, optionName, defaultValue);
Expand Down
9 changes: 8 additions & 1 deletion dist/cjs/src/base/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ class ExchangeError extends Error {
this.name = 'ExchangeError';
}
}
class ExchangeClosedByUser extends Error {
constructor(message) {
super(message);
this.name = 'ExchangeClosedByUser';
}
}
class AuthenticationError extends ExchangeError {
constructor(message) {
super(message);
Expand Down Expand Up @@ -252,7 +258,7 @@ class RequestTimeout extends NetworkError {
// // Derived class hierarchy
// errorHierarchy
// )
const errors = { 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, ContractUnavailable, NoChange, OperationRejected, OperationFailed, ProxyError };
const errors = { BaseError, ExchangeClosedByUser, 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, ContractUnavailable, NoChange, OperationRejected, OperationFailed, ProxyError };

exports.AccountNotEnabled = AccountNotEnabled;
exports.AccountSuspended = AccountSuspended;
Expand All @@ -267,6 +273,7 @@ exports.CancelPending = CancelPending;
exports.ContractUnavailable = ContractUnavailable;
exports.DDoSProtection = DDoSProtection;
exports.DuplicateOrderId = DuplicateOrderId;
exports.ExchangeClosedByUser = ExchangeClosedByUser;
exports.ExchangeError = ExchangeError;
exports.ExchangeNotAvailable = ExchangeNotAvailable;
exports.InsufficientFunds = InsufficientFunds;
Expand Down
4 changes: 4 additions & 0 deletions dist/cjs/src/base/ws/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ class Client {
// todo: exception types for server-side disconnects
this.reset(new errors.NetworkError('connection closed by remote server, closing code ' + String(event.code)));
}
if (this.error instanceof errors.ExchangeClosedByUser) {
this.reset(this.error);
}
if (this.disconnected !== undefined) {
this.disconnected.resolve(true);
}
Expand All @@ -229,6 +232,7 @@ class Client {
const future = Future.Future();
if (platform.isNode) {
/* eslint-disable no-inner-declarations */
/* eslint-disable jsdoc/require-jsdoc */
function onSendComplete(error) {
if (error) {
future.reject(error);
Expand Down
30 changes: 24 additions & 6 deletions dist/cjs/src/binance.js
Original file line number Diff line number Diff line change
Expand Up @@ -3145,7 +3145,12 @@ class binance extends binance$1 {
response = await this.dapiPublicGetTickerBookTicker(params);
}
else {
response = await this.publicGetTickerBookTicker(params);
const request = {};
if (symbols !== undefined) {
const marketIds = this.marketIds(symbols);
request['symbols'] = this.json(marketIds);
}
response = await this.publicGetTickerBookTicker(this.extend(request, params));
}
return this.parseTickers(response, symbols);
}
Expand Down Expand Up @@ -4414,6 +4419,8 @@ class binance extends binance$1 {
* @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading
* @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false
* @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false
* @param {float} [params.trailingPercent] the percent to trail away from the current market price
* @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
await this.loadMarkets();
Expand Down Expand Up @@ -4462,6 +4469,8 @@ class binance extends binance$1 {
* @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
* @param {object} params extra parameters specific to the exchange API endpoint
* @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading
* @param {float} [params.trailingPercent] the percent to trail away from the current market price
* @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
* @returns {object} request to be sent to the exchange
*/
const market = this.market(symbol);
Expand All @@ -4475,9 +4484,12 @@ class binance extends binance$1 {
const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice); // fallback to stopLoss
const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
const trailingDelta = this.safeValue(params, 'trailingDelta');
const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice', price);
const trailingPercent = this.safeString2(params, 'trailingPercent', 'callbackRate');
const isTrailingPercentOrder = trailingPercent !== undefined;
const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
const isTakeProfit = takeProfitPrice !== undefined;
params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice']);
params = this.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent']);
const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params);
const request = {
'symbol': market['id'],
Expand All @@ -4498,7 +4510,14 @@ class binance extends binance$1 {
}
let uppercaseType = type.toUpperCase();
let stopPrice = undefined;
if (isStopLoss) {
if (isTrailingPercentOrder) {
uppercaseType = 'TRAILING_STOP_MARKET';
request['callbackRate'] = trailingPercent;
if (trailingTriggerPrice !== undefined) {
request['activationPrice'] = this.priceToPrecision(symbol, trailingTriggerPrice);
}
}
else if (isStopLoss) {
stopPrice = stopLossPrice;
if (isMarketOrder) {
// spot STOP_LOSS market orders are not a valid order type
Expand Down Expand Up @@ -4642,9 +4661,8 @@ class binance extends binance$1 {
}
else if (uppercaseType === 'TRAILING_STOP_MARKET') {
quantityIsRequired = true;
const callbackRate = this.safeNumber(query, 'callbackRate');
if (callbackRate === undefined) {
throw new errors.InvalidOrder(this.id + ' createOrder() requires a callbackRate extra param for a ' + type + ' order');
if (trailingPercent === undefined) {
throw new errors.InvalidOrder(this.id + ' createOrder() requires a trailingPercent param for a ' + type + ' order');
}
}
if (quantityIsRequired) {
Expand Down
Loading

0 comments on commit 43aaacc

Please sign in to comment.