From 5946522ec5b651c0e33c774042935715076d46fd Mon Sep 17 00:00:00 2001 From: "Aryn C. Smithington" Date: Fri, 15 May 2026 05:10:36 +0000 Subject: [PATCH] Add unified accounting coverage for CEX ETL --- js/src/bitfinex.d.ts | 49 +++++++++++++++++++++++ js/src/bitfinex.js | 87 +++++++++++++++++++++++++++++++++++++++++ js/src/bybit.js | 8 +++- js/src/mexc.d.ts | 18 ++++++++- js/src/mexc.js | 87 ++++++++++++++++++++++++++++++++++++++++- ts/src/bitfinex.ts | 92 ++++++++++++++++++++++++++++++++++++++++++++ ts/src/bybit.ts | 8 +++- ts/src/mexc.ts | 92 +++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 433 insertions(+), 8 deletions(-) diff --git a/js/src/bitfinex.d.ts b/js/src/bitfinex.d.ts index 50c4033..9349f48 100644 --- a/js/src/bitfinex.d.ts +++ b/js/src/bitfinex.d.ts @@ -66,7 +66,19 @@ export default class bitfinex extends Exchange { * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure} */ transfer(code: string, amount: number, fromAccount: string, toAccount: string, params?: {}): Promise; + /** + * @method + * @name bitfinex#fetchTransfers + * @description fetch internal transfers as unified transfer structures from ledger entries + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest transfer, default is undefined + * @param {int} [limit] max number of transfers to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} + */ + fetchTransfers(code?: Str, since?: Int, limit?: Int, params?: {}): Promise; parseTransfer(transfer: Dict, currency?: Currency): TransferEntry; + ledgerEntryToTransfer(entry: LedgerEntry): TransferEntry; parseTransferStatus(status: Str): Str; convertDerivativesId(currency: any, type: any): any; /** @@ -254,6 +266,19 @@ export default class bitfinex extends Exchange { * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ fetchClosedOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise; + /** + * @method + * @name bitfinex#fetchOrders + * @description fetches information on multiple orders made by the user + * @see https://docs.bitfinex.com/reference/rest-auth-retrieve-orders + * @see https://docs.bitfinex.com/reference/rest-auth-orders-history + * @param {string} symbol unified market symbol of the market orders were made in + * @param {int} [since] the earliest time in ms to fetch orders for + * @param {int} [limit] the maximum number of order structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + fetchOrders(symbol?: Str, since?: Int, limit?: Int, params?: {}): Promise; /** * @method * @name bitfinex#fetchOrderTrades @@ -324,6 +349,30 @@ export default class bitfinex extends Exchange { * @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure} */ fetchDepositsWithdrawals(code?: Str, since?: Int, limit?: Int, params?: {}): Promise; + /** + * @method + * @name bitfinex#fetchDeposits + * @description fetch all deposits made to an account + * @see https://docs.bitfinex.com/reference/rest-auth-movements + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest deposit, default is undefined + * @param {int} [limit] max number of deposits to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + fetchDeposits(code?: Str, since?: Int, limit?: Int, params?: {}): Promise; + /** + * @method + * @name bitfinex#fetchWithdrawals + * @description fetch all withdrawals made from an account + * @see https://docs.bitfinex.com/reference/rest-auth-movements + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest withdrawal, default is undefined + * @param {int} [limit] max number of withdrawals to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + fetchWithdrawals(code?: Str, since?: Int, limit?: Int, params?: {}): Promise; /** * @method * @name bitfinex#withdraw diff --git a/js/src/bitfinex.js b/js/src/bitfinex.js index 9dd19c4..cee458d 100644 --- a/js/src/bitfinex.js +++ b/js/src/bitfinex.js @@ -66,6 +66,7 @@ export default class bitfinex extends Exchange { 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, + 'fetchDeposits': true, 'fetchDepositsWithdrawals': true, 'fetchFundingHistory': false, 'fetchFundingRate': 'emulated', @@ -92,6 +93,7 @@ export default class bitfinex extends Exchange { 'fetchOrderBook': true, 'fetchOrderBooks': false, 'fetchOrderTrades': true, + 'fetchOrders': true, 'fetchPosition': false, 'fetchPositionMode': false, 'fetchPositions': true, @@ -103,6 +105,7 @@ export default class bitfinex extends Exchange { 'fetchTradingFees': true, 'fetchTransactionFees': undefined, 'fetchTransactions': 'emulated', + 'fetchTransfers': 'emulated', 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, @@ -112,6 +115,7 @@ export default class bitfinex extends Exchange { 'setPositionMode': false, 'signIn': false, 'transfer': true, + 'fetchWithdrawals': true, 'withdraw': true, }, 'timeframes': { @@ -1046,6 +1050,25 @@ export default class bitfinex extends Exchange { } return this.parseTransfer({ 'result': response }, currency); } + /** + * @method + * @name bitfinex#fetchTransfers + * @description fetch internal transfers as unified transfer structures from ledger entries + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest transfer, default is undefined + * @param {int} [limit] max number of transfers to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} + */ + async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) { + const ledger = await this.fetchLedger(code, since, limit, params); + const transfers = ledger.filter((entry) => entry['type'] === 'transfer'); + const result = []; + for (let i = 0; i < transfers.length; i++) { + result.push(this.ledgerEntryToTransfer(transfers[i])); + } + return this.filterBySinceLimit(result, since, limit); + } parseTransfer(transfer, currency = undefined) { // // transfer @@ -1089,6 +1112,19 @@ export default class bitfinex extends Exchange { 'info': result, }; } + ledgerEntryToTransfer(entry) { + return { + 'id': this.safeString(entry, 'id'), + 'timestamp': this.safeInteger(entry, 'timestamp'), + 'datetime': this.safeString(entry, 'datetime'), + 'status': this.safeString(entry, 'status'), + 'amount': this.safeNumber(entry, 'amount'), + 'currency': this.safeString(entry, 'currency'), + 'fromAccount': this.safeString(entry, 'account'), + 'toAccount': this.safeString(entry, 'referenceAccount'), + 'info': entry['info'], + }; + } parseTransferStatus(status) { const statuses = { 'SUCCESS': 'ok', @@ -2249,6 +2285,25 @@ export default class bitfinex extends Exchange { } return this.parseOrders(ordersList, market, since, limit); } + /** + * @method + * @name bitfinex#fetchOrders + * @description fetches information on multiple orders made by the user + * @see https://docs.bitfinex.com/reference/rest-auth-retrieve-orders + * @see https://docs.bitfinex.com/reference/rest-auth-orders-history + * @param {string} symbol unified market symbol of the market orders were made in + * @param {int} [since] the earliest time in ms to fetch orders for + * @param {int} [limit] the maximum number of order structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { + const openOrders = await this.fetchOpenOrders(symbol, since, limit, this.extend({}, params)); + const closedOrders = await this.fetchClosedOrders(symbol, since, limit, this.extend({}, params)); + const uniqueOrders = this.removeRepeatedElementsFromArray(openOrders.concat(closedOrders), false); + const sortedOrders = this.sortBy(uniqueOrders, 'timestamp'); + return this.filterBySinceLimit(sortedOrders, since, limit); + } /** * @method * @name bitfinex#fetchOrderTrades @@ -2728,6 +2783,38 @@ export default class bitfinex extends Exchange { // return this.parseTransactions(response, currency, since, limit); } + /** + * @method + * @name bitfinex#fetchDeposits + * @description fetch all deposits made to an account + * @see https://docs.bitfinex.com/reference/rest-auth-movements + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest deposit, default is undefined + * @param {int} [limit] max number of deposits to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) { + const transactions = await this.fetchDepositsWithdrawals(code, since, limit, params); + const deposits = transactions.filter((transaction) => transaction['type'] === 'deposit'); + return this.filterBySinceLimit(deposits, since, limit); + } + /** + * @method + * @name bitfinex#fetchWithdrawals + * @description fetch all withdrawals made from an account + * @see https://docs.bitfinex.com/reference/rest-auth-movements + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest withdrawal, default is undefined + * @param {int} [limit] max number of withdrawals to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) { + const transactions = await this.fetchDepositsWithdrawals(code, since, limit, params); + const withdrawals = transactions.filter((transaction) => transaction['type'] === 'withdrawal'); + return this.filterBySinceLimit(withdrawals, since, limit); + } /** * @method * @name bitfinex#withdraw diff --git a/js/src/bybit.js b/js/src/bybit.js index f974e0b..3e1afba 100644 --- a/js/src/bybit.js +++ b/js/src/bybit.js @@ -113,7 +113,7 @@ export default class bybit extends Exchange { 'fetchOptionChain': true, 'fetchOrder': true, 'fetchOrderBook': true, - 'fetchOrders': false, + 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionHistory': 'emulated', @@ -5039,7 +5039,11 @@ export default class bybit extends Exchange { */ const enableUnifiedAccount = this.safeBool(res, 1); if (enableUnifiedAccount) { - throw new NotSupported(this.id + ' fetchOrders() is not supported after the 5/02 update for UTA accounts, please use fetchOpenOrders, fetchClosedOrders or fetchCanceledOrders'); + const openOrders = await this.fetchOpenOrders(symbol, since, limit, this.extend({}, params)); + const historicalOrders = await this.fetchCanceledAndClosedOrders(symbol, since, limit, this.extend({}, params)); + const uniqueOrders = this.removeRepeatedElementsFromArray(openOrders.concat(historicalOrders), false); + const sortedOrders = this.sortBy(uniqueOrders, 'timestamp'); + return this.filterBySinceLimit(sortedOrders, since, limit); } return await this.fetchOrdersClassic(symbol, since, limit, params); } diff --git a/js/src/mexc.d.ts b/js/src/mexc.d.ts index f6e060f..80e2579 100644 --- a/js/src/mexc.d.ts +++ b/js/src/mexc.d.ts @@ -1,5 +1,5 @@ import Exchange from './abstract/mexc.js'; -import type { TransferEntry, IndexType, Int, OrderSide, Balances, OrderType, OHLCV, FundingRateHistory, Position, OrderBook, OrderRequest, FundingHistory, Order, Str, Trade, Transaction, Ticker, Tickers, Strings, Market, Currency, Leverage, Num, Account, MarginModification, Currencies, Dict, LeverageTier, LeverageTiers, int, FundingRate, DepositAddress, TradingFeeInterface } from './base/types.js'; +import type { TransferEntry, IndexType, Int, OrderSide, Balances, OrderType, OHLCV, FundingRateHistory, Position, OrderBook, OrderRequest, FundingHistory, Order, Str, Trade, Transaction, Ticker, Tickers, Strings, Market, Currency, Leverage, Num, Account, MarginModification, Currencies, Dict, LeverageTier, LeverageTiers, int, FundingRate, DepositAddress, TradingFeeInterface, LedgerEntry } from './base/types.js'; /** * @class mexc * @augments Exchange @@ -641,6 +641,22 @@ export default class mexc extends Exchange { * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} */ fetchTransfers(code?: Str, since?: Int, limit?: Int, params?: {}): Promise; + /** + * @method + * @name mexc#fetchLedger + * @description fetch account-movement history as a unified ledger by composing MEXC deposits, withdrawals, and internal transfers + * @param {string} [code] unified currency code of the ledger entries, default is undefined + * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined + * @param {int} [limit] max number of ledger entries to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.includeDeposits] default true + * @param {boolean} [params.includeWithdrawals] default true + * @param {boolean} [params.includeTransfers] default true + * @returns {object[]} a list of [ledger structures]{@link https://docs.ccxt.com/#/?id=ledger} + */ + fetchLedger(code?: Str, since?: Int, limit?: Int, params?: {}): Promise; + transactionToLedgerEntry(transaction: Transaction): LedgerEntry; + transferToLedgerEntry(transfer: TransferEntry): LedgerEntry; /** * @method * @name mexc#transfer diff --git a/js/src/mexc.js b/js/src/mexc.js index 8736a98..5729f83 100644 --- a/js/src/mexc.js +++ b/js/src/mexc.js @@ -88,7 +88,7 @@ export default class mexc extends Exchange { 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchL2OrderBook': true, - 'fetchLedger': undefined, + 'fetchLedger': 'emulated', 'fetchLedgerEntry': undefined, 'fetchLeverage': true, 'fetchLeverages': false, @@ -5388,6 +5388,91 @@ export default class mexc extends Exchange { } return this.parseTransfers(resultList, currency, since, limit); } + /** + * @method + * @name mexc#fetchLedger + * @description fetch account-movement history as a unified ledger by composing MEXC deposits, withdrawals, and internal transfers + * @param {string} [code] unified currency code of the ledger entries, default is undefined + * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined + * @param {int} [limit] max number of ledger entries to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.includeDeposits] default true + * @param {boolean} [params.includeWithdrawals] default true + * @param {boolean} [params.includeTransfers] default true + * @returns {object[]} a list of [ledger structures]{@link https://docs.ccxt.com/#/?id=ledger} + */ + async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets(); + const includeDeposits = this.safeBool(params, 'includeDeposits', true); + const includeWithdrawals = this.safeBool(params, 'includeWithdrawals', true); + const includeTransfers = this.safeBool(params, 'includeTransfers', true); + params = this.omit(params, ['includeDeposits', 'includeWithdrawals', 'includeTransfers']); + const ledgerEntries = []; + if (includeDeposits) { + const deposits = await this.fetchDeposits(code, since, limit, this.extend({}, params)); + for (let i = 0; i < deposits.length; i++) { + ledgerEntries.push(this.transactionToLedgerEntry(deposits[i])); + } + } + if (includeWithdrawals) { + const withdrawals = await this.fetchWithdrawals(code, since, limit, this.extend({}, params)); + for (let i = 0; i < withdrawals.length; i++) { + ledgerEntries.push(this.transactionToLedgerEntry(withdrawals[i])); + } + } + if (includeTransfers) { + const transfers = await this.fetchTransfers(code, since, limit, this.extend({}, params)); + for (let i = 0; i < transfers.length; i++) { + ledgerEntries.push(this.transferToLedgerEntry(transfers[i])); + } + } + const uniqueEntries = this.removeRepeatedElementsFromArray(ledgerEntries); + const sortedEntries = this.sortBy(uniqueEntries, 'timestamp'); + return this.filterBySinceLimit(sortedEntries, since, limit); + } + transactionToLedgerEntry(transaction) { + const type = this.safeString(transaction, 'type'); + const currencyCode = this.safeString(transaction, 'currency'); + const direction = (type === 'withdrawal') ? 'out' : 'in'; + return this.safeLedgerEntry({ + 'info': transaction['info'], + 'id': this.safeString(transaction, 'id'), + 'timestamp': this.safeInteger(transaction, 'timestamp'), + 'datetime': this.safeString(transaction, 'datetime'), + 'direction': direction, + 'account': undefined, + 'referenceId': this.safeString(transaction, 'txid'), + 'referenceAccount': undefined, + 'type': type, + 'currency': currencyCode, + 'amount': this.safeNumber(transaction, 'amount'), + 'before': undefined, + 'after': undefined, + 'status': this.safeString(transaction, 'status'), + 'fee': this.safeValue(transaction, 'fee'), + }); + } + transferToLedgerEntry(transfer) { + const fromAccount = this.safeString(transfer, 'fromAccount'); + const toAccount = this.safeString(transfer, 'toAccount'); + return this.safeLedgerEntry({ + 'info': transfer['info'], + 'id': this.safeString(transfer, 'id'), + 'timestamp': this.safeInteger(transfer, 'timestamp'), + 'datetime': this.safeString(transfer, 'datetime'), + 'direction': undefined, + 'account': fromAccount, + 'referenceId': this.safeString(transfer, 'id'), + 'referenceAccount': toAccount, + 'type': 'transfer', + 'currency': this.safeString(transfer, 'currency'), + 'amount': this.safeNumber(transfer, 'amount'), + 'before': undefined, + 'after': undefined, + 'status': this.safeString(transfer, 'status'), + 'fee': undefined, + }); + } /** * @method * @name mexc#transfer diff --git a/ts/src/bitfinex.ts b/ts/src/bitfinex.ts index 3387b88..5323dbc 100644 --- a/ts/src/bitfinex.ts +++ b/ts/src/bitfinex.ts @@ -63,6 +63,7 @@ export default class bitfinex extends Exchange { 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, + 'fetchDeposits': true, 'fetchDepositsWithdrawals': true, 'fetchFundingHistory': false, 'fetchFundingRate': 'emulated', // emulated in exchange @@ -89,6 +90,7 @@ export default class bitfinex extends Exchange { 'fetchOrderBook': true, 'fetchOrderBooks': false, 'fetchOrderTrades': true, + 'fetchOrders': true, 'fetchPosition': false, 'fetchPositionMode': false, 'fetchPositions': true, @@ -100,6 +102,7 @@ export default class bitfinex extends Exchange { 'fetchTradingFees': true, 'fetchTransactionFees': undefined, 'fetchTransactions': 'emulated', + 'fetchTransfers': 'emulated', 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, @@ -109,6 +112,7 @@ export default class bitfinex extends Exchange { 'setPositionMode': false, 'signIn': false, 'transfer': true, + 'fetchWithdrawals': true, 'withdraw': true, }, 'timeframes': { @@ -1053,6 +1057,26 @@ export default class bitfinex extends Exchange { return this.parseTransfer ({ 'result': response }, currency); } + /** + * @method + * @name bitfinex#fetchTransfers + * @description fetch internal transfers as unified transfer structures from ledger entries + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest transfer, default is undefined + * @param {int} [limit] max number of transfers to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} + */ + async fetchTransfers (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + const ledger = await this.fetchLedger (code, since, limit, params); + const transfers = ledger.filter ((entry) => entry['type'] === 'transfer'); + const result = []; + for (let i = 0; i < transfers.length; i++) { + result.push (this.ledgerEntryToTransfer (transfers[i])); + } + return this.filterBySinceLimit (result, since, limit); + } + parseTransfer (transfer: Dict, currency: Currency = undefined): TransferEntry { // // transfer @@ -1097,6 +1121,20 @@ export default class bitfinex extends Exchange { }; } + ledgerEntryToTransfer (entry: LedgerEntry): TransferEntry { + return { + 'id': this.safeString (entry, 'id'), + 'timestamp': this.safeInteger (entry, 'timestamp'), + 'datetime': this.safeString (entry, 'datetime'), + 'status': this.safeString (entry, 'status'), + 'amount': this.safeNumber (entry, 'amount'), + 'currency': this.safeString (entry, 'currency'), + 'fromAccount': this.safeString (entry, 'account'), + 'toAccount': this.safeString (entry, 'referenceAccount'), + 'info': entry['info'], + }; + } + parseTransferStatus (status: Str): Str { const statuses: Dict = { 'SUCCESS': 'ok', @@ -2268,6 +2306,26 @@ export default class bitfinex extends Exchange { return this.parseOrders (ordersList, market, since, limit); } + /** + * @method + * @name bitfinex#fetchOrders + * @description fetches information on multiple orders made by the user + * @see https://docs.bitfinex.com/reference/rest-auth-retrieve-orders + * @see https://docs.bitfinex.com/reference/rest-auth-orders-history + * @param {string} symbol unified market symbol of the market orders were made in + * @param {int} [since] the earliest time in ms to fetch orders for + * @param {int} [limit] the maximum number of order structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + async fetchOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + const openOrders = await this.fetchOpenOrders (symbol, since, limit, this.extend ({}, params)); + const closedOrders = await this.fetchClosedOrders (symbol, since, limit, this.extend ({}, params)); + const uniqueOrders = this.removeRepeatedElementsFromArray (openOrders.concat (closedOrders), false); + const sortedOrders = this.sortBy (uniqueOrders, 'timestamp'); + return this.filterBySinceLimit (sortedOrders, since, limit); + } + /** * @method * @name bitfinex#fetchOrderTrades @@ -2749,6 +2807,40 @@ export default class bitfinex extends Exchange { return this.parseTransactions (response, currency, since, limit); } + /** + * @method + * @name bitfinex#fetchDeposits + * @description fetch all deposits made to an account + * @see https://docs.bitfinex.com/reference/rest-auth-movements + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest deposit, default is undefined + * @param {int} [limit] max number of deposits to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + async fetchDeposits (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + const transactions = await this.fetchDepositsWithdrawals (code, since, limit, params); + const deposits = transactions.filter ((transaction) => transaction['type'] === 'deposit'); + return this.filterBySinceLimit (deposits, since, limit); + } + + /** + * @method + * @name bitfinex#fetchWithdrawals + * @description fetch all withdrawals made from an account + * @see https://docs.bitfinex.com/reference/rest-auth-movements + * @param {string} [code] unified currency code, default is undefined + * @param {int} [since] timestamp in ms of the earliest withdrawal, default is undefined + * @param {int} [limit] max number of withdrawals to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + async fetchWithdrawals (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + const transactions = await this.fetchDepositsWithdrawals (code, since, limit, params); + const withdrawals = transactions.filter ((transaction) => transaction['type'] === 'withdrawal'); + return this.filterBySinceLimit (withdrawals, since, limit); + } + /** * @method * @name bitfinex#withdraw diff --git a/ts/src/bybit.ts b/ts/src/bybit.ts index 781b785..e9ceab9 100644 --- a/ts/src/bybit.ts +++ b/ts/src/bybit.ts @@ -112,7 +112,7 @@ export default class bybit extends Exchange { 'fetchOptionChain': true, 'fetchOrder': true, 'fetchOrderBook': true, - 'fetchOrders': false, + 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionHistory': 'emulated', @@ -5019,7 +5019,11 @@ export default class bybit extends Exchange { */ const enableUnifiedAccount = this.safeBool (res, 1); if (enableUnifiedAccount) { - throw new NotSupported (this.id + ' fetchOrders() is not supported after the 5/02 update for UTA accounts, please use fetchOpenOrders, fetchClosedOrders or fetchCanceledOrders'); + const openOrders = await this.fetchOpenOrders (symbol, since, limit, this.extend ({}, params)); + const historicalOrders = await this.fetchCanceledAndClosedOrders (symbol, since, limit, this.extend ({}, params)); + const uniqueOrders = this.removeRepeatedElementsFromArray (openOrders.concat (historicalOrders), false); + const sortedOrders = this.sortBy (uniqueOrders, 'timestamp'); + return this.filterBySinceLimit (sortedOrders, since, limit); } return await this.fetchOrdersClassic (symbol, since, limit, params); } diff --git a/ts/src/mexc.ts b/ts/src/mexc.ts index 4614d0b..c5a74d5 100644 --- a/ts/src/mexc.ts +++ b/ts/src/mexc.ts @@ -6,7 +6,7 @@ import { BadRequest, InvalidNonce, BadSymbol, InvalidOrder, InvalidAddress, Exch import { TICK_SIZE } from './base/functions/number.js'; import { Precise } from './base/Precise.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; -import type { TransferEntry, IndexType, Int, OrderSide, Balances, OrderType, OHLCV, FundingRateHistory, Position, OrderBook, OrderRequest, FundingHistory, Order, Str, Trade, Transaction, Ticker, Tickers, Strings, Market, Currency, Leverage, Num, Account, MarginModification, Currencies, Dict, LeverageTier, LeverageTiers, int, FundingRate, DepositAddress, TradingFeeInterface } from './base/types.js'; +import type { TransferEntry, IndexType, Int, OrderSide, Balances, OrderType, OHLCV, FundingRateHistory, Position, OrderBook, OrderRequest, FundingHistory, Order, Str, Trade, Transaction, Ticker, Tickers, Strings, Market, Currency, Leverage, Num, Account, MarginModification, Currencies, Dict, LeverageTier, LeverageTiers, int, FundingRate, DepositAddress, TradingFeeInterface, LedgerEntry } from './base/types.js'; // --------------------------------------------------------------------------- @@ -87,7 +87,7 @@ export default class mexc extends Exchange { 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchL2OrderBook': true, - 'fetchLedger': undefined, + 'fetchLedger': 'emulated', 'fetchLedgerEntry': undefined, 'fetchLeverage': true, 'fetchLeverages': false, @@ -5387,6 +5387,94 @@ export default class mexc extends Exchange { return this.parseTransfers (resultList, currency, since, limit); } + /** + * @method + * @name mexc#fetchLedger + * @description fetch account-movement history as a unified ledger by composing MEXC deposits, withdrawals, and internal transfers + * @param {string} [code] unified currency code of the ledger entries, default is undefined + * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined + * @param {int} [limit] max number of ledger entries to return, default is undefined + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.includeDeposits] default true + * @param {boolean} [params.includeWithdrawals] default true + * @param {boolean} [params.includeTransfers] default true + * @returns {object[]} a list of [ledger structures]{@link https://docs.ccxt.com/#/?id=ledger} + */ + async fetchLedger (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + await this.loadMarkets (); + const includeDeposits = this.safeBool (params, 'includeDeposits', true); + const includeWithdrawals = this.safeBool (params, 'includeWithdrawals', true); + const includeTransfers = this.safeBool (params, 'includeTransfers', true); + params = this.omit (params, [ 'includeDeposits', 'includeWithdrawals', 'includeTransfers' ]); + const ledgerEntries: LedgerEntry[] = []; + if (includeDeposits) { + const deposits = await this.fetchDeposits (code, since, limit, this.extend ({}, params)); + for (let i = 0; i < deposits.length; i++) { + ledgerEntries.push (this.transactionToLedgerEntry (deposits[i])); + } + } + if (includeWithdrawals) { + const withdrawals = await this.fetchWithdrawals (code, since, limit, this.extend ({}, params)); + for (let i = 0; i < withdrawals.length; i++) { + ledgerEntries.push (this.transactionToLedgerEntry (withdrawals[i])); + } + } + if (includeTransfers) { + const transfers = await this.fetchTransfers (code, since, limit, this.extend ({}, params)); + for (let i = 0; i < transfers.length; i++) { + ledgerEntries.push (this.transferToLedgerEntry (transfers[i])); + } + } + const uniqueEntries = this.removeRepeatedElementsFromArray (ledgerEntries); + const sortedEntries = this.sortBy (uniqueEntries, 'timestamp'); + return this.filterBySinceLimit (sortedEntries, since, limit); + } + + transactionToLedgerEntry (transaction: Transaction): LedgerEntry { + const type = this.safeString (transaction, 'type'); + const currencyCode = this.safeString (transaction, 'currency'); + const direction = (type === 'withdrawal') ? 'out' : 'in'; + return this.safeLedgerEntry ({ + 'info': transaction['info'], + 'id': this.safeString (transaction, 'id'), + 'timestamp': this.safeInteger (transaction, 'timestamp'), + 'datetime': this.safeString (transaction, 'datetime'), + 'direction': direction, + 'account': undefined, + 'referenceId': this.safeString (transaction, 'txid'), + 'referenceAccount': undefined, + 'type': type, + 'currency': currencyCode, + 'amount': this.safeNumber (transaction, 'amount'), + 'before': undefined, + 'after': undefined, + 'status': this.safeString (transaction, 'status'), + 'fee': this.safeValue (transaction, 'fee'), + }) as LedgerEntry; + } + + transferToLedgerEntry (transfer: TransferEntry): LedgerEntry { + const fromAccount = this.safeString (transfer, 'fromAccount'); + const toAccount = this.safeString (transfer, 'toAccount'); + return this.safeLedgerEntry ({ + 'info': transfer['info'], + 'id': this.safeString (transfer, 'id'), + 'timestamp': this.safeInteger (transfer, 'timestamp'), + 'datetime': this.safeString (transfer, 'datetime'), + 'direction': undefined, + 'account': fromAccount, + 'referenceId': this.safeString (transfer, 'id'), + 'referenceAccount': toAccount, + 'type': 'transfer', + 'currency': this.safeString (transfer, 'currency'), + 'amount': this.safeNumber (transfer, 'amount'), + 'before': undefined, + 'after': undefined, + 'status': this.safeString (transfer, 'status'), + 'fee': undefined, + }) as LedgerEntry; + } + /** * @method * @name mexc#transfer