import useInterval from '@components/shared/useInterval' import mangoStore from '@store/mangoStore' import { useEffect, useMemo } from 'react' import { floorToDecimal, getDecimalCount } from 'utils/numbers' import Decimal from 'decimal.js' import { ChartTradeType } from 'types' import { useTranslation } from 'next-i18next' import useSelectedMarket from 'hooks/useSelectedMarket' import { Howl } from 'howler' import { IconButton } from '@components/shared/Button' import useLocalStorageState from 'hooks/useLocalStorageState' import { SOUND_SETTINGS_KEY } from 'utils/constants' import { SpeakerWaveIcon, SpeakerXMarkIcon } from '@heroicons/react/20/solid' import Tooltip from '@components/shared/Tooltip' import { INITIAL_SOUND_SETTINGS } from '@components/settings/SoundSettings' import usePrevious from '@components/shared/usePrevious' const buySound = new Howl({ src: ['/sounds/trade-buy.mp3'], volume: 0.5, }) const sellSound = new Howl({ src: ['/sounds/trade-sell.mp3'], volume: 0.5, }) const RecentTrades = () => { const { t } = useTranslation(['common', 'trade']) const fills = mangoStore((s) => s.selectedMarket.fills) const [soundSettings, setSoundSettings] = useLocalStorageState( SOUND_SETTINGS_KEY, INITIAL_SOUND_SETTINGS ) const previousFills = usePrevious(fills) useEffect(() => { if (!soundSettings['recent-trades']) return if (fills.length && previousFills && previousFills.length) { const latestFill: ChartTradeType = fills[0] const previousFill: ChartTradeType = previousFills[0] if (previousFill.orderId.toString() !== latestFill.orderId.toString()) { const side = latestFill.side || (latestFill.takerSide === 1 ? 'bid' : 'ask') if (['buy', 'bid'].includes(side)) { buySound.play() } else { sellSound.play() } } } }, [fills, previousFills, soundSettings]) const { selectedMarket, serumOrPerpMarket: market } = useSelectedMarket() const baseSymbol = useMemo(() => { return selectedMarket?.name.split(/-|\//)[0] }, [selectedMarket]) const quoteSymbol = useMemo(() => { return selectedMarket?.name.split(/-|\//)[1] }, [selectedMarket]) // const fetchRecentTrades = useCallback(async () => { // if (!market) return // try { // const response = await fetch( // `https://event-history-api-candles.herokuapp.com/trades/address/${market.publicKey}` // ) // const parsedResp = await response.json() // const newTrades = parsedResp.data // if (!newTrades) return null // if (newTrades.length && trades.length === 0) { // setTrades(newTrades) // } else if (newTrades?.length && !isEqual(newTrades[0], trades[0])) { // setTrades(newTrades) // } // } catch (e) { // console.error('Unable to fetch recent trades', e) // } // }, [market, trades]) useEffect(() => { // if (CLUSTER === 'mainnet-beta') { // fetchRecentTrades() // } const actions = mangoStore.getState().actions actions.loadMarketFills() }, [selectedMarket]) useInterval(async () => { // if (CLUSTER === 'mainnet-beta') { // fetchRecentTrades() // } const actions = mangoStore.getState().actions actions.loadMarketFills() }, 5000) const [buyRatio, sellRatio] = useMemo(() => { if (!fills.length) return [0, 0] const vol = fills.reduce( (a: { buys: number; sells: number }, c: any) => { if (c.side === 'buy' || c.takerSide === 1) { a.buys = a.buys + c.size } else { a.sells = a.sells + c.size } return a }, { buys: 0, sells: 0 } ) const totalVol = vol.buys + vol.sells return [vol.buys / totalVol, vol.sells / totalVol] }, [fills]) return (
setSoundSettings({ ...soundSettings, 'recent-trades': !soundSettings['recent-trades'], }) } size="small" hideBg > {soundSettings['recent-trades'] ? ( ) : ( )} {t('trade:buys')}:{' '} {(buyRatio * 100).toFixed(1)}% | {t('trade:sells')}:{' '} {(sellRatio * 100).toFixed(1)}%
{!!fills.length && fills.map((trade: ChartTradeType, i: number) => { const side = trade.side || (trade.takerSide === 1 ? 'bid' : 'ask') // const price = // typeof trade.price === 'number' // ? trade.price // : trade.price.toNumber() const formattedPrice = market?.tickSize ? floorToDecimal( trade.price, getDecimalCount(market.tickSize) ) : new Decimal(trade?.price || 0) // const size = trade?.quantity?.toNumber() || trade?.size const formattedSize = market?.minOrderSize && trade.size ? floorToDecimal( trade.size, getDecimalCount(market.minOrderSize) ) : new Decimal(trade.size || 0) return ( ) })}
{`${t( 'price' )} (${quoteSymbol})`} {t('trade:size')} ({baseSymbol}) {t('time')}
{formattedPrice.toFixed()} {formattedSize.toFixed()} {trade.time ? new Date(trade.time).toLocaleTimeString() : trade.timestamp ? new Date( trade.timestamp.toNumber() ).toLocaleTimeString() : '-'}
) } export default RecentTrades