ccxt 4.4.48__py2.py3-none-any.whl → 4.4.50__py2.py3-none-any.whl

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.
Files changed (97) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +1 -0
  3. ccxt/abstract/binancecoinm.py +1 -0
  4. ccxt/abstract/binanceus.py +1 -0
  5. ccxt/abstract/binanceusdm.py +1 -0
  6. ccxt/alpaca.py +62 -1
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/alpaca.py +62 -1
  9. ccxt/async_support/base/exchange.py +1 -1
  10. ccxt/async_support/binance.py +8 -4
  11. ccxt/async_support/bingx.py +73 -29
  12. ccxt/async_support/bitget.py +12 -10
  13. ccxt/async_support/blofin.py +1 -1
  14. ccxt/async_support/coinex.py +3 -3
  15. ccxt/async_support/coinsph.py +17 -8
  16. ccxt/async_support/deribit.py +82 -0
  17. ccxt/async_support/digifinex.py +125 -10
  18. ccxt/async_support/ellipx.py +61 -0
  19. ccxt/async_support/exmo.py +58 -0
  20. ccxt/async_support/hitbtc.py +99 -0
  21. ccxt/async_support/hollaex.py +85 -16
  22. ccxt/async_support/huobijp.py +73 -0
  23. ccxt/async_support/hyperliquid.py +22 -1
  24. ccxt/async_support/idex.py +71 -0
  25. ccxt/async_support/independentreserve.py +64 -0
  26. ccxt/async_support/indodax.py +61 -0
  27. ccxt/async_support/kucoin.py +47 -67
  28. ccxt/async_support/kuna.py +60 -1
  29. ccxt/async_support/latoken.py +64 -0
  30. ccxt/async_support/lbank.py +70 -0
  31. ccxt/async_support/luno.py +73 -0
  32. ccxt/async_support/lykke.py +64 -0
  33. ccxt/async_support/mercado.py +65 -0
  34. ccxt/async_support/mexc.py +4 -3
  35. ccxt/async_support/myokx.py +10 -0
  36. ccxt/async_support/ndax.py +71 -0
  37. ccxt/async_support/novadax.py +74 -0
  38. ccxt/async_support/oceanex.py +69 -0
  39. ccxt/async_support/okcoin.py +92 -7
  40. ccxt/async_support/onetrading.py +66 -0
  41. ccxt/async_support/oxfun.py +66 -0
  42. ccxt/async_support/p2b.py +63 -1
  43. ccxt/async_support/paradex.py +68 -0
  44. ccxt/async_support/paymium.py +42 -0
  45. ccxt/async_support/probit.py +68 -1
  46. ccxt/async_support/timex.py +67 -0
  47. ccxt/async_support/tokocrypto.py +81 -4
  48. ccxt/async_support/tradeogre.py +58 -1
  49. ccxt/async_support/whitebit.py +10 -4
  50. ccxt/base/exchange.py +62 -1
  51. ccxt/binance.py +8 -4
  52. ccxt/bingx.py +73 -29
  53. ccxt/bitget.py +12 -10
  54. ccxt/blofin.py +1 -1
  55. ccxt/coinex.py +3 -3
  56. ccxt/coinsph.py +17 -8
  57. ccxt/deribit.py +82 -0
  58. ccxt/digifinex.py +125 -10
  59. ccxt/ellipx.py +61 -0
  60. ccxt/exmo.py +58 -0
  61. ccxt/hitbtc.py +99 -0
  62. ccxt/hollaex.py +85 -16
  63. ccxt/huobijp.py +73 -0
  64. ccxt/hyperliquid.py +22 -1
  65. ccxt/idex.py +71 -0
  66. ccxt/independentreserve.py +64 -0
  67. ccxt/indodax.py +61 -0
  68. ccxt/kucoin.py +47 -67
  69. ccxt/kuna.py +60 -1
  70. ccxt/latoken.py +64 -0
  71. ccxt/lbank.py +70 -0
  72. ccxt/luno.py +73 -0
  73. ccxt/lykke.py +64 -0
  74. ccxt/mercado.py +65 -0
  75. ccxt/mexc.py +4 -3
  76. ccxt/myokx.py +10 -0
  77. ccxt/ndax.py +71 -0
  78. ccxt/novadax.py +74 -0
  79. ccxt/oceanex.py +69 -0
  80. ccxt/okcoin.py +92 -7
  81. ccxt/onetrading.py +66 -0
  82. ccxt/oxfun.py +66 -0
  83. ccxt/p2b.py +63 -1
  84. ccxt/paradex.py +68 -0
  85. ccxt/paymium.py +42 -0
  86. ccxt/pro/__init__.py +1 -1
  87. ccxt/pro/bitmart.py +5 -0
  88. ccxt/probit.py +68 -1
  89. ccxt/timex.py +67 -0
  90. ccxt/tokocrypto.py +81 -4
  91. ccxt/tradeogre.py +58 -1
  92. ccxt/whitebit.py +10 -4
  93. {ccxt-4.4.48.dist-info → ccxt-4.4.50.dist-info}/METADATA +4 -4
  94. {ccxt-4.4.48.dist-info → ccxt-4.4.50.dist-info}/RECORD +97 -97
  95. {ccxt-4.4.48.dist-info → ccxt-4.4.50.dist-info}/LICENSE.txt +0 -0
  96. {ccxt-4.4.48.dist-info → ccxt-4.4.50.dist-info}/WHEEL +0 -0
  97. {ccxt-4.4.48.dist-info → ccxt-4.4.50.dist-info}/top_level.txt +0 -0
