diff --git a/src/abacus-ts/calculators/funding.ts b/src/abacus-ts/calculators/funding.ts new file mode 100644 index 000000000..d22cc175b --- /dev/null +++ b/src/abacus-ts/calculators/funding.ts @@ -0,0 +1,21 @@ +import { IndexerHistoricalFundingResponseObject } from '@/types/indexer/indexerApiGen'; + +import { FundingDirection } from '@/constants/markets'; + +import { MustBigNumber } from '@/lib/numbers'; + +export const getDirectionFromFundingRate = (fundingRate: string) => { + const fundingRateBN = MustBigNumber(fundingRate); + + return fundingRateBN.isZero() + ? FundingDirection.None + : fundingRateBN.isPositive() + ? FundingDirection.ToShort + : FundingDirection.ToLong; +}; + +export const mapFundingChartObject = (funding: IndexerHistoricalFundingResponseObject) => ({ + fundingRate: MustBigNumber(funding.rate).toNumber(), + time: new Date(funding.effectiveAt).getTime(), + direction: getDirectionFromFundingRate(funding.rate), +}); diff --git a/src/abacus-ts/rest/funding.ts b/src/abacus-ts/rest/funding.ts index dc1c4e874..fec23f419 100644 --- a/src/abacus-ts/rest/funding.ts +++ b/src/abacus-ts/rest/funding.ts @@ -1,3 +1,5 @@ +import { useMemo } from 'react'; + import { IndexerHistoricalFundingResponse } from '@/types/indexer/indexerApiGen'; import { useQuery } from '@tanstack/react-query'; @@ -6,13 +8,20 @@ import { timeUnits } from '@/constants/time'; import { useAppSelector } from '@/state/appTypes'; import { getCurrentMarketIdIfTradeable } from '@/state/perpetualsSelectors'; +import { isTruthy } from '@/lib/isTruthy'; +import { MustBigNumber } from '@/lib/numbers'; +import { orEmptyObj } from '@/lib/typeUtils'; + +import { getDirectionFromFundingRate, mapFundingChartObject } from '../calculators/funding'; +import { selectCurrentMarketInfo } from '../selectors/markets'; import { useIndexerClient } from './lib/useIndexer'; export const useCurrentMarketHistoricalFunding = () => { const { indexerClient, key: indexerKey } = useIndexerClient(); const currentMarketId = useAppSelector(getCurrentMarketIdIfTradeable); + const { nextFundingRate } = orEmptyObj(useAppSelector(selectCurrentMarketInfo)); - return useQuery({ + const historicalFundingQuery = useQuery({ enabled: Boolean(currentMarketId) && Boolean(indexerClient), queryKey: ['historicalFunding', currentMarketId, indexerKey], queryFn: async () => { @@ -24,9 +33,26 @@ export const useCurrentMarketHistoricalFunding = () => { const result: IndexerHistoricalFundingResponse = await indexerClient.markets.getPerpetualMarketHistoricalFunding(currentMarketId); - return result.historicalFunding; + + return result.historicalFunding.reverse().map(mapFundingChartObject); }, refetchInterval: timeUnits.hour, staleTime: timeUnits.hour, }); + + const data = useMemo(() => { + return [ + ...(historicalFundingQuery.data ?? []), + nextFundingRate != null && { + fundingRate: MustBigNumber(nextFundingRate).toNumber(), + time: Date.now(), + direction: getDirectionFromFundingRate(nextFundingRate), + }, + ].filter(isTruthy); + }, [historicalFundingQuery.data, nextFundingRate]); + + return { + ...historicalFundingQuery, + data, + }; }; diff --git a/src/views/charts/FundingChart/index.tsx b/src/views/charts/FundingChart/index.tsx index ff2104586..64de28a1a 100644 --- a/src/views/charts/FundingChart/index.tsx +++ b/src/views/charts/FundingChart/index.tsx @@ -1,8 +1,8 @@ import { useState } from 'react'; +import { BonsaiHooks } from '@/abacus-ts/ontology'; import { curveMonotoneX, curveStepAfter } from '@visx/curve'; import type { TooltipContextType } from '@visx/xychart'; -import { shallowEqual } from 'react-redux'; import styled, { css } from 'styled-components'; import { ButtonSize } from '@/constants/buttons'; @@ -22,9 +22,6 @@ import { ToggleGroup } from '@/components/ToggleGroup'; import { AxisLabelOutput } from '@/components/visx/AxisLabelOutput'; import { TimeSeriesChart } from '@/components/visx/TimeSeriesChart'; -import { useAppSelector } from '@/state/appTypes'; -import { calculateFundingRateHistory } from '@/state/perpetualsCalculators'; - import { MustBigNumber } from '@/lib/numbers'; import { FundingChartTooltipContent } from './Tooltip'; @@ -49,7 +46,7 @@ export const FundingChart = ({ selectedLocale }: ElementProps) => { const stringGetter = useStringGetter(); // Chart data - const data = useAppSelector(calculateFundingRateHistory, shallowEqual); + const { data, isLoading, isError } = BonsaiHooks.useCurrentMarketHistoricalFunding(); const latestDatum = data[data.length - 1]; @@ -129,7 +126,17 @@ export const FundingChart = ({ selectedLocale }: ElementProps) => { onTooltipContext={(ttContext) => setTooltipContext(ttContext)} minZoomDomain={FUNDING_RATE_TIME_RESOLUTION * 4} numGridLines={1} - slotEmpty={} + slotEmpty={ + isLoading ? ( + + ) : ( + isError && ( +
+ {stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG })} +
+ ) + ) + } >