import React, { useCallback, useMemo, useState } from 'react' import useMangoStore from '../stores/useMangoStore' import usePrevious from '../hooks/usePrevious' import useInterval from '../hooks/useInterval' import ChartApi from '../utils/chartDataConnector' import UiLock from './UiLock' import ManualRefresh from './ManualRefresh' import useOraclePrice from '../hooks/useOraclePrice' import DayHighLow from './DayHighLow' import { useEffect } from 'react' import { formatUsdValue } from '../utils' function calculateFundingRate(perpStats, perpMarket) { const oldestStat = perpStats[perpStats.length - 1] const latestStat = perpStats[0] if (!latestStat || !perpMarket) return null const fundingDifference = latestStat.longFunding - oldestStat.longFunding const fundingInQuoteDecimals = fundingDifference / Math.pow(10, perpMarket.quoteDecimals) const basePriceInBaseLots = latestStat.baseOraclePrice * perpMarket.baseLotsToNumber(1) return (fundingInQuoteDecimals / basePriceInBaseLots) * 100 } function parseOpenInterest(perpStats, perpMarket) { if (!perpStats?.length || !perpMarket) return 0 return perpMarket.baseLotsToNumber(perpStats[0].openInterest / 2) } const MarketHeader = () => { const oraclePrice = useOraclePrice() const marketConfig = useMangoStore((s) => s.selectedMarket.config) const selectedMarket = useMangoStore((s) => s.selectedMarket.current) const mangoGroupName = useMangoStore((s) => s.selectedMangoGroup.name) const baseSymbol = marketConfig.baseSymbol const selectedMarketName = marketConfig.name const previousMarketName: string = usePrevious(selectedMarketName) const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current) const connected = useMangoStore((s) => s.wallet.connected) const [ohlcv, setOhlcv] = useState(null) const [loading, setLoading] = useState(false) const [perpStats, setPerpStats] = useState([]) const [spotStats, setSpotStats] = useState(null) // const change = ohlcv ? ((ohlcv.c[0] - ohlcv.o[0]) / ohlcv.o[0]) * 100 : '--' const volume = ohlcv ? ohlcv.v[0] : '--' const fetchSpotStats = useCallback(async () => { const urlParams = new URLSearchParams({ mangoGroup: mangoGroupName }) urlParams.append('market', selectedMarketName) const spotStats = await fetch( 'https://mango-stats-v3.herokuapp.com/spot/change/24?' + urlParams ) const parsedSpotStats = await spotStats.json() setSpotStats(parsedSpotStats) }, [selectedMarketName, mangoGroupName]) const fetchPerpStats = useCallback(async () => { const perpStats = await fetch( `https://mango-stats-v3.herokuapp.com/perp/funding_rate?market=${selectedMarketName}` ) const parsedPerpStats = await perpStats.json() setPerpStats(parsedPerpStats) }, [selectedMarketName]) useEffect(() => { if (!selectedMarketName.includes('PERP')) { fetchSpotStats() } }, [fetchSpotStats, selectedMarketName]) useEffect(() => { if (selectedMarketName.includes('PERP')) { fetchPerpStats() } }, [fetchPerpStats, selectedMarketName]) const fetchOhlcv = useCallback(async () => { if (!selectedMarketName) return // calculate from and to date (0:00UTC to 23:59:59UTC) const date = new Date() const utcFrom = new Date( Date.UTC( date.getFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0 ) ) const utcTo = new Date( Date.UTC( date.getFullYear(), date.getUTCMonth(), date.getUTCDate(), 23, 59, 59 ) ) const from = utcFrom.getTime() / 1000 const to = utcTo.getTime() / 1000 const ohlcv = await ChartApi.getOhlcv(selectedMarketName, '1D', from, to) if (ohlcv) { setOhlcv(ohlcv) setLoading(false) } }, [selectedMarketName]) useInterval(async () => { fetchOhlcv() }, 5000) useMemo(() => { if (previousMarketName !== selectedMarketName) { setLoading(true) } }, [selectedMarketName]) return (
{baseSymbol}
{selectedMarketName.includes('PERP') ? '–' : '/'}
{selectedMarketName.split(/\/|-/)[1]}
Oracle price
{oraclePrice ? formatUsdValue(oraclePrice) : '--'}
24h Change
{spotStats?.change ? (
0 ? `text-th-green` : spotStats.change < 0 ? `text-th-red` : `text-th-fgd-1` }`} > {spotStats.change.toFixed(2) + '%'}
) : ( )}
24h Vol
{ohlcv && !loading && volume ? ( volume !== '--' ? ( <> {volume.toFixed(2)} {baseSymbol} ) : ( volume ) ) : ( )}
{selectedMarketName.includes('PERP') ? ( <>
Avg Funding Rate (1h)
{calculateFundingRate(perpStats, selectedMarket)?.toFixed(6)}%
Open Interest
{parseOpenInterest(perpStats, selectedMarket)} {baseSymbol}
) : null}
{connected && mangoAccount ? : null}
) } export default MarketHeader const MarketDataLoader = () => (
)