@@ -291,6 +291,88 @@ class deribit(Exchange, ImplicitAPI):
291
291
  },
292
292
  },
293
293
  },
294
+ 'features': {
295
+ 'default': {
296
+ 'sandbox': True,
297
+ 'createOrder': {
298
+ 'marginMode': False,
299
+ 'triggerPrice': True, # todo
300
+ # todo implement
301
+ 'triggerPriceType': {
302
+ 'last': True,
303
+ 'mark': True,
304
+ 'index': True,
305
+ },
306
+ 'triggerDirection': False,
307
+ 'stopLossPrice': False, # todo
308
+ 'takeProfitPrice': False, # todo
309
+ 'attachedStopLossTakeProfit': None,
310
+ 'timeInForce': {
311
+ 'IOC': True,
312
+ 'FOK': True,
313
+ 'PO': True,
314
+ 'GTD': True,
315
+ },
316
+ 'hedged': False,
317
+ 'selfTradePrevention': False,
318
+ 'trailing': True, # todo
319
+ 'leverage': False,
320
+ 'marketBuyByCost': True, # todo
321
+ 'marketBuyRequiresPrice': False,
322
+ 'iceberg': True, # todo
323
+ },
324
+ 'createOrders': None,
325
+ 'fetchMyTrades': {
326
+ 'marginMode': False,
327
+ 'limit': 100, # todo: revise
328
+ 'daysBack': 100000,
329
+ 'untilDays': 100000,
330
+ },
331
+ 'fetchOrder': {
332
+ 'marginMode': False,
333
+ 'trigger': False,
334
+ 'trailing': False,
335
+ },
336
+ 'fetchOpenOrders': {
337
+ 'marginMode': False,
338
+ 'limit': None,
339
+ 'trigger': False,
340
+ 'trailing': False,
341
+ },
342
+ 'fetchOrders': None,
343
+ 'fetchClosedOrders': {
344
+ 'marginMode': False,
345
+ 'limit': 100,
346
+ 'daysBack': 100000,
347
+ 'daysBackCanceled': 1,
348
+ 'untilDays': 100000,
349
+ 'trigger': False,
350
+ 'trailing': False,
351
+ },
352
+ 'fetchOHLCV': {
353
+ 'limit': 1000, # todo: recheck
354
+ },
355
+ },
356
+ 'spot': {
357
+ 'extends': 'default',
358
+ },
359
+ 'swap': {
360
+ 'linear': {
361
+ 'extends': 'default',
362
+ },
363
+ 'inverse': {
364
+ 'extends': 'default',
365
+ },
366
+ },
367
+ 'future': {
368
+ 'linear': {
369
+ 'extends': 'default',
370
+ },
371
+ 'inverse': {
372
+ 'extends': 'default',
373
+ },
374
+ },
375
+ },
294
376
  'exceptions': {
295
377
  # 0 or absent Success, No error.
296
378
  '9999': PermissionDenied, # 'api_not_enabled' User didn't enable API for the Account.
@@ -254,6 +254,109 @@ class digifinex(Exchange, ImplicitAPI):
254
254
  },
