Repository: ccxt/ccxt
File: ts/src/bybit.ts (TypeScript)

Code before:
        for (let i = 0; i < tickerList.length; i++) {
            tickerList[i]['timestamp'] = timestamp; // will be removed inside the parser
        }
        return this.parseFundingRates (tickerList, symbols);
    }

    /**
     * @method
     * @name bybit#fetchFundingRateHistory
     * @description fetches historical funding rate prices
     * @see https://bybit-exchange.github.io/docs/v5/market/history-fund-rate
     * @param {string} symbol unified symbol of the market to fetch the funding rate history for
     * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
     * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-history-structure} to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] timestamp in ms of the latest funding rate
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-history-structure}
     */
    async fetchFundingRateHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchFundingRateHistory() requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const fundingTimeFrameMins = this.safeInteger (market['info'], 'fundingInterval');
        let paginate = false;
        [ paginate, params ] = this.handleOptionAndParams (params, 'fetchFundingRateHistory', 'paginate');
        if (paginate) {
            let defaultTf = '8h';
            if (fundingTimeFrameMins !== undefined) {
                defaultTf = this.timeframeFromMilliseconds (fundingTimeFrameMins * 60 * 1000);
            }
            return await this.fetchPaginatedCallDeterministic ('fetchFundingRateHistory', symbol, since, limit, defaultTf, params, 200) as FundingRateHistory[];
        }
        if (limit === undefined) {
            limit = 200;
        }
        const request: Dict = {
            // 'category': '', // Product type. linear,inverse
            // 'symbol': '', // Symbol name
            // 'startTime': 0, // The start timestamp (ms)
            // 'endTime': 0, // The end timestamp (ms)
            'limit': limit, // Limit for data size per page. [1, 200]. Default: 200
        };
        symbol = market['symbol'];
        request['symbol'] = market['id'];
        let type = undefined;
        [ type, params ] = this.getBybitType ('fetchFundingRateHistory', market, params);
        if (type === 'spot' || type === 'option') {
            throw new NotSupported (this.id + ' fetchFundingRateHistory() only support linear and inverse market');

Review comment (suggestion):
I don't think this is safe to use. 
it'll only reflect the current funding Interval - not how funding interval was at "since" or anytime between since and until (which is what you'd really need).


Example: if a pair _now_ reports an interval of 8h - this won't mean that in May 2025, it couldn't have had a funding interval of 1h - going up to 4h in september - and then to 8h starting this January.

When i looked at this problematic i found that the only _reliable_ way for pagination offsets with dynamic funding fees is to either use "what you got last + 1" - or (if done in parallel/async and you need to know the frequency beforehand) - assume a funding interval of 1h - even though that might mean you'll do 8x the requests necessary. 
That's still a better tradeoff than ending up with funding fees that are missing part of a month.

Code after:
        for (let i = 0; i < tickerList.length; i++) {
            tickerList[i]['timestamp'] = timestamp; // will be removed inside the parser
        }
        return this.parseFundingRates (tickerList, symbols);
    }

    /**
     * @method
     * @name bybit#fetchFundingRateHistory
     * @description fetches historical funding rate prices
     * @see https://bybit-exchange.github.io/docs/v5/market/history-fund-rate
     * @param {string} symbol unified symbol of the market to fetch the funding rate history for
     * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
     * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-history-structure} to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] timestamp in ms of the latest funding rate
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-history-structure}
     */
    async fetchFundingRateHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchFundingRateHistory() requires a symbol argument');
        }
        await this.loadMarkets ();
        let paginate = false;
        [ paginate, params ] = this.handleOptionAndParams (params, 'fetchFundingRateHistory', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic ('fetchFundingRateHistory', symbol, since, limit, params, 200) as FundingRateHistory[];
        }
        if (limit === undefined) {
            limit = 200;
        }
        const request: Dict = {
            // 'category': '', // Product type. linear,inverse
            // 'symbol': '', // Symbol name
            // 'startTime': 0, // The start timestamp (ms)
            // 'endTime': 0, // The end timestamp (ms)
            'limit': limit, // Limit for data size per page. [1, 200]. Default: 200
        };
        const market = this.market (symbol);
        const fundingTimeFrameMins = this.safeInteger (market['info'], 'fundingInterval');
        symbol = market['symbol'];
        request['symbol'] = market['id'];
        let type = undefined;
        [ type, params ] = this.getBybitType ('fetchFundingRateHistory', market, params);
        if (type === 'spot' || type === 'option') {
            throw new NotSupported (this.id + ' fetchFundingRateHistory() only support linear and inverse market');
        }
        request['category'] = type;
        if (since !== undefined) {
            request['startTime'] = since;