re-arrange layout
This commit is contained in:
parent
1612c61819
commit
1e46d26141
|
@ -0,0 +1,67 @@
|
||||||
|
import mangoStore from '@store/mangoStore'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { formatYAxis } from 'utils/formatting'
|
||||||
|
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
||||||
|
import NetDepositsChart from './NetDepositsChart'
|
||||||
|
|
||||||
|
const DepositsAndBorrows = () => {
|
||||||
|
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||||
|
const mangoStats = mangoStore((s) => s.tokenStats.mangoStats)
|
||||||
|
const loadingStats = mangoStore((s) => s.tokenStats.loading)
|
||||||
|
const [borrowDaysToShow, setBorrowDaysToShow] = useState('30')
|
||||||
|
const [depositDaysToShow, setDepositDaysToShow] = useState('30')
|
||||||
|
const tokenStatsInitialLoad = mangoStore((s) => s.tokenStats.initialLoad)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!tokenStatsInitialLoad) {
|
||||||
|
const actions = mangoStore.getState().actions
|
||||||
|
actions.fetchTokenStats()
|
||||||
|
}
|
||||||
|
}, [tokenStatsInitialLoad])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="my-4 px-6 text-lg">Deposits and Borrows</h2>
|
||||||
|
<div className="grid grid-cols-2 border-t border-th-bkg-3">
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 ">
|
||||||
|
<DetailedAreaOrBarChart
|
||||||
|
changeAsPercent
|
||||||
|
data={mangoStats}
|
||||||
|
daysToShow={depositDaysToShow}
|
||||||
|
setDaysToShow={setDepositDaysToShow}
|
||||||
|
loading={loadingStats}
|
||||||
|
heightClass="h-64"
|
||||||
|
loaderHeightClass="h-[350px]"
|
||||||
|
prefix="$"
|
||||||
|
tickFormat={(x) => `$${formatYAxis(x)}`}
|
||||||
|
title={t('total-deposit-value')}
|
||||||
|
xKey="date"
|
||||||
|
yKey={'depositValue'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:pl-6">
|
||||||
|
<DetailedAreaOrBarChart
|
||||||
|
changeAsPercent
|
||||||
|
data={mangoStats}
|
||||||
|
daysToShow={borrowDaysToShow}
|
||||||
|
setDaysToShow={setBorrowDaysToShow}
|
||||||
|
heightClass="h-64"
|
||||||
|
loaderHeightClass="h-[350px]"
|
||||||
|
loading={loadingStats}
|
||||||
|
prefix="$"
|
||||||
|
tickFormat={(x) => `$${formatYAxis(x)}`}
|
||||||
|
title={t('total-borrow-value')}
|
||||||
|
xKey="date"
|
||||||
|
yKey={'borrowValue'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:pl-6">
|
||||||
|
<NetDepositsChart />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DepositsAndBorrows
|
|
@ -0,0 +1,175 @@
|
||||||
|
import Switch from '@components/forms/Switch'
|
||||||
|
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
||||||
|
import mangoStore from '@store/mangoStore'
|
||||||
|
import usePerpStatsChartData from 'hooks/usePerpStatsChartData'
|
||||||
|
import { useMemo, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { MangoTokenStatsItem } from 'types'
|
||||||
|
import { formatYAxis } from 'utils/formatting'
|
||||||
|
import { groupPerpByHourlyInterval } from './Volume'
|
||||||
|
|
||||||
|
interface GroupedTokenDataItem extends MangoTokenStatsItem {
|
||||||
|
intervalStartMillis: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupTokenByHourlyInterval = (
|
||||||
|
data: MangoTokenStatsItem[],
|
||||||
|
intervalDurationHours: number,
|
||||||
|
) => {
|
||||||
|
const intervalMillis = intervalDurationHours * 60 * 60 * 1000
|
||||||
|
const groupedData = []
|
||||||
|
let currentGroup: GroupedTokenDataItem | null = null
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const obj = data[i]
|
||||||
|
const date = new Date(obj.date)
|
||||||
|
const intervalStartMillis =
|
||||||
|
Math.floor(date.getTime() / intervalMillis) * intervalMillis
|
||||||
|
if (
|
||||||
|
!currentGroup ||
|
||||||
|
currentGroup.intervalStartMillis !== intervalStartMillis
|
||||||
|
) {
|
||||||
|
currentGroup = {
|
||||||
|
...obj,
|
||||||
|
intervalStartMillis: intervalStartMillis,
|
||||||
|
}
|
||||||
|
groupedData.push(currentGroup)
|
||||||
|
} else {
|
||||||
|
currentGroup.feesCollected += obj.feesCollected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupedData
|
||||||
|
}
|
||||||
|
|
||||||
|
const Fees = () => {
|
||||||
|
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||||
|
const mangoStats = mangoStore((s) => s.tokenStats.mangoStats)
|
||||||
|
const loadingStats = mangoStore((s) => s.tokenStats.loading)
|
||||||
|
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
|
||||||
|
const [feesDaysToShow, setFeesDaysToShow] = useState('30')
|
||||||
|
const [showCumulativeFees, setShowCumulativeFees] = useState(true)
|
||||||
|
const [feesPerpDaysToShow, setFeesPerpDaysToShow] = useState('30')
|
||||||
|
const [showCumulativePerpFees, setShowCumulativePerpFees] = useState(true)
|
||||||
|
const { feeValues: perpFeeChartData } = usePerpStatsChartData()
|
||||||
|
|
||||||
|
const tokenFeesChartData = useMemo(() => {
|
||||||
|
if (!mangoStats.length) return []
|
||||||
|
if (showCumulativeFees) {
|
||||||
|
return mangoStats
|
||||||
|
} else {
|
||||||
|
const transformedData = []
|
||||||
|
for (let i = 1; i < mangoStats.length; i++) {
|
||||||
|
const currentInterval = { ...mangoStats[i] }
|
||||||
|
const previousInterval = mangoStats[i - 1]
|
||||||
|
|
||||||
|
// Calculate the absolute fees for the current interval
|
||||||
|
currentInterval.feesCollected =
|
||||||
|
currentInterval.feesCollected - previousInterval.feesCollected
|
||||||
|
|
||||||
|
transformedData.push(currentInterval)
|
||||||
|
}
|
||||||
|
transformedData.unshift(mangoStats[0])
|
||||||
|
|
||||||
|
if (feesDaysToShow === '30') {
|
||||||
|
return groupTokenByHourlyInterval(transformedData, 24)
|
||||||
|
} else if (feesDaysToShow === '7') {
|
||||||
|
return groupTokenByHourlyInterval(transformedData, 4)
|
||||||
|
} else return transformedData
|
||||||
|
}
|
||||||
|
}, [mangoStats, feesDaysToShow, showCumulativeFees])
|
||||||
|
|
||||||
|
const perpFeeValues = useMemo(() => {
|
||||||
|
if (!perpFeeChartData || !perpFeeChartData.length) return []
|
||||||
|
|
||||||
|
let feeChartData = perpFeeChartData
|
||||||
|
if (!showCumulativePerpFees) {
|
||||||
|
const transformedData = []
|
||||||
|
for (let i = 1; i < perpFeeChartData.length; i++) {
|
||||||
|
const currentInterval = { ...perpFeeChartData[i] }
|
||||||
|
const previousInterval = perpFeeChartData[i - 1]
|
||||||
|
|
||||||
|
// Calculate the absolute fees for the current interval
|
||||||
|
currentInterval.value = currentInterval.value - previousInterval.value
|
||||||
|
|
||||||
|
transformedData.push(currentInterval)
|
||||||
|
}
|
||||||
|
transformedData.unshift(perpFeeChartData[0])
|
||||||
|
|
||||||
|
if (feesDaysToShow === '30') {
|
||||||
|
feeChartData = groupPerpByHourlyInterval(transformedData, 24)
|
||||||
|
} else if (feesDaysToShow === '7') {
|
||||||
|
feeChartData = groupPerpByHourlyInterval(transformedData, 4)
|
||||||
|
} else feeChartData = transformedData
|
||||||
|
}
|
||||||
|
|
||||||
|
return feeChartData
|
||||||
|
}, [feesDaysToShow, perpFeeChartData, showCumulativePerpFees])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="my-4 px-6 text-lg">Fees</h2>
|
||||||
|
<div className="grid grid-cols-2 border-t border-th-bkg-3">
|
||||||
|
<div className="col-span-2 flex flex-col justify-between border-b border-th-bkg-3 md:col-span-1">
|
||||||
|
<div className="px-4 pt-4 md:px-6">
|
||||||
|
<DetailedAreaOrBarChart
|
||||||
|
changeAsPercent
|
||||||
|
data={tokenFeesChartData}
|
||||||
|
daysToShow={feesDaysToShow}
|
||||||
|
setDaysToShow={setFeesDaysToShow}
|
||||||
|
heightClass="h-64"
|
||||||
|
loaderHeightClass="h-[350px]"
|
||||||
|
loading={loadingStats}
|
||||||
|
prefix="$"
|
||||||
|
tickFormat={(x) => `$${formatYAxis(x)}`}
|
||||||
|
title={t('token:token-fees-collected')}
|
||||||
|
tooltipContent={t('token:tooltip-token-fees-collected')}
|
||||||
|
xKey="date"
|
||||||
|
yKey={'feesCollected'}
|
||||||
|
chartType={showCumulativeFees ? 'area' : 'bar'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end px-4 pb-4 md:px-6">
|
||||||
|
<Switch
|
||||||
|
checked={showCumulativeFees}
|
||||||
|
onChange={() => setShowCumulativeFees(!showCumulativeFees)}
|
||||||
|
small
|
||||||
|
>
|
||||||
|
{t('stats:show-cumulative')}
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 flex flex-col justify-between border-b border-th-bkg-3 md:col-span-1">
|
||||||
|
<div className="px-4 pt-4 md:px-6">
|
||||||
|
<DetailedAreaOrBarChart
|
||||||
|
changeAsPercent
|
||||||
|
data={perpFeeValues}
|
||||||
|
daysToShow={feesPerpDaysToShow}
|
||||||
|
setDaysToShow={setFeesPerpDaysToShow}
|
||||||
|
heightClass="h-64"
|
||||||
|
loading={loadingPerpStats}
|
||||||
|
loaderHeightClass="h-[350px]"
|
||||||
|
prefix="$"
|
||||||
|
tickFormat={(x) => `$${formatYAxis(x)}`}
|
||||||
|
title="Perp Fees"
|
||||||
|
xKey="date"
|
||||||
|
yKey="value"
|
||||||
|
chartType={showCumulativePerpFees ? 'area' : 'bar'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end px-4 pb-4 md:px-6">
|
||||||
|
<Switch
|
||||||
|
checked={showCumulativePerpFees}
|
||||||
|
onChange={() =>
|
||||||
|
setShowCumulativePerpFees(!showCumulativePerpFees)
|
||||||
|
}
|
||||||
|
small
|
||||||
|
>
|
||||||
|
{t('stats:show-cumulative')}
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Fees
|
|
@ -0,0 +1,24 @@
|
||||||
|
import LiquidationsAtRiskChart from './LiquidationsAtRiskChart'
|
||||||
|
import PerpLiquidationsChart from './PerpLiquidationsChart'
|
||||||
|
import TokenLiquidationsChart from './TokenLiquidationsChart'
|
||||||
|
|
||||||
|
const Liquidations = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="my-4 px-6 text-lg">Liquidations</h2>
|
||||||
|
<div className="grid grid-cols-2 border-t border-th-bkg-3">
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:border-r">
|
||||||
|
<TokenLiquidationsChart />
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:pl-6">
|
||||||
|
<PerpLiquidationsChart />
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4">
|
||||||
|
<LiquidationsAtRiskChart />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Liquidations
|
|
@ -1,21 +0,0 @@
|
||||||
import LiquidationsAtRiskChart from './LiquidationsAtRiskChart'
|
|
||||||
import PerpLiquidationsChart from './PerpLiquidationsChart'
|
|
||||||
import TokenLiquidationsChart from './TokenLiquidationsChart'
|
|
||||||
|
|
||||||
const LiquidationsCharts = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1">
|
|
||||||
<LiquidationsAtRiskChart />
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:border-r">
|
|
||||||
<TokenLiquidationsChart />
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:pl-6">
|
|
||||||
<PerpLiquidationsChart />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LiquidationsCharts
|
|
|
@ -1,264 +0,0 @@
|
||||||
import { useTranslation } from 'next-i18next'
|
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
|
||||||
import mangoStore from '@store/mangoStore'
|
|
||||||
import { PerpStatsItem } from 'types'
|
|
||||||
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
|
||||||
import { formatYAxis } from 'utils/formatting'
|
|
||||||
import Switch from '@components/forms/Switch'
|
|
||||||
|
|
||||||
interface ValueItem {
|
|
||||||
date: string
|
|
||||||
value: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PerpStatsData {
|
|
||||||
feeValues: ValueItem[]
|
|
||||||
openInterestValues: ValueItem[]
|
|
||||||
volumeValues: ValueItem[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GroupedDataItem extends ValueItem {
|
|
||||||
intervalStartMillis: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const groupByHourlyInterval = (
|
|
||||||
data: ValueItem[],
|
|
||||||
intervalDurationHours: number,
|
|
||||||
) => {
|
|
||||||
const intervalMillis = intervalDurationHours * 60 * 60 * 1000
|
|
||||||
const groupedData = []
|
|
||||||
let currentGroup: GroupedDataItem | null = null
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
const obj = data[i]
|
|
||||||
const date = new Date(obj.date)
|
|
||||||
const intervalStartMillis =
|
|
||||||
Math.floor(date.getTime() / intervalMillis) * intervalMillis
|
|
||||||
if (
|
|
||||||
!currentGroup ||
|
|
||||||
currentGroup.intervalStartMillis !== intervalStartMillis
|
|
||||||
) {
|
|
||||||
currentGroup = {
|
|
||||||
...obj,
|
|
||||||
intervalStartMillis: intervalStartMillis,
|
|
||||||
}
|
|
||||||
groupedData.push(currentGroup)
|
|
||||||
} else {
|
|
||||||
currentGroup.value += obj.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return groupedData
|
|
||||||
}
|
|
||||||
|
|
||||||
const MangoPerpStatsCharts = () => {
|
|
||||||
const { t } = useTranslation(['common', 'stats', 'token', 'trade'])
|
|
||||||
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
|
|
||||||
const perpStats = mangoStore((s) => s.perpStats.data)
|
|
||||||
const [feesDaysToShow, setFeesDaysToShow] = useState('30')
|
|
||||||
const [oiDaysToShow, setOiDaysToShow] = useState('30')
|
|
||||||
const [volumeDaysToShow, setVolumeDaysToShow] = useState('30')
|
|
||||||
const [showCumulativeFees, setShowCumulativeFees] = useState(true)
|
|
||||||
const [showCumulativeVolume, setShowCumulativeVolume] = useState(true)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!perpStats || !perpStats.length) {
|
|
||||||
const actions = mangoStore.getState().actions
|
|
||||||
actions.fetchPerpStats()
|
|
||||||
}
|
|
||||||
}, [perpStats])
|
|
||||||
|
|
||||||
const [feeValues, openInterestValues, volumeValues] = useMemo(() => {
|
|
||||||
if (!perpStats || !perpStats.length) return [[], [], []]
|
|
||||||
const data = perpStats.reduce(
|
|
||||||
(a: PerpStatsData, c: PerpStatsItem) => {
|
|
||||||
const hasDateFee = a.feeValues.find(
|
|
||||||
(d: ValueItem) => d.date === c.date_hour,
|
|
||||||
)
|
|
||||||
|
|
||||||
const hasDateOpenInterest = a.openInterestValues.find(
|
|
||||||
(d: ValueItem) => d.date === c.date_hour,
|
|
||||||
)
|
|
||||||
|
|
||||||
const hasDateVolume = a.volumeValues.find(
|
|
||||||
(d: ValueItem) => d.date === c.date_hour,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!hasDateFee) {
|
|
||||||
a.feeValues.push({
|
|
||||||
date: c.date_hour,
|
|
||||||
value: c.total_fees,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
hasDateFee.value += c.total_fees
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasDateOpenInterest) {
|
|
||||||
a.openInterestValues.push({
|
|
||||||
date: c.date_hour,
|
|
||||||
value: Math.floor(c.open_interest * c.price),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
hasDateOpenInterest.value += Math.floor(c.open_interest * c.price)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasDateVolume) {
|
|
||||||
a.volumeValues.push({
|
|
||||||
date: c.date_hour,
|
|
||||||
value: c.cumulative_quote_volume,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
hasDateVolume.value += c.cumulative_quote_volume
|
|
||||||
}
|
|
||||||
|
|
||||||
return a
|
|
||||||
},
|
|
||||||
{ feeValues: [], openInterestValues: [], volumeValues: [] },
|
|
||||||
)
|
|
||||||
|
|
||||||
const { feeValues, openInterestValues, volumeValues } = data
|
|
||||||
|
|
||||||
const sortedFeeValues = feeValues.sort(
|
|
||||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
|
||||||
)
|
|
||||||
const sortedOpenInterestValues = openInterestValues.sort(
|
|
||||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
|
||||||
)
|
|
||||||
const sortedVolumeValues = volumeValues.sort(
|
|
||||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
|
||||||
)
|
|
||||||
|
|
||||||
let feeChartData = sortedFeeValues
|
|
||||||
if (!showCumulativeFees) {
|
|
||||||
const transformedData = []
|
|
||||||
for (let i = 1; i < sortedFeeValues.length; i++) {
|
|
||||||
const currentInterval = { ...sortedFeeValues[i] }
|
|
||||||
const previousInterval = sortedFeeValues[i - 1]
|
|
||||||
|
|
||||||
// Calculate the absolute fees for the current interval
|
|
||||||
currentInterval.value = currentInterval.value - previousInterval.value
|
|
||||||
|
|
||||||
transformedData.push(currentInterval)
|
|
||||||
}
|
|
||||||
transformedData.unshift(sortedFeeValues[0])
|
|
||||||
|
|
||||||
if (feesDaysToShow === '30') {
|
|
||||||
feeChartData = groupByHourlyInterval(transformedData, 24)
|
|
||||||
} else if (feesDaysToShow === '7') {
|
|
||||||
feeChartData = groupByHourlyInterval(transformedData, 4)
|
|
||||||
} else feeChartData = transformedData
|
|
||||||
}
|
|
||||||
|
|
||||||
let volumeChartData = sortedVolumeValues
|
|
||||||
if (!showCumulativeVolume) {
|
|
||||||
const transformedData = []
|
|
||||||
for (let i = 1; i < sortedVolumeValues.length; i++) {
|
|
||||||
const currentInterval = { ...sortedVolumeValues[i] }
|
|
||||||
const previousInterval = sortedVolumeValues[i - 1]
|
|
||||||
|
|
||||||
// Calculate the absolute fees for the current interval
|
|
||||||
currentInterval.value = currentInterval.value - previousInterval.value
|
|
||||||
|
|
||||||
transformedData.push(currentInterval)
|
|
||||||
}
|
|
||||||
transformedData.unshift(sortedVolumeValues[0])
|
|
||||||
|
|
||||||
if (volumeDaysToShow === '30') {
|
|
||||||
volumeChartData = groupByHourlyInterval(transformedData, 24)
|
|
||||||
} else if (volumeDaysToShow === '7') {
|
|
||||||
volumeChartData = groupByHourlyInterval(transformedData, 4)
|
|
||||||
} else volumeChartData = transformedData
|
|
||||||
}
|
|
||||||
|
|
||||||
return [feeChartData, sortedOpenInterestValues, volumeChartData]
|
|
||||||
}, [
|
|
||||||
feesDaysToShow,
|
|
||||||
perpStats,
|
|
||||||
showCumulativeFees,
|
|
||||||
showCumulativeVolume,
|
|
||||||
volumeDaysToShow,
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{feeValues.length ? (
|
|
||||||
<div className="col-span-2 flex flex-col justify-between border-b border-th-bkg-3 md:col-span-1 md:border-r">
|
|
||||||
<div className="px-4 pt-4 md:px-6">
|
|
||||||
<DetailedAreaOrBarChart
|
|
||||||
changeAsPercent
|
|
||||||
data={feeValues}
|
|
||||||
daysToShow={feesDaysToShow}
|
|
||||||
setDaysToShow={setFeesDaysToShow}
|
|
||||||
heightClass="h-64"
|
|
||||||
loading={loadingPerpStats}
|
|
||||||
loaderHeightClass="h-[350px]"
|
|
||||||
prefix="$"
|
|
||||||
tickFormat={(x) => `$${formatYAxis(x)}`}
|
|
||||||
title="Perp Fees"
|
|
||||||
xKey="date"
|
|
||||||
yKey="value"
|
|
||||||
chartType={showCumulativeFees ? 'area' : 'bar'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex justify-end border-t border-th-bkg-3 px-4 py-2 md:px-6">
|
|
||||||
<Switch
|
|
||||||
checked={showCumulativeFees}
|
|
||||||
onChange={() => setShowCumulativeFees(!showCumulativeFees)}
|
|
||||||
small
|
|
||||||
>
|
|
||||||
{t('stats:show-cumulative')}
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{openInterestValues.length ? (
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-4 py-4 md:col-span-1 md:px-6">
|
|
||||||
<DetailedAreaOrBarChart
|
|
||||||
changeAsPercent
|
|
||||||
data={openInterestValues}
|
|
||||||
daysToShow={oiDaysToShow}
|
|
||||||
setDaysToShow={setOiDaysToShow}
|
|
||||||
heightClass="h-64"
|
|
||||||
loading={loadingPerpStats}
|
|
||||||
loaderHeightClass="h-[350px]"
|
|
||||||
prefix="$"
|
|
||||||
tickFormat={(x) => `$${formatYAxis(x)}`}
|
|
||||||
title={t('stats:perp-open-interest')}
|
|
||||||
xKey="date"
|
|
||||||
yKey="value"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{volumeValues.length ? (
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 md:col-span-1 md:border-r">
|
|
||||||
<div className="px-4 pt-4 md:px-6">
|
|
||||||
<DetailedAreaOrBarChart
|
|
||||||
changeAsPercent
|
|
||||||
data={volumeValues}
|
|
||||||
daysToShow={volumeDaysToShow}
|
|
||||||
setDaysToShow={setVolumeDaysToShow}
|
|
||||||
heightClass="h-64"
|
|
||||||
loading={loadingPerpStats}
|
|
||||||
loaderHeightClass="h-[350px]"
|
|
||||||
prefix="$"
|
|
||||||
tickFormat={(x) => `$${formatYAxis(x)}`}
|
|
||||||
title={t('stats:perp-volume')}
|
|
||||||
xKey="date"
|
|
||||||
yKey="value"
|
|
||||||
chartType={showCumulativeVolume ? 'area' : 'bar'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex justify-end border-t border-th-bkg-3 px-4 py-2 md:px-6">
|
|
||||||
<Switch
|
|
||||||
checked={showCumulativeVolume}
|
|
||||||
onChange={() => setShowCumulativeVolume(!showCumulativeVolume)}
|
|
||||||
small
|
|
||||||
>
|
|
||||||
{t('stats:show-cumulative')}
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MangoPerpStatsCharts
|
|
|
@ -1,14 +1,16 @@
|
||||||
import LiquidationsCharts from './LiquidationsCharts'
|
import Liquidations from './Liquidations'
|
||||||
import MangoPerpStatsCharts from './MangoPerpStatsCharts'
|
import DepositsAndBorrows from './DepositsAndBorrows'
|
||||||
import TokenStatsCharts from './TokenStatsCharts'
|
import Fees from './Fees'
|
||||||
|
import Volume from './Volume'
|
||||||
|
|
||||||
const MangoStats = () => {
|
const MangoStats = () => {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-2">
|
<>
|
||||||
<TokenStatsCharts />
|
<DepositsAndBorrows />
|
||||||
<MangoPerpStatsCharts />
|
<Fees />
|
||||||
<LiquidationsCharts />
|
<Volume />
|
||||||
</div>
|
<Liquidations />
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
||||||
|
import mangoStore from '@store/mangoStore'
|
||||||
|
import usePerpStatsChartData from 'hooks/usePerpStatsChartData'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { formatYAxis } from 'utils/formatting'
|
||||||
|
|
||||||
|
const OpenInterest = () => {
|
||||||
|
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||||
|
const [oiDaysToShow, setOiDaysToShow] = useState('30')
|
||||||
|
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
|
||||||
|
const { openInterestValues } = usePerpStatsChartData()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>Open Interest</h2>
|
||||||
|
<div className="grid grid-cols-1">
|
||||||
|
<div className="border-b border-th-bkg-3 px-4 py-4 md:px-6">
|
||||||
|
<DetailedAreaOrBarChart
|
||||||
|
changeAsPercent
|
||||||
|
data={openInterestValues}
|
||||||
|
daysToShow={oiDaysToShow}
|
||||||
|
setDaysToShow={setOiDaysToShow}
|
||||||
|
heightClass="h-64"
|
||||||
|
loading={loadingPerpStats}
|
||||||
|
loaderHeightClass="h-[350px]"
|
||||||
|
prefix="$"
|
||||||
|
tickFormat={(x) => `$${formatYAxis(x)}`}
|
||||||
|
title={t('stats:perp-open-interest')}
|
||||||
|
xKey="date"
|
||||||
|
yKey="value"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OpenInterest
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
import { MANGO_DATA_API_URL } from 'utils/constants'
|
||||||
|
|
||||||
|
export const fetchSwapVolume = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${MANGO_DATA_API_URL}/stats/mango-swap-volume`,
|
||||||
|
)
|
||||||
|
const data = await response.json()
|
||||||
|
return data
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Failed to fetch swap volume', e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SwapVolumeChart = () => {
|
||||||
|
const { data } = useQuery(['mango-swap-volume'], () => fetchSwapVolume(), {
|
||||||
|
cacheTime: 1000 * 60 * 10,
|
||||||
|
staleTime: 1000 * 60,
|
||||||
|
retry: 3,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
|
return <div />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SwapVolumeChart
|
|
@ -1,155 +0,0 @@
|
||||||
import mangoStore from '@store/mangoStore'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
|
||||||
import { formatYAxis } from 'utils/formatting'
|
|
||||||
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
|
||||||
import { MangoTokenStatsItem } from 'types'
|
|
||||||
import Switch from '@components/forms/Switch'
|
|
||||||
import NetDepositsChart from './NetDepositsChart'
|
|
||||||
|
|
||||||
interface GroupedDataItem extends MangoTokenStatsItem {
|
|
||||||
intervalStartMillis: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const groupByHourlyInterval = (
|
|
||||||
data: MangoTokenStatsItem[],
|
|
||||||
intervalDurationHours: number,
|
|
||||||
) => {
|
|
||||||
const intervalMillis = intervalDurationHours * 60 * 60 * 1000
|
|
||||||
const groupedData = []
|
|
||||||
let currentGroup: GroupedDataItem | null = null
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
const obj = data[i]
|
|
||||||
const date = new Date(obj.date)
|
|
||||||
const intervalStartMillis =
|
|
||||||
Math.floor(date.getTime() / intervalMillis) * intervalMillis
|
|
||||||
if (
|
|
||||||
!currentGroup ||
|
|
||||||
currentGroup.intervalStartMillis !== intervalStartMillis
|
|
||||||
) {
|
|
||||||
currentGroup = {
|
|
||||||
...obj,
|
|
||||||
intervalStartMillis: intervalStartMillis,
|
|
||||||
}
|
|
||||||
groupedData.push(currentGroup)
|
|
||||||
} else {
|
|
||||||
currentGroup.feesCollected += obj.feesCollected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return groupedData
|
|
||||||
}
|
|
||||||
|
|
||||||
const TokenStatsCharts = () => {
|
|
||||||
const { t } = useTranslation(['common', 'token', 'trade'])
|
|
||||||
const mangoStats = mangoStore((s) => s.tokenStats.mangoStats)
|
|
||||||
const loadingStats = mangoStore((s) => s.tokenStats.loading)
|
|
||||||
const [borrowDaysToShow, setBorrowDaysToShow] = useState('30')
|
|
||||||
const [depositDaysToShow, setDepositDaysToShow] = useState('30')
|
|
||||||
const [feesDaysToShow, setFeesDaysToShow] = useState('30')
|
|
||||||
const [showCumulativeFees, setShowCumulativeFees] = useState(true)
|
|
||||||
const tokenStatsInitialLoad = mangoStore((s) => s.tokenStats.initialLoad)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!tokenStatsInitialLoad) {
|
|
||||||
const actions = mangoStore.getState().actions
|
|
||||||
actions.fetchTokenStats()
|
|
||||||
}
|
|
||||||
}, [tokenStatsInitialLoad])
|
|
||||||
|
|
||||||
const tokenFeesChartData = useMemo(() => {
|
|
||||||
if (!mangoStats.length) return []
|
|
||||||
if (showCumulativeFees) {
|
|
||||||
return mangoStats
|
|
||||||
} else {
|
|
||||||
const transformedData = []
|
|
||||||
for (let i = 1; i < mangoStats.length; i++) {
|
|
||||||
const currentInterval = { ...mangoStats[i] }
|
|
||||||
const previousInterval = mangoStats[i - 1]
|
|
||||||
|
|
||||||
// Calculate the absolute fees for the current interval
|
|
||||||
currentInterval.feesCollected =
|
|
||||||
currentInterval.feesCollected - previousInterval.feesCollected
|
|
||||||
|
|
||||||
transformedData.push(currentInterval)
|
|
||||||
}
|
|
||||||
transformedData.unshift(mangoStats[0])
|
|
||||||
|
|
||||||
if (feesDaysToShow === '30') {
|
|
||||||
return groupByHourlyInterval(transformedData, 24)
|
|
||||||
} else if (feesDaysToShow === '7') {
|
|
||||||
return groupByHourlyInterval(transformedData, 4)
|
|
||||||
} else return transformedData
|
|
||||||
}
|
|
||||||
}, [mangoStats, feesDaysToShow, showCumulativeFees])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:border-r">
|
|
||||||
<DetailedAreaOrBarChart
|
|
||||||
changeAsPercent
|
|
||||||
data={mangoStats}
|
|
||||||
daysToShow={depositDaysToShow}
|
|
||||||
setDaysToShow={setDepositDaysToShow}
|
|
||||||
loading={loadingStats}
|
|
||||||
heightClass="h-64"
|
|
||||||
loaderHeightClass="h-[350px]"
|
|
||||||
prefix="$"
|
|
||||||
tickFormat={(x) => `$${formatYAxis(x)}`}
|
|
||||||
title={t('total-deposit-value')}
|
|
||||||
xKey="date"
|
|
||||||
yKey={'depositValue'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:pl-6">
|
|
||||||
<DetailedAreaOrBarChart
|
|
||||||
changeAsPercent
|
|
||||||
data={mangoStats}
|
|
||||||
daysToShow={borrowDaysToShow}
|
|
||||||
setDaysToShow={setBorrowDaysToShow}
|
|
||||||
heightClass="h-64"
|
|
||||||
loaderHeightClass="h-[350px]"
|
|
||||||
loading={loadingStats}
|
|
||||||
prefix="$"
|
|
||||||
tickFormat={(x) => `$${formatYAxis(x)}`}
|
|
||||||
title={t('total-borrow-value')}
|
|
||||||
xKey="date"
|
|
||||||
yKey={'borrowValue'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2 border-b border-th-bkg-3 px-6 py-4 md:col-span-1 md:border-r md:pl-6">
|
|
||||||
<NetDepositsChart />
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2 flex flex-col justify-between border-b border-th-bkg-3 md:col-span-1">
|
|
||||||
<div className="px-4 pt-4 md:px-6">
|
|
||||||
<DetailedAreaOrBarChart
|
|
||||||
changeAsPercent
|
|
||||||
data={tokenFeesChartData}
|
|
||||||
daysToShow={feesDaysToShow}
|
|
||||||
setDaysToShow={setFeesDaysToShow}
|
|
||||||
heightClass="h-64"
|
|
||||||
loaderHeightClass="h-[350px]"
|
|
||||||
loading={loadingStats}
|
|
||||||
prefix="$"
|
|
||||||
tickFormat={(x) => `$${formatYAxis(x)}`}
|
|
||||||
title={t('token:token-fees-collected')}
|
|
||||||
tooltipContent={t('token:tooltip-token-fees-collected')}
|
|
||||||
xKey="date"
|
|
||||||
yKey={'feesCollected'}
|
|
||||||
chartType={showCumulativeFees ? 'area' : 'bar'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex justify-end border-t border-th-bkg-3 px-4 py-2 md:px-6">
|
|
||||||
<Switch
|
|
||||||
checked={showCumulativeFees}
|
|
||||||
onChange={() => setShowCumulativeFees(!showCumulativeFees)}
|
|
||||||
small
|
|
||||||
>
|
|
||||||
{t('stats:show-cumulative')}
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TokenStatsCharts
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { useMemo, useState } from 'react'
|
||||||
|
import mangoStore from '@store/mangoStore'
|
||||||
|
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
||||||
|
import { formatYAxis } from 'utils/formatting'
|
||||||
|
import Switch from '@components/forms/Switch'
|
||||||
|
import usePerpStatsChartData from 'hooks/usePerpStatsChartData'
|
||||||
|
import SwapVolumeChart from './SwapVolumeChart'
|
||||||
|
|
||||||
|
export interface PerpValueItem {
|
||||||
|
date: string
|
||||||
|
value: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GroupedDataPerpItem extends PerpValueItem {
|
||||||
|
intervalStartMillis: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const groupPerpByHourlyInterval = (
|
||||||
|
data: PerpValueItem[],
|
||||||
|
intervalDurationHours: number,
|
||||||
|
) => {
|
||||||
|
const intervalMillis = intervalDurationHours * 60 * 60 * 1000
|
||||||
|
const groupedData = []
|
||||||
|
let currentGroup: GroupedDataPerpItem | null = null
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const obj = data[i]
|
||||||
|
const date = new Date(obj.date)
|
||||||
|
const intervalStartMillis =
|
||||||
|
Math.floor(date.getTime() / intervalMillis) * intervalMillis
|
||||||
|
if (
|
||||||
|
!currentGroup ||
|
||||||
|
currentGroup.intervalStartMillis !== intervalStartMillis
|
||||||
|
) {
|
||||||
|
currentGroup = {
|
||||||
|
...obj,
|
||||||
|
intervalStartMillis: intervalStartMillis,
|
||||||
|
}
|
||||||
|
groupedData.push(currentGroup)
|
||||||
|
} else {
|
||||||
|
currentGroup.value += obj.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupedData
|
||||||
|
}
|
||||||
|
|
||||||
|
const Volume = () => {
|
||||||
|
const { t } = useTranslation(['common', 'stats', 'token', 'trade'])
|
||||||
|
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
|
||||||
|
const [perpVolumeDaysToShow, setPerpPerpVolumeDaysToShow] = useState('30')
|
||||||
|
const [showCumulativePerpVolume, setShowCumulativePerpVolume] = useState(true)
|
||||||
|
const { volumeValues: perpVolumeChartData } = usePerpStatsChartData()
|
||||||
|
|
||||||
|
const perpVolumeValues = useMemo(() => {
|
||||||
|
if (!perpVolumeChartData || !perpVolumeChartData.length) return []
|
||||||
|
|
||||||
|
let volumeChartData = perpVolumeChartData
|
||||||
|
if (!showCumulativePerpVolume) {
|
||||||
|
const transformedData = []
|
||||||
|
for (let i = 1; i < perpVolumeChartData.length; i++) {
|
||||||
|
const currentInterval = { ...perpVolumeChartData[i] }
|
||||||
|
const previousInterval = perpVolumeChartData[i - 1]
|
||||||
|
|
||||||
|
// Calculate the absolute fees for the current interval
|
||||||
|
currentInterval.value = currentInterval.value - previousInterval.value
|
||||||
|
|
||||||
|
transformedData.push(currentInterval)
|
||||||
|
}
|
||||||
|
transformedData.unshift(perpVolumeChartData[0])
|
||||||
|
|
||||||
|
if (perpVolumeDaysToShow === '30') {
|
||||||
|
volumeChartData = groupPerpByHourlyInterval(transformedData, 24)
|
||||||
|
} else if (perpVolumeDaysToShow === '7') {
|
||||||
|
volumeChartData = groupPerpByHourlyInterval(transformedData, 4)
|
||||||
|
} else volumeChartData = transformedData
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumeChartData
|
||||||
|
}, [perpVolumeDaysToShow, perpVolumeChartData, showCumulativePerpVolume])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="my-4 px-6 text-lg">Volume</h2>
|
||||||
|
<div className="grid grid-cols-2 border-t border-th-bkg-3">
|
||||||
|
<div className="col-span-2 border-b border-th-bkg-3">
|
||||||
|
<div className="px-4 pt-4 md:px-6">
|
||||||
|
<DetailedAreaOrBarChart
|
||||||
|
changeAsPercent
|
||||||
|
data={perpVolumeValues}
|
||||||
|
daysToShow={perpVolumeDaysToShow}
|
||||||
|
setDaysToShow={setPerpPerpVolumeDaysToShow}
|
||||||
|
heightClass="h-64"
|
||||||
|
loading={loadingPerpStats}
|
||||||
|
loaderHeightClass="h-[350px]"
|
||||||
|
prefix="$"
|
||||||
|
tickFormat={(x) => `$${formatYAxis(x)}`}
|
||||||
|
title={t('stats:perp-volume')}
|
||||||
|
xKey="date"
|
||||||
|
yKey="value"
|
||||||
|
chartType={showCumulativePerpVolume ? 'area' : 'bar'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end px-4 pb-4 md:px-6">
|
||||||
|
<Switch
|
||||||
|
checked={showCumulativePerpVolume}
|
||||||
|
onChange={() =>
|
||||||
|
setShowCumulativePerpVolume(!showCumulativePerpVolume)
|
||||||
|
}
|
||||||
|
small
|
||||||
|
>
|
||||||
|
{t('stats:show-cumulative')}
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<SwapVolumeChart />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Volume
|
|
@ -0,0 +1,90 @@
|
||||||
|
import mangoStore from '@store/mangoStore'
|
||||||
|
import { useEffect, useMemo } from 'react'
|
||||||
|
import { PerpStatsItem } from 'types'
|
||||||
|
|
||||||
|
export interface PerpValueItem {
|
||||||
|
date: string
|
||||||
|
value: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PerpStatsData {
|
||||||
|
feeValues: PerpValueItem[]
|
||||||
|
openInterestValues: PerpValueItem[]
|
||||||
|
volumeValues: PerpValueItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function usePerpStatsChartData() {
|
||||||
|
const perpStats = mangoStore((s) => s.perpStats.data)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!perpStats || !perpStats.length) {
|
||||||
|
const actions = mangoStore.getState().actions
|
||||||
|
actions.fetchPerpStats()
|
||||||
|
}
|
||||||
|
}, [perpStats])
|
||||||
|
|
||||||
|
const [feeValues, openInterestValues, volumeValues] = useMemo(() => {
|
||||||
|
if (!perpStats || !perpStats.length) return [[], [], []]
|
||||||
|
const data = perpStats.reduce(
|
||||||
|
(a: PerpStatsData, c: PerpStatsItem) => {
|
||||||
|
const hasDateFee = a.feeValues.find(
|
||||||
|
(d: PerpValueItem) => d.date === c.date_hour,
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasDateOpenInterest = a.openInterestValues.find(
|
||||||
|
(d: PerpValueItem) => d.date === c.date_hour,
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasDateVolume = a.volumeValues.find(
|
||||||
|
(d: PerpValueItem) => d.date === c.date_hour,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!hasDateFee) {
|
||||||
|
a.feeValues.push({
|
||||||
|
date: c.date_hour,
|
||||||
|
value: c.total_fees,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
hasDateFee.value += c.total_fees
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDateOpenInterest) {
|
||||||
|
a.openInterestValues.push({
|
||||||
|
date: c.date_hour,
|
||||||
|
value: Math.floor(c.open_interest * c.price),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
hasDateOpenInterest.value += Math.floor(c.open_interest * c.price)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDateVolume) {
|
||||||
|
a.volumeValues.push({
|
||||||
|
date: c.date_hour,
|
||||||
|
value: c.cumulative_quote_volume,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
hasDateVolume.value += c.cumulative_quote_volume
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
{ feeValues: [], openInterestValues: [], volumeValues: [] },
|
||||||
|
)
|
||||||
|
|
||||||
|
const { feeValues, openInterestValues, volumeValues } = data
|
||||||
|
|
||||||
|
const sortedFeeValues = feeValues.sort(
|
||||||
|
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
||||||
|
)
|
||||||
|
const sortedOpenInterestValues = openInterestValues.sort(
|
||||||
|
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
||||||
|
)
|
||||||
|
const sortedVolumeValues = volumeValues.sort(
|
||||||
|
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return [sortedFeeValues, sortedOpenInterestValues, sortedVolumeValues]
|
||||||
|
}, [perpStats])
|
||||||
|
|
||||||
|
return { feeValues, openInterestValues, volumeValues }
|
||||||
|
}
|
Loading…
Reference in New Issue