255
255
  },
256
256
  },
257
+ 'features': {
258
+ 'default': {
259
+ 'sandbox': False,
260
+ 'createOrder': {
261
+ 'marginMode': True,
262
+ 'triggerPrice': False,
263
+ 'triggerPriceType': None,
264
+ 'triggerDirection': False,
265
+ 'stopLossPrice': False,
266
+ 'takeProfitPrice': False,
267
+ 'attachedStopLossTakeProfit': None,
268
+ 'timeInForce': {
269
+ 'IOC': False,
270
+ 'FOK': False,
271
+ 'PO': True,
272
+ 'GTD': False,
273
+ },
274
+ 'hedged': False,
275
+ 'selfTradePrevention': False,
276
+ 'trailing': False,
277
+ 'leverage': False,
278
+ 'marketBuyByCost': False,
279
+ 'marketBuyRequiresPrice': False,
280
+ 'iceberg': False,
281
+ },
282
+ 'createOrders': {
283
+ 'max': 10,
284
+ 'marginMode': True,
285
+ },
286
+ 'fetchMyTrades': {
287
+ 'marginMode': True,
288
+ 'limit': 500,
289
+ 'daysBack': 100000, # todo
290
+ 'untilDays': 30,
291
+ },
292
+ 'fetchOrder': {
293
+ 'marginMode': True,
294
+ 'trigger': False,
295
+ 'trailing': False,
296
+ 'marketType': True,
297
+ },
298
+ 'fetchOpenOrders': {
299
+ 'marginMode': True,
300
+ 'limit': None,
301
+ 'trigger': False,
302
+ 'trailing': False,
303
+ },
304
+ 'fetchOrders': {
305
+ 'marginMode': True,
306
+ 'limit': 100,
307
+ 'daysBack': 100000, # todo
308
+ 'untilDays': 30,
309
+ 'trigger': False,
310
+ 'trailing': False,
311
+ },
312
+ 'fetchClosedOrders': None,
313
+ 'fetchOHLCV': {
314
+ 'limit': 500,
315
+ },
316
+ },
317
+ 'spot': {
318
+ 'extends': 'default',
319
+ },
320
+ 'forDerivatives': {
321
+ 'extends': 'default',
322
+ 'createOrders': {
323
+ 'max': 20,
324
+ 'marginMode': False,
325
+ },
326
+ 'fetchMyTrades': {
327
+ 'marginMode': False,
328
+ 'limit': 100,
329
+ 'daysBack': 100000, # todo
330
+ 'untilDays': 100000, # todo
331
+ },
332
+ 'fetchOrder': {
333
+ 'marginMode': False,
334
+ },
335
+ 'fetchOpenOrders': {
336
+ 'marginMode': False,
337
+ 'limit': 100,
338
+ },
339
+ 'fetchOrders': {
340
+ 'marginMode': False,
341
+ 'daysBack': 100000, # todo
342
+ },
343
+ 'fetchOHLCV': {
344
+ 'limit': 100,
345
+ },
346
+ },
347
+ 'swap': {
348
+ 'linear': {
349
+ 'extends': 'forDerivatives',
350
+ },
351
+ 'inverse': {
352
+ 'extends': 'forDerivatives',
353
+ },
354
+ },
355
+ 'future': {
356
+ 'linear': None,
357
+ 'inverse': None,
358
+ },
359
+ },
257
360
  'fees': {
258
361
  'trading': {
259
362
  'tierBased': True,
@@ -1459,6 +1562,7 @@ class digifinex(Exchange, ImplicitAPI):
1459
1562
  :param int [since]: timestamp in ms of the earliest candle to fetch
1460
1563
  :param int [limit]: the maximum amount of candles to fetch
1461
1564
  :param dict [params]: extra parameters specific to the exchange API endpoint
1565
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
1462
1566
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1463
1567
  """
1464
1568
  await self.load_markets()
@@ -1472,19 +1576,30 @@ class digifinex(Exchange, ImplicitAPI):
1472
1576
  request['limit'] = min(limit, 100)
1473
1577
  response = await self.publicSwapGetPublicCandles(self.extend(request, params))
1474
1578
  else:
1579
+ until = self.safe_integer(params, 'until')
1475
1580
  request['symbol'] = market['id']
1476
1581
  request['period'] = self.safe_string(self.timeframes, timeframe, timeframe)
1477
- if since is not None:
1478
- startTime = self.parse_to_int(since / 1000)
1582
+ startTime = since
1583
+ duration = self.parse_timeframe(timeframe)
1584
+ if startTime is None:
1585
+ if (limit is not None) or (until is not None):
1586
+ endTime = until if (until is not None) else self.milliseconds()
1587
+ startLimit = limit if (limit is not None) else 200
1588
+ startTime = endTime - (startLimit * duration * 1000)
1589
+ if startTime is not None:
1590
+ startTime = self.parse_to_int(startTime / 1000)
1479
1591
  request['start_time'] = startTime
1480
- if limit is not None:
1481
- duration = self.parse_timeframe(timeframe)
1482
- request['end_time'] = self.sum(startTime, limit * duration)
1483
- elif limit is not None:
1484
- endTime = self.seconds()
1485
- duration = self.parse_timeframe(timeframe)
1486
- auxLimit = limit # in c# -limit is mutating the arg
1487
- request['start_time'] = self.sum(endTime, -auxLimit * duration)
1592
+ if (limit is not None) or (until is not None):
1593
+ if until is not None:
1594
+ endByUntil = self.parse_to_int(until / 1000)
1595
+ if limit is not None:
1596
+ endByLimit = self.sum(startTime, limit * duration)
1597
+ request['end_time'] = min(endByLimit, endByUntil)
1598
+ else:
1599
+ request['end_time'] = endByUntil
1600
+ else:
1601
+ request['end_time'] = self.sum(startTime, limit * duration)
1602
+ params = self.omit(params, 'until')
1488
1603
  response = await self.publicSpotGetKline(self.extend(request, params))
1489
1604
  #
1490
1605
  # spot
@@ -235,6 +235,66 @@ class ellipx(Exchange, ImplicitAPI):
235
235
  'ETH': 'Ethereum',
236
236
  },
237
237
  },
238
+ 'features': {
239
+ 'spot': {
240
+ 'sandbox': False,
241
+ 'createOrder': {
242
+ 'marginMode': False,
243
+ 'triggerPrice': False,
244
+ 'triggerPriceType': None,
245
+ 'triggerDirection': False,
246
+ 'stopLossPrice': False,
247
+ 'takeProfitPrice': False,
248
+ 'attachedStopLossTakeProfit': None,
249
+ 'timeInForce': {
250
+ 'IOC': False,
251
+ 'FOK': False,
252
+ 'PO': False,
253
+ 'GTD': False,
254
+ },
255
+ 'hedged': False,
256
+ 'selfTradePrevention': False,
257
+ 'trailing': False,
258
+ 'leverage': False,
259
+ 'marketBuyByCost': True,
260
+ 'marketBuyRequiresPrice': False,
261
+ 'iceberg': False,
262
+ },
263
+ 'createOrders': None,
264
+ 'fetchMyTrades': None,
265
+ 'fetchOrder': {
266
+ 'marginMode': False,
267
+ 'trigger': False,
268
+ 'trailing': False,
269
+ },
270
+ 'fetchOpenOrders': {
271
+ 'marginMode': False,
272
+ 'limit': None,
273
+ 'trigger': False,
274
+ 'trailing': False,
275
+ },
276
+ 'fetchOrders': {
277
+ 'marginMode': False,
278
+ 'limit': None, # todo
279
+ 'daysBack': None, # todo
280
+ 'untilDays': None, # todo
281
+ 'trigger': False,
282
+ 'trailing': False,
283
+ },
284
+ 'fetchClosedOrders': None,
285
+ 'fetchOHLCV': {
286
+ 'limit': 100,
287
+ },
288
+ },
289
+ 'swap': {
290
+ 'linear': None,
291
+ 'inverse': None,
292
+ },
293
+ 'future': {
294
+ 'linear': None,
295
+ 'inverse': None,
296
+ },
297
+ },
238
298
  'commonCurrencies': {},
239
299
  'exceptions': {
240
300
  'exact': {
@@ -662,6 +722,7 @@ class ellipx(Exchange, ImplicitAPI):
662
722
  :param int [since]: timestamp in ms of the earliest candle to fetch
663
723
  :param int [limit]: the maximum amount of candles to fetch
664
724
  :param dict [params]: extra parameters specific to the API endpoint
725
+ :param int [params.until]: timestamp in ms of the earliest candle to fetch
665
726
  :returns OHLCV[]: A list of candles ordered, open, high, low, close, volume
666
727
  """
667
728
  await self.load_markets()
@@ -220,6 +220,64 @@ class exmo(Exchange, ImplicitAPI):
220
220
  'fillResponseFromRequest': True,
221
221
  },
222
222
  },
