Merge pull request #165 from blockworks-foundation/perp-volume-chart

add volume chart to perp stats
This commit is contained in:
tlrsssss 2023-06-05 11:21:40 -04:00 committed by GitHub
commit d8b66e390e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 81 deletions

View File

@ -3,15 +3,15 @@ import dayjs from 'dayjs'
import { useTranslation } from 'next-i18next'
import { useMemo, useState } from 'react'
import { formatYAxis } from 'utils/formatting'
// import { formatNumericValue } from 'utils/numbers'
// import { usePerpFundingRate } from '@components/trade/PerpFundingRate'
import { PerpStatsItem } from 'types'
import { PerpMarket } from '@blockworks-foundation/mango-v4'
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
import AverageFundingChart from './AverageFundingChart'
const CHART_WRAPPER_CLASSES = 'col-span-2 border-b border-th-bkg-3 py-4 px-6'
const CHART_WRAPPER_CLASSES =
'col-span-2 lg:col-span-1 border-b border-th-bkg-3 py-4 px-6'
import PerpMarketParams from './PerpMarketParams'
import PerpVolumeChart from './PerpVolumeChart'
const PerpMarketDetails = ({
marketStats,
@ -24,53 +24,22 @@ const PerpMarketDetails = ({
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
const [priceDaysToShow, setPriceDaysToShow] = useState('30')
const [oiDaysToShow, setOiDaysToShow] = useState('30')
// const [hourlyFundingeDaysToShow, setHourlyFundingDaysToShow] = useState('30')
// const [instantFundingDaysToShow, setInstantFundingDaysToShow] = useState('30')
// const rate = usePerpFundingRate()
const lastStat = useMemo(() => {
if (!marketStats.length) return undefined
return marketStats[marketStats.length - 1]
}, [marketStats])
// const fundingRate = useMemo(() => {
// if (!lastStat) return 0
// if (rate?.isSuccess) {
// const marketRate = rate?.data?.find(
// (r) => r.market_index === perpMarket?.perpMarketIndex
// )
// return marketRate?.funding_rate_hourly
// }
// return lastStat.instantaneous_funding_rate
// }, [rate, lastStat])
// const perpHourlyStats = useMemo(() => {
// const latestStat = { ...lastStat } as PerpStatsItem
// latestStat.instantaneous_funding_rate = fundingRate ? fundingRate : 0
// latestStat.date_hour = dayjs().toISOString()
// if (marketStats) {
// const perpHourly = marketStats.concat([latestStat])
// return perpHourly.map((stat) => ({
// ...stat,
// funding_rate_hourly: stat.funding_rate_hourly * 100,
// }))
// }
// }, [marketStats, fundingRate])
// const instantFundingRateStats = useMemo(() => {
// if (marketStats) {
// return marketStats.map((stat) => ({
// ...stat,
// instantaneous_funding_rate: stat.instantaneous_funding_rate * 100,
// }))
// }
// return []
// }, [marketStats])
return (
<div className="grid grid-cols-2">
{marketStats?.length && lastStat ? (
<>
<div className={`${CHART_WRAPPER_CLASSES} lg:border-r`}>
<PerpVolumeChart
loading={loadingPerpStats}
marketStats={marketStats}
/>
</div>
<div className={CHART_WRAPPER_CLASSES}>
<DetailedAreaOrBarChart
data={marketStats.concat([
@ -93,42 +62,7 @@ const PerpMarketDetails = ({
yKey={'open_interest'}
/>
</div>
{/* old funding charts */}
{/* <div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
<DetailedAreaOrBarChart
data={perpHourlyStats ? perpHourlyStats : []}
daysToShow={hourlyFundingeDaysToShow}
setDaysToShow={setHourlyFundingDaysToShow}
heightClass="h-64"
loading={loadingPerpStats}
loaderHeightClass="h-[350px]"
suffix="%"
tickFormat={(x) => formatNumericValue(x, 4)}
title={t('trade:hourly-funding')}
xKey="date_hour"
yKey={'funding_rate_hourly'}
yDecimals={5}
showZeroLine
/>
</div>
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
<DetailedAreaOrBarChart
data={instantFundingRateStats}
daysToShow={instantFundingDaysToShow}
setDaysToShow={setInstantFundingDaysToShow}
heightClass="h-64"
loading={loadingPerpStats}
loaderHeightClass="h-[350px]"
suffix="%"
tickFormat={(x) => formatNumericValue(x, 4)}
title={t('trade:instantaneous-funding')}
xKey="date_hour"
yKey={'instantaneous_funding_rate'}
yDecimals={5}
showZeroLine
/>
</div> */}
<div className={CHART_WRAPPER_CLASSES}>
<div className={`${CHART_WRAPPER_CLASSES} lg:border-r`}>
<AverageFundingChart
loading={loadingPerpStats}
marketStats={marketStats}

View File

@ -0,0 +1,117 @@
import { useMemo, useState } from 'react'
import { GroupedDataItem, PerpStatsItem } from 'types'
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
import { useTranslation } from 'next-i18next'
import { formatYAxis } from 'utils/formatting'
const PerpVolumeChart = ({
loading,
marketStats,
}: {
loading: boolean
marketStats: PerpStatsItem[]
}) => {
const { t } = useTranslation(['common', 'stats', 'trade'])
const [daysToShow, setDaysToShow] = useState('30')
const groupArrayByHours = (data: PerpStatsItem[], hours: number) => {
const groupedData = []
let currentGroup: GroupedDataItem[] = []
for (let i = 0; i < data.length; i++) {
const obj = data[i]
const date = new Date(obj.date_hour)
if (hours === 24) {
const day = date.getDate()
const month = date.getMonth()
if (
currentGroup.length === 0 ||
(currentGroup[0].day === day && currentGroup[0].month === month)
) {
currentGroup.push({ ...obj, day: day, month: month })
} else {
groupedData.push(currentGroup)
currentGroup = [{ ...obj, day: day, month: month }]
}
} else {
const intervalMillis = hours * 60 * 60 * 1000
const timestamp = date.getTime()
if (
currentGroup.length === 0 ||
timestamp - currentGroup[0].timestamp <= intervalMillis
) {
currentGroup.push({ ...obj, timestamp: timestamp })
} else {
groupedData.push(currentGroup)
currentGroup = [{ ...obj, timestamp: timestamp }]
}
}
}
if (currentGroup.length > 0) {
groupedData.push(currentGroup)
}
return groupedData
}
const interval = useMemo(() => {
if (daysToShow === '30') {
return 24
} else if (daysToShow === '7') {
return 6
} else {
return 1
}
}, [daysToShow])
const chartData = useMemo(() => {
if (!marketStats) return []
const chartData = []
if (interval !== 1) {
const groupedData = groupArrayByHours(marketStats, interval)
for (let i = 0; i < groupedData.length; i++) {
const volume =
groupedData[i][groupedData[i].length - 1].cumulative_quote_volume -
groupedData[i][0].cumulative_quote_volume
chartData.push({
date_hour: groupedData[i][groupedData[i].length - 1].date_hour,
volume: volume,
})
}
} else {
for (let i = 0; i < marketStats.length; i++) {
const volume =
marketStats[i].cumulative_quote_volume -
(marketStats[i - 1] ? marketStats[i - 1].cumulative_quote_volume : 0)
chartData.push({
date_hour: marketStats[i].date_hour,
volume: volume,
})
}
}
return chartData
}, [daysToShow, interval, marketStats])
return (
<DetailedAreaOrBarChart
data={chartData}
daysToShow={daysToShow}
setDaysToShow={setDaysToShow}
heightClass="h-64"
loading={loading}
loaderHeightClass="h-[350px]"
prefix="$"
tickFormat={(x) => formatYAxis(x)}
title={t('stats:volume')}
xKey="date_hour"
yKey="volume"
// yDecimals={5}
chartType="bar"
tooltipDateFormat={daysToShow === '30' ? 'DD MMM YY' : ''}
/>
)
}
export default PerpVolumeChart

View File

@ -11,5 +11,6 @@
"tooltip-init-asset-liability-weight": "The contribution a perp position has to your initial account health. Asset weight is applied to long positions and liability weight is applied to shorts. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.",
"tooltip-maint-asset-liability-weight": "The contribution a perp position has to your maintenance account health. Asset weight is applied to long positions and liability weight is applied to shorts. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.",
"tooltip-pnl-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over positive unsettled perp pnl.",
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period."
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period.",
"volume": "Volume"
}

View File

@ -11,5 +11,6 @@
"tooltip-init-asset-liability-weight": "The contribution a perp position has to your initial account health. Asset weight is applied to long positions and liability weight is applied to shorts. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.",
"tooltip-maint-asset-liability-weight": "The contribution a perp position has to your maintenance account health. Asset weight is applied to long positions and liability weight is applied to shorts. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.",
"tooltip-pnl-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over positive unsettled perp pnl.",
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period."
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period.",
"volume": "Volume"
}

View File

@ -11,5 +11,6 @@
"tooltip-init-asset-liability-weight": "The contribution a perp position has to your initial account health. Asset weight is applied to long positions and liability weight is applied to shorts. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.",
"tooltip-maint-asset-liability-weight": "The contribution a perp position has to your maintenance account health. Asset weight is applied to long positions and liability weight is applied to shorts. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.",
"tooltip-pnl-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over positive unsettled perp pnl.",
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period."
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period.",
"volume": "Volume"
}

View File

@ -11,5 +11,6 @@
"tooltip-init-asset-liability-weight": "The contribution a perp position has to your initial account health. Asset weight is applied to long positions and liability weight is applied to shorts. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.",
"tooltip-maint-asset-liability-weight": "The contribution a perp position has to your maintenance account health. Asset weight is applied to long positions and liability weight is applied to shorts. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.",
"tooltip-pnl-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over positive unsettled perp pnl.",
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period."
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period.",
"volume": "Volume"
}

View File

@ -11,5 +11,6 @@
"tooltip-init-asset-liability-weight": "The contribution a perp position has to your initial account health. Asset weight is applied to long positions and liability weight is applied to shorts. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.",
"tooltip-maint-asset-liability-weight": "The contribution a perp position has to your maintenance account health. Asset weight is applied to long positions and liability weight is applied to shorts. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.",
"tooltip-pnl-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over positive unsettled perp pnl.",
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period."
"tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period.",
"volume": "Volume"
}

View File

@ -302,6 +302,8 @@ export interface PerpStatsItem {
total_fees: number
}
export type GroupedDataItem = PerpStatsItem & Record<string, any>
export type ActivityFeed = {
activity_type: string
block_datetime: string