ccxt 4.2.61 → 4.2.62

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
@@ -177,7 +177,7 @@ var woo$1 = require('./src/pro/woo.js');
177
177
 
178
178
  //-----------------------------------------------------------------------------
179
179
  // this is updated by vss.js when building
180
- const version = '4.2.61';
180
+ const version = '4.2.62';
181
181
  Exchange["default"].ccxtVersion = version;
182
182
  const exchanges = {
183
183
  'ace': ace,
@@ -1340,6 +1340,23 @@ class bitget extends bitget$1 {
1340
1340
  'swap': {
1341
1341
  'method': 'publicMixGetV2MixMarketCandles', // or publicMixGetV2MixMarketHistoryCandles or publicMixGetV2MixMarketHistoryIndexCandles or publicMixGetV2MixMarketHistoryMarkCandles
1342
1342
  },
1343
+ 'maxDaysPerTimeframe': {
1344
+ '1m': 30,
1345
+ '3m': 30,
1346
+ '5m': 30,
1347
+ '10m': 52,
1348
+ '15m': 52,
1349
+ '30m': 52,
1350
+ '1h': 83,
1351
+ '2h': 120,
1352
+ '4h': 240,
1353
+ '6h': 360,
1354
+ '12h': 360,
1355
+ '1d': 360,
1356
+ '3d': 1000,
1357
+ '1w': 1000,
1358
+ '1M': 1000,
1359
+ },
1343
1360
  },
1344
1361
  'fetchTrades': {
1345
1362
  'spot': {
@@ -3291,10 +3308,11 @@ class bitget extends bitget$1 {
3291
3308
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
3292
3309
  */
3293
3310
  await this.loadMarkets();
3311
+ const maxLimit = 1000; // max 1000
3294
3312
  let paginate = false;
3295
3313
  [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate');
3296
3314
  if (paginate) {
3297
- return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
3315
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit);
3298
3316
  }
3299
3317
  const sandboxMode = this.safeBool(this.options, 'sandboxMode', false);
3300
3318
  let market = undefined;
@@ -3308,35 +3326,53 @@ class bitget extends bitget$1 {
3308
3326
  const marketType = market['spot'] ? 'spot' : 'swap';
3309
3327
  const timeframes = this.options['timeframes'][marketType];
3310
3328
  const selectedTimeframe = this.safeString(timeframes, timeframe, timeframe);
3329
+ const duration = this.parseTimeframe(timeframe) * 1000;
3311
3330
  const request = {
3312
3331
  'symbol': market['id'],
3313
3332
  'granularity': selectedTimeframe,
3314
3333
  };
3315
- const until = this.safeInteger2(params, 'until', 'till');
3316
- params = this.omit(params, ['until', 'till']);
3334
+ const defaultLimit = 100; // by default, exchange returns 100 items
3335
+ const msInDay = 1000 * 60 * 60 * 24;
3317
3336
  if (limit !== undefined) {
3337
+ limit = Math.min(limit, maxLimit);
3318
3338
  request['limit'] = limit;
3319
3339
  }
3320
- if (since !== undefined) {
3321
- request['startTime'] = since;
3340
+ const until = this.safeInteger2(params, 'until', 'till');
3341
+ params = this.omit(params, ['until', 'till']);
3342
+ if (until !== undefined) {
3343
+ request['endTime'] = until;
3322
3344
  }
3323
3345
  if (since !== undefined) {
3324
- if (limit === undefined) {
3325
- limit = 100; // exchange default
3346
+ request['startTime'] = since;
3347
+ if (market['spot'] && (until === undefined)) {
3348
+ // for spot we need to send "entTime" too
3349
+ const limitForEnd = (limit !== undefined) ? limit : defaultLimit;
3350
+ const calculatedEnd = this.sum(since, duration * limitForEnd);
3351
+ request['endTime'] = calculatedEnd;
3326
3352
  }
3327
- const duration = this.parseTimeframe(timeframe) * 1000;
3328
- request['endTime'] = this.sum(since, duration * (limit + 1)) - 1; // limit + 1)) - 1 is needed for when since is not the exact timestamp of a candle
3329
- }
3330
- else if (until !== undefined) {
3331
- request['endTime'] = until;
3332
- }
3333
- else {
3334
- request['endTime'] = this.milliseconds();
3335
3353
  }
3336
3354
  let response = undefined;
3337
- const thirtyOneDaysAgo = this.milliseconds() - 2678400000;
3355
+ const now = this.milliseconds();
3356
+ // retrievable periods listed here:
3357
+ // - https://www.bitget.com/api-doc/spot/market/Get-Candle-Data#request-parameters
3358
+ // - https://www.bitget.com/api-doc/contract/market/Get-Candle-Data#description
3359
+ const ohlcOptions = this.safeDict(this.options, 'fetchOHLCV', {});
3360
+ const retrievableDaysMap = this.safeDict(ohlcOptions, 'maxDaysPerTimeframe', {});
3361
+ const maxRetrievableDaysForNonHistory = this.safeInteger(retrievableDaysMap, timeframe, 30); // default to safe minimum
3362
+ const endpointTsBoundary = now - maxRetrievableDaysForNonHistory * msInDay;
3363
+ // checks if we need history endpoint
3364
+ let needsHistoryEndpoint = false;
3365
+ const displaceByLimit = (limit === undefined) ? 0 : limit * duration;
3366
+ if (since !== undefined && since < endpointTsBoundary) {
3367
+ // if since it earlier than the allowed diapason
3368
+ needsHistoryEndpoint = true;
3369
+ }
3370
+ else if (until !== undefined && until - displaceByLimit < endpointTsBoundary) {
3371
+ // if until is earlier than the allowed diapason
3372
+ needsHistoryEndpoint = true;
3373
+ }
3338
3374
  if (market['spot']) {
3339
- if ((since !== undefined) && (since < thirtyOneDaysAgo)) {
3375
+ if (needsHistoryEndpoint) {
3340
3376
  response = await this.publicSpotGetV2SpotMarketHistoryCandles(this.extend(request, params));
3341
3377
  }
3342
3378
  else {
@@ -3344,22 +3380,37 @@ class bitget extends bitget$1 {
3344
3380
  }
3345
3381
  }
3346
3382
  else {
3383
+ const maxDistanceDaysForContracts = 90; // maximum 90 days allowed between start-end times
3384
+ let distanceError = false;
3385
+ if (limit !== undefined && limit * duration > maxDistanceDaysForContracts * msInDay) {
3386
+ distanceError = true;
3387
+ }
3388
+ else if (since !== undefined && until !== undefined && until - since > maxDistanceDaysForContracts * msInDay) {
3389
+ distanceError = true;
3390
+ }
3391
+ if (distanceError) {
3392
+ throw new errors.BadRequest(this.id + ' fetchOHLCV() between start and end must be less than ' + maxDistanceDaysForContracts.toString() + ' days');
3393
+ }
3347
3394
  const priceType = this.safeString(params, 'price');
3348
3395
  params = this.omit(params, ['price']);
3349
3396
  let productType = undefined;
3350
3397
  [productType, params] = this.handleProductTypeAndParams(market, params);
3351
3398
  request['productType'] = productType;
3399
+ const extended = this.extend(request, params);
3400
+ // todo: mark & index also have their "recent" endpoints, but not priority now.
3352
3401
  if (priceType === 'mark') {
3353
- response = await this.publicMixGetV2MixMarketHistoryMarkCandles(this.extend(request, params));
3402
+ response = await this.publicMixGetV2MixMarketHistoryMarkCandles(extended);
3354
3403
  }
3355
3404
  else if (priceType === 'index') {
3356
- response = await this.publicMixGetV2MixMarketHistoryIndexCandles(this.extend(request, params));
3357
- }
3358
- else if ((since !== undefined) && (since < thirtyOneDaysAgo)) {
3359
- response = await this.publicMixGetV2MixMarketHistoryCandles(this.extend(request, params));
3405
+ response = await this.publicMixGetV2MixMarketHistoryIndexCandles(extended);
3360
3406
  }
3361
3407
  else {
3362
- response = await this.publicMixGetV2MixMarketCandles(this.extend(request, params));
3408
+ if (needsHistoryEndpoint) {
3409
+ response = await this.publicMixGetV2MixMarketHistoryCandles(extended);
3410
+ }
3411
+ else {
3412
+ response = await this.publicMixGetV2MixMarketCandles(extended);
3413
+ }
3363
3414
  }
3364
3415
  }
3365
3416
  if (response === '') {
@@ -128,7 +128,7 @@ class hyperliquid extends hyperliquid$1 {
128
128
  },
129
129
  'hostname': 'hyperliquid.xyz',
130
130
  'urls': {
131
- 'logo': 'https://private-user-images.githubusercontent.com/43336371/310452397-3974aea3-c1a1-40c8-8df1-c2c00c829ca1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MDk3MTk4OTUsIm5iZiI6MTcwOTcxOTU5NSwicGF0aCI6Ii80MzMzNjM3MS8zMTA0NTIzOTctMzk3NGFlYTMtYzFhMS00MGM4LThkZjEtYzJjMDBjODI5Y2ExLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDAzMDYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwMzA2VDEwMDYzNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNhNjk0Yzg4Y2I4MDFhZTViODZmZWI5MWUzNzYxZTExN2JkYjdlZjJkMzM1YjVlNDg5ZmM2MGQ3NDJhYWRhYjkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.SYtqqL0tfQe6rnqsFNwHRVhKouJTjQEBGX0FPXWGoG8',
131
+ 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/b371bc6c-4a8c-489f-87f4-20a913dd8d4b',
132
132
  'api': {
133
133
  'public': 'https://api.{hostname}',
134
134
  'private': 'https://api.{hostname}',
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 type { Market, Trade, Fee, Ticker, OrderBook, Order, Transaction, Tickers, Currency, Balance, DepositAddress, WithdrawalResponse, DepositAddressResponse, OHLCV, Balances, PartialBalances, Dictionary, MinMax, Position, FundingRateHistory, Liquidation, FundingHistory, MarginMode, Greeks, Leverage, Leverages } 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, NoChange } from './src/base/errors.js';
7
- declare const version = "4.2.60";
7
+ declare const version = "4.2.61";
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, NoChange } from './src/base/errors.js';
39
39
  //-----------------------------------------------------------------------------
40
40
  // this is updated by vss.js when building
41
- const version = '4.2.61';
41
+ const version = '4.2.62';
42
42
  Exchange.ccxtVersion = version;
43
43
  //-----------------------------------------------------------------------------
44
44
  import ace from './src/ace.js';
package/js/src/bitget.js CHANGED
@@ -1343,6 +1343,23 @@ export default class bitget extends Exchange {
1343
1343
  'swap': {
1344
1344
  'method': 'publicMixGetV2MixMarketCandles', // or publicMixGetV2MixMarketHistoryCandles or publicMixGetV2MixMarketHistoryIndexCandles or publicMixGetV2MixMarketHistoryMarkCandles
1345
1345
  },
1346
+ 'maxDaysPerTimeframe': {
1347
+ '1m': 30,
1348
+ '3m': 30,
1349
+ '5m': 30,
1350
+ '10m': 52,
1351
+ '15m': 52,
1352
+ '30m': 52,
1353
+ '1h': 83,
1354
+ '2h': 120,
1355
+ '4h': 240,
1356
+ '6h': 360,
1357
+ '12h': 360,
1358
+ '1d': 360,
1359
+ '3d': 1000,
1360
+ '1w': 1000,
1361
+ '1M': 1000,
1362
+ },
1346
1363
  },
1347
1364
  'fetchTrades': {
1348
1365
  'spot': {
@@ -3294,10 +3311,11 @@ export default class bitget extends Exchange {
3294
3311
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
3295
3312
  */
3296
3313
  await this.loadMarkets();
3314
+ const maxLimit = 1000; // max 1000
3297
3315
  let paginate = false;
3298
3316
  [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate');
3299
3317
  if (paginate) {
3300
- return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
3318
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit);
3301
3319
  }
3302
3320
  const sandboxMode = this.safeBool(this.options, 'sandboxMode', false);
3303
3321
  let market = undefined;
@@ -3311,35 +3329,53 @@ export default class bitget extends Exchange {
3311
3329
  const marketType = market['spot'] ? 'spot' : 'swap';
3312
3330
  const timeframes = this.options['timeframes'][marketType];
3313
3331
  const selectedTimeframe = this.safeString(timeframes, timeframe, timeframe);
3332
+ const duration = this.parseTimeframe(timeframe) * 1000;
3314
3333
  const request = {
3315
3334
  'symbol': market['id'],
3316
3335
  'granularity': selectedTimeframe,
3317
3336
  };
3318
- const until = this.safeInteger2(params, 'until', 'till');
3319
- params = this.omit(params, ['until', 'till']);
3337
+ const defaultLimit = 100; // by default, exchange returns 100 items
3338
+ const msInDay = 1000 * 60 * 60 * 24;
3320
3339
  if (limit !== undefined) {
3340
+ limit = Math.min(limit, maxLimit);
3321
3341
  request['limit'] = limit;
3322
3342
  }
3323
- if (since !== undefined) {
3324
- request['startTime'] = since;
3343
+ const until = this.safeInteger2(params, 'until', 'till');
3344
+ params = this.omit(params, ['until', 'till']);
3345
+ if (until !== undefined) {
3346
+ request['endTime'] = until;
3325
3347
  }
3326
3348
  if (since !== undefined) {
3327
- if (limit === undefined) {
3328
- limit = 100; // exchange default
3349
+ request['startTime'] = since;
3350
+ if (market['spot'] && (until === undefined)) {
3351
+ // for spot we need to send "entTime" too
3352
+ const limitForEnd = (limit !== undefined) ? limit : defaultLimit;
3353
+ const calculatedEnd = this.sum(since, duration * limitForEnd);
3354
+ request['endTime'] = calculatedEnd;
3329
3355
  }
3330
- const duration = this.parseTimeframe(timeframe) * 1000;
3331
- request['endTime'] = this.sum(since, duration * (limit + 1)) - 1; // limit + 1)) - 1 is needed for when since is not the exact timestamp of a candle
3332
- }
3333
- else if (until !== undefined) {
3334
- request['endTime'] = until;
3335
- }
3336
- else {
3337
- request['endTime'] = this.milliseconds();
3338
3356
  }
3339
3357
  let response = undefined;
3340
- const thirtyOneDaysAgo = this.milliseconds() - 2678400000;
3358
+ const now = this.milliseconds();
3359
+ // retrievable periods listed here:
3360
+ // - https://www.bitget.com/api-doc/spot/market/Get-Candle-Data#request-parameters
3361
+ // - https://www.bitget.com/api-doc/contract/market/Get-Candle-Data#description
3362
+ const ohlcOptions = this.safeDict(this.options, 'fetchOHLCV', {});
3363
+ const retrievableDaysMap = this.safeDict(ohlcOptions, 'maxDaysPerTimeframe', {});
3364
+ const maxRetrievableDaysForNonHistory = this.safeInteger(retrievableDaysMap, timeframe, 30); // default to safe minimum
3365
+ const endpointTsBoundary = now - maxRetrievableDaysForNonHistory * msInDay;
3366
+ // checks if we need history endpoint
3367
+ let needsHistoryEndpoint = false;
3368
+ const displaceByLimit = (limit === undefined) ? 0 : limit * duration;
3369
+ if (since !== undefined && since < endpointTsBoundary) {
3370
+ // if since it earlier than the allowed diapason
3371
+ needsHistoryEndpoint = true;
3372
+ }
3373
+ else if (until !== undefined && until - displaceByLimit < endpointTsBoundary) {
3374
+ // if until is earlier than the allowed diapason
3375
+ needsHistoryEndpoint = true;
3376
+ }
3341
3377
  if (market['spot']) {
3342
- if ((since !== undefined) && (since < thirtyOneDaysAgo)) {
3378
+ if (needsHistoryEndpoint) {
3343
3379
  response = await this.publicSpotGetV2SpotMarketHistoryCandles(this.extend(request, params));
3344
3380
  }
3345
3381
  else {
@@ -3347,22 +3383,37 @@ export default class bitget extends Exchange {
3347
3383
  }
3348
3384
  }
3349
3385
  else {
3386
+ const maxDistanceDaysForContracts = 90; // maximum 90 days allowed between start-end times
3387
+ let distanceError = false;
3388
+ if (limit !== undefined && limit * duration > maxDistanceDaysForContracts * msInDay) {
3389
+ distanceError = true;
3390
+ }
3391
+ else if (since !== undefined && until !== undefined && until - since > maxDistanceDaysForContracts * msInDay) {
3392
+ distanceError = true;
3393
+ }
3394
+ if (distanceError) {
3395
+ throw new BadRequest(this.id + ' fetchOHLCV() between start and end must be less than ' + maxDistanceDaysForContracts.toString() + ' days');
3396
+ }
3350
3397
  const priceType = this.safeString(params, 'price');
3351
3398
  params = this.omit(params, ['price']);
3352
3399
  let productType = undefined;
3353
3400
  [productType, params] = this.handleProductTypeAndParams(market, params);
3354
3401
  request['productType'] = productType;
3402
+ const extended = this.extend(request, params);
3403
+ // todo: mark & index also have their "recent" endpoints, but not priority now.
3355
3404
  if (priceType === 'mark') {
3356
- response = await this.publicMixGetV2MixMarketHistoryMarkCandles(this.extend(request, params));
3405
+ response = await this.publicMixGetV2MixMarketHistoryMarkCandles(extended);
3357
3406
  }
3358
3407
  else if (priceType === 'index') {
3359
- response = await this.publicMixGetV2MixMarketHistoryIndexCandles(this.extend(request, params));
3360
- }
3361
- else if ((since !== undefined) && (since < thirtyOneDaysAgo)) {
3362
- response = await this.publicMixGetV2MixMarketHistoryCandles(this.extend(request, params));
3408
+ response = await this.publicMixGetV2MixMarketHistoryIndexCandles(extended);
3363
3409
  }
3364
3410
  else {
3365
- response = await this.publicMixGetV2MixMarketCandles(this.extend(request, params));
3411
+ if (needsHistoryEndpoint) {
3412
+ response = await this.publicMixGetV2MixMarketHistoryCandles(extended);
3413
+ }
3414
+ else {
3415
+ response = await this.publicMixGetV2MixMarketCandles(extended);
3416
+ }
3366
3417
  }
3367
3418
  }
3368
3419
  if (response === '') {
@@ -131,7 +131,7 @@ export default class hyperliquid extends Exchange {
131
131
  },
132
132
  'hostname': 'hyperliquid.xyz',
133
133
  'urls': {
134
- 'logo': 'https://private-user-images.githubusercontent.com/43336371/310452397-3974aea3-c1a1-40c8-8df1-c2c00c829ca1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MDk3MTk4OTUsIm5iZiI6MTcwOTcxOTU5NSwicGF0aCI6Ii80MzMzNjM3MS8zMTA0NTIzOTctMzk3NGFlYTMtYzFhMS00MGM4LThkZjEtYzJjMDBjODI5Y2ExLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDAzMDYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwMzA2VDEwMDYzNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNhNjk0Yzg4Y2I4MDFhZTViODZmZWI5MWUzNzYxZTExN2JkYjdlZjJkMzM1YjVlNDg5ZmM2MGQ3NDJhYWRhYjkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.SYtqqL0tfQe6rnqsFNwHRVhKouJTjQEBGX0FPXWGoG8',
134
+ 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/b371bc6c-4a8c-489f-87f4-20a913dd8d4b',
135
135
  'api': {
136
136
  'public': 'https://api.{hostname}',
137
137
  'private': 'https://api.{hostname}',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.2.61",
3
+ "version": "4.2.62",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",