223
+ 'features': {
224
+ 'spot': {
225
+ 'sandbox': False,
226
+ 'createOrder': {
227
+ 'marginMode': True, # todo revise
228
+ 'triggerPrice': True, # todo: endpoint lacks other features
229
+ 'triggerPriceType': None,
230
+ 'triggerDirection': False,
231
+ 'stopLossPrice': False,
232
+ 'takeProfitPrice': False,
233
+ 'attachedStopLossTakeProfit': None,
234
+ 'timeInForce': {
235
+ 'IOC': True,
236
+ 'FOK': True,
237
+ 'PO': True,
238
+ 'GTD': True,
239
+ },
240
+ 'hedged': False,
241
+ 'selfTradePrevention': False,
242
+ 'trailing': False,
243
+ 'leverage': True,
244
+ 'marketBuyByCost': True,
245
+ 'marketBuyRequiresPrice': False,
246
+ 'iceberg': False,
247
+ },
248
+ 'createOrders': None,
249
+ 'fetchMyTrades': {
250
+ 'marginMode': True,
251
+ 'limit': 100,
252
+ 'daysBack': None,
253
+ 'untilDays': None,
254
+ },
255
+ 'fetchOrder': {
256
+ 'marginMode': False,
257
+ 'trigger': False,
258
+ 'trailing': False,
259
+ },
260
+ 'fetchOpenOrders': {
261
+ 'marginMode': False,
262
+ 'limit': None,
263
+ 'trigger': False,
264
+ 'trailing': False,
265
+ },
266
+ 'fetchOrders': None,
267
+ 'fetchClosedOrders': None,
268
+ 'fetchOHLCV': {
269
+ 'limit': 1000, # todo, not in request
270
+ },
271
+ },
272
+ 'swap': {
273
+ 'linear': None,
274
+ 'inverse': None,
275
+ },
276
+ 'future': {
277
+ 'linear': None,
278
+ 'inverse': None,
279
+ },
280
+ },
223
281
  'commonCurrencies': {
224
282
  'GMT': 'GMT Token',
225
283
  },
@@ -304,6 +304,105 @@ class hitbtc(Exchange, ImplicitAPI):
304
304
  },
305
305
  },
306
306
  },
307
+ 'features': {
308
+ 'default': {
309
+ 'sandbox': True,
310
+ 'createOrder': {
311
+ 'marginMode': False,
312
+ 'triggerPrice': True,
313
+ 'triggerPriceType': None,
314
+ 'triggerDirection': False,
315
+ 'stopLossPrice': False, # todo
316
+ 'takeProfitPrice': False, # todo
317
+ 'attachedStopLossTakeProfit': None,
318
+ 'timeInForce': {
319
+ 'IOC': True,
320
+ 'FOK': True,
321
+ 'PO': True,
322
+ 'GTD': True,
323
+ },
324
+ 'hedged': False,
325
+ 'selfTradePrevention': False,
326
+ 'trailing': False,
327
+ 'leverage': False,
328
+ 'marketBuyByCost': False,
329
+ 'marketBuyRequiresPrice': False,
330
+ 'iceberg': True,
331
+ },
332
+ 'createOrders': None,
333
+ 'fetchMyTrades': {
334
+ 'marginMode': True,
335
+ 'limit': 1000,
336
+ 'daysBack': 100000,
337
+ 'untilDays': 100000,
338
+ 'marketType': True,
339
+ },
340
+ 'fetchOrder': {
341
+ 'marginMode': True,
342
+ 'trigger': False,
343
+ 'trailing': False,
344
+ 'marketType': True,
345
+ },
346
+ 'fetchOpenOrders': {
347
+ 'marginMode': True,
348
+ 'limit': 1000,
349
+ 'trigger': False,
350
+ 'trailing': False,
351
+ 'marketType': True,
352
+ },
353
+ 'fetchOrders': None,
354
+ 'fetchClosedOrders': {
355
+ 'marginMode': True,
356
+ 'limit': 1000,
357
+ 'daysBack': 100000, # todo
358
+ 'daysBackCanceled': 1, # todo
359
+ 'untilDays': 100000, # todo
360
+ 'trigger': False,
361
+ 'trailing': False,
362
+ 'marketType': True,
363
+ },
364
+ 'fetchOHLCV': {
365
+ 'limit': 1000,
366
+ },
367
+ },
368
+ 'spot': {
369
+ 'extends': 'default',
370
+ },
371
+ 'forDerivatives': {
372
+ 'extends': 'default',
373
+ 'createOrder': {
374
+ 'marginMode': True,
375
+ },
376
+ 'fetchOrder': {
377
+ 'marginMode': False,
378
+ },
379
+ 'fetchMyTrades': {
380
+ 'marginMode': False,
381
+ },
382
+ 'fetchOpenOrders': {
383
+ 'marginMode': False,
384
+ },
385
+ 'fetchClosedOrders': {
386
+ 'marginMode': False,
387
+ },
388
+ },
389
+ 'swap': {
390
+ 'linear': {
391
+ 'extends': 'forDerivatives',
392
+ },
393
+ 'inverse': {
394
+ 'extends': 'forDerivatives',
395
+ },
396
+ },
397
+ 'future': {
398
+ 'linear': {
399
+ 'extends': 'forDerivatives',
400
+ },
401
+ 'inverse': {
402
+ 'extends': 'forDerivatives',
403
+ },
404
+ },
405
+ },
307
406
  'timeframes': {
308
407
  '1m': 'M1',
309
408
  '3m': 'M3',
@@ -174,6 +174,79 @@ class hollaex(Exchange, ImplicitAPI):
174
174
  },
175
175
  },
176
176
  },
177
+ 'features': {
178
+ 'spot': {
179
+ 'sandbox': True,
180
+ 'createOrder': {
181
+ 'marginMode': False,
182
+ 'triggerPrice': True,
183
+ 'triggerPriceType': None,
184
+ 'triggerDirection': False,
185
+ 'stopLossPrice': False, # todo
186
+ 'takeProfitPrice': False, # todo
187
+ 'attachedStopLossTakeProfit': None,
188
+ 'timeInForce': {
189
+ 'IOC': False,
190
+ 'FOK': False,
191
+ 'PO': True,
192
+ 'GTD': False,
193
+ },
194
+ 'hedged': False,
195
+ 'selfTradePrevention': False,
196
+ 'trailing': False,
197
+ 'leverage': False,
198
+ 'marketBuyByCost': False,
199
+ 'marketBuyRequiresPrice': False,
200
+ 'iceberg': False,
201
+ },
202
+ 'createOrders': None,
203
+ 'fetchMyTrades': {
204
+ 'marginMode': False,
205
+ 'limit': 100,
206
+ 'daysBack': 100000,
207
+ 'untilDays': 100000, # todo implement
208
+ },
209
+ 'fetchOrder': {
210
+ 'marginMode': False,
211
+ 'trigger': False,
212
+ 'trailing': False,
213
+ },
214
+ 'fetchOpenOrders': {
215
+ 'marginMode': False,
216
+ 'limit': 100,
217
+ 'trigger': False,
218
+ 'trailing': False,
219
+ },
220
+ 'fetchOrders': {
221
+ 'marginMode': False,
222
+ 'limit': 100,
223
+ 'daysBack': 100000, # todo
224
+ 'untilDays': 100000, # todo
225
+ 'trigger': False,
226
+ 'trailing': False,
227
+ },
228
+ 'fetchClosedOrders': {
229
+ 'marginMode': False,
230
+ 'limit': 100,
231
+ 'daysBack': 100000, # todo
232
+ 'daysBackCanceled': 1, # todo
233
+ 'untilDays': 100000, # todo
234
+ 'trigger': False,
235
+ 'trailing': False,
236
+ },
237
+ 'fetchOHLCV': {
238
+ 'limit': 1000, # todo: no limit in request
239
+ },
240
+ },
241
+ 'swap': {
242
+ 'linear': None,
243
+ 'inverse': None,
244
+ },
245
+ 'future': {
246
+ 'linear': None,
247
+ 'inverse': None,
248
+ },
249
+ },
177
250
  'fees': {
178
251
  'trading': {
179
252
  'tierBased': True,
@@ -756,7 +829,7 @@ class hollaex(Exchange, ImplicitAPI):
756
829
 
757
830
  async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
758
831
  """
759
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
832
+ hollaex has large gaps between candles, so it's recommended to specify since
760
833
 
761
834
  https://apidocs.hollaex.com/#chart
762
835
 
@@ -765,6 +838,7 @@ class hollaex(Exchange, ImplicitAPI):
765
838
  :param int [since]: timestamp in ms of the earliest candle to fetch
766
839
  :param int [limit]: the maximum amount of candles to fetch
767
840
  :param dict [params]: extra parameters specific to the exchange API endpoint
841
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
768
842
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
769
843
  """
770
844
  await self.load_markets()
@@ -773,22 +847,17 @@ class hollaex(Exchange, ImplicitAPI):
773
847
  'symbol': market['id'],
774
848
  'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
775
849
  }
776
- duration = self.parse_timeframe(timeframe)
777
- if since is None:
778
- if limit is None:
779
- limit = 1000 # they have no defaults and can actually provide tens of thousands of bars in one request, but we should cap "default" at generous amount
780
- end = self.seconds()
781
- start = end - duration * limit
782
- request['to'] = end
783
- request['from'] = start
850
+ until = self.safe_integer(params, 'until')
851
+ end = self.seconds()
852
+ if until is not None:
853
+ end = self.parse_to_int(until / 1000)
854
+ defaultSpan = 2592000 # 30 days
855
+ if since is not None:
856
+ request['from'] = self.parse_to_int(since / 1000)
784
857
  else:
785
- if limit is None:
786
- request['from'] = self.parse_to_int(since / 1000)
787
- request['to'] = self.seconds()
788
- else:
789
- start = self.parse_to_int(since / 1000)
790
- request['from'] = start
791
- request['to'] = self.sum(start, duration * limit)
858
+ request['from'] = end - defaultSpan
859
+ request['to'] = end
860
+ params = self.omit(params, 'until')
792
861
  response = await self.publicGetChart(self.extend(request, params))
793
862
  #
794
863
  # [