Skip to content

Commit

Permalink
feat(spot-volume): show spot-volume and market cap (#1318)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredvu authored Nov 21, 2024
1 parent 7b41838 commit 7e072b1
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 144 deletions.
2 changes: 2 additions & 0 deletions src/constants/markets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export type MarketData = {
tickSizeDecimals?: Nullable<number>;
trades24H?: Nullable<number>;
volume24H?: Nullable<number>;
spotVolume24H?: Nullable<number>;
marketCap?: Nullable<number>;
tags?: Nullable<string[]>;
isFavorite: boolean;
};
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/tradingView/useTradingViewLaunchable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { getTvChartConfig } from '@/state/tradingViewSelectors';
import { getLaunchableMarketDatafeed } from '@/lib/tradingView/launchableMarketFeed';
import { getSavedResolution, getWidgetOptions, getWidgetOverrides } from '@/lib/tradingView/utils';

import { useMetadataService } from '../useLaunchableMarkets';
import { useMetadataService } from '../useMetadataService';

/**
* @description Hook to initialize TradingView Chart
Expand Down
134 changes: 3 additions & 131 deletions src/hooks/useLaunchableMarkets.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,10 @@
import { useMemo } from 'react';

import { useQueries, useQuery } from '@tanstack/react-query';

import {
MetadataServiceAsset,
MetadataServiceCandlesTimeframes,
MetadataServiceInfoResponse,
MetadataServicePricesResponse,
} from '@/constants/assetMetadata';
import { timeUnits } from '@/constants/time';

import metadataClient from '@/clients/metadataService';
import { getAssetFromMarketId } from '@/lib/assetUtils';
import { getTickSizeDecimalsFromPrice } from '@/lib/numbers';
import { mapMetadataServiceCandles } from '@/lib/tradingView/utils';

import { useDydxClient } from './useDydxClient';

const ASSETS_TO_REMOVE = ['USDC', 'USDT'];

export const useMetadataService = () => {
const metadataQuery = useQueries({
queries: [
{
queryKey: ['marketMapInfo'],
queryFn: async (): Promise<MetadataServiceInfoResponse> => {
return metadataClient.getAssetInfo();
},
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
},
{
queryKey: ['marketMapPrice'],
queryFn: async (): Promise<MetadataServicePricesResponse> => {
return metadataClient.getAssetPrices();
},
refetchInterval: timeUnits.minute * 5,
},
],
combine: (results) => {
const info = results[0].data;
const prices = results[1].data;
const data: Record<string, MetadataServiceAsset> = {};

Object.keys(info ?? {}).forEach((key) => {
const infoKey = info?.[key];
const pricesKey = prices?.[key];

if (infoKey && pricesKey && !ASSETS_TO_REMOVE.includes(key)) {
const tickSizeDecimals = getTickSizeDecimalsFromPrice(pricesKey.price);

data[key] = {
id: key,
name: infoKey.name,
logo: infoKey.logo,
urls: {
website: infoKey.urls.website,
technicalDoc: infoKey.urls.technical_doc,
cmc: infoKey.urls.cmc,
},
sectorTags: infoKey.sector_tags,
exchanges: infoKey.exchanges,
price: pricesKey.price,
percentChange24h: pricesKey.percent_change_24h,
marketCap: pricesKey.market_cap,
volume24h: pricesKey.volume_24h,
reportedMarketCap: pricesKey.self_reported_market_cap,
tickSizeDecimals,
};
}
});

return {
data,
isLoading: results.some((result) => result.isLoading),
isError: results.some((result) => result.isError),
isSuccess: results.every((result) => result.isSuccess),
};
},
});

return metadataQuery;
};

export const useMetadataServiceAssetFromId = (marketId?: string) => {
const metadataServiceData = useMetadataService();

const launchableAsset = useMemo(() => {
if (!metadataServiceData.data || !marketId) {
return null;
}

const assetId = getAssetFromMarketId(marketId);
return metadataServiceData.data[assetId];
}, [metadataServiceData.data, marketId]);

return launchableAsset;
};
import { useMetadataService } from './useMetadataService';
import { usePerpetualMarkets } from './userPerpetualMarkets';

export const useLaunchableMarkets = () => {
const { requestAllPerpetualMarkets } = useDydxClient();

const perpetualMarketsFetch = useQuery({
queryKey: ['requestAllPerpetualMarkets'],
queryFn: requestAllPerpetualMarkets,
refetchInterval: timeUnits.minute,
staleTime: timeUnits.minute,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});

const perpetualMarketsFetch = usePerpetualMarkets();
const metadataServiceData = useMetadataService();

const filteredPotentialMarkets: { id: string; asset: string }[] = useMemo(() => {
Expand All @@ -132,24 +25,3 @@ export const useLaunchableMarkets = () => {
data: filteredPotentialMarkets,
};
};

export const useMetadataServiceCandles = (
asset?: string,
timeframe?: MetadataServiceCandlesTimeframes
) => {
const candlesQuery = useQuery({
enabled: !!asset && !!timeframe,
queryKey: ['candles', asset, timeframe],
queryFn: async () => {
return metadataClient.getCandles({ asset: asset!, timeframe: timeframe! });
},
refetchInterval: timeUnits.minute * 5,
refetchOnMount: false,
refetchOnWindowFocus: false,
});

return {
...candlesQuery,
data: candlesQuery.data?.[asset ?? '']?.map(mapMetadataServiceCandles),
};
};
21 changes: 17 additions & 4 deletions src/hooks/useMarketsData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { matchesSearchFilter } from '@/lib/search';
import { testFlags } from '@/lib/testFlags';
import { orEmptyObj, orEmptyRecord } from '@/lib/typeUtils';

import { useMetadataService } from './useLaunchableMarkets';
import { useMetadataService } from './useMetadataService';
import { useAllStatsigGateValues } from './useStatsig';

const filterFunctions = {
Expand Down Expand Up @@ -136,7 +136,7 @@ export const useMarketsData = ({
const allAssets = orEmptyRecord(useAppSelector(getAssets, shallowEqual));
const sevenDaysSparklineData = usePerpetualMarketSparklines();
const featureFlags = useAllStatsigGateValues();
const unlaunchedMarkets = useMetadataService();
const metadataServiceInfo = useMetadataService();
const shouldHideLaunchableMarkets =
useAppSelector(getShouldHideLaunchableMarkets) || hideUnlaunchedMarkets;
const favoritedMarkets = useAppSelector(getFavoritedMarkets, shallowEqual);
Expand Down Expand Up @@ -165,6 +165,12 @@ export const useMarketsData = ({
sevenDaysSparklineData && sevenDaySparklineEntries < SEVEN_DAY_SPARKLINE_ENTRIES
);
const clobPairId = allPerpetualClobIds[marketData.id] ?? 0;
const {
volume24h: spotVolume24H,
marketCap,
reportedMarketCap,
} = orEmptyObj(metadataServiceInfo.data[marketData.assetId]);

const {
assetId,
displayId,
Expand Down Expand Up @@ -205,13 +211,15 @@ export const useMarketsData = ({
tickSizeDecimals,
trades24H,
volume24H,
spotVolume24H,
marketCap: marketCap ?? reportedMarketCap,
isFavorite: favoritedMarkets.includes(id),
}
);
});

if (!shouldHideLaunchableMarkets && testFlags.pml) {
const unlaunchedMarketsData = Object.values(unlaunchedMarkets.data)
const unlaunchedMarketsData = Object.values(metadataServiceInfo.data)
.sort(sortByMarketCap)
.map((market) => {
const {
Expand All @@ -222,6 +230,9 @@ export const useMarketsData = ({
price,
percentChange24h,
tickSizeDecimals,
volume24h: spotVolume24H,
marketCap,
reportedMarketCap,
} = market;

if (allPerpetualMarketIdsSet.has(assetId)) return null;
Expand Down Expand Up @@ -255,6 +266,8 @@ export const useMarketsData = ({
tickSizeDecimals,
trades24H: undefined,
volume24H: undefined,
spotVolume24H,
marketCap: marketCap ?? reportedMarketCap,
isFavorite: favoritedMarkets.includes(id),
}
);
Expand All @@ -271,7 +284,7 @@ export const useMarketsData = ({
sevenDaysSparklineData,
allPerpetualClobIds,
allAssets,
unlaunchedMarkets.data,
metadataServiceInfo.data,
favoritedMarkets,
]);

Expand Down
117 changes: 117 additions & 0 deletions src/hooks/useMetadataService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { useMemo } from 'react';

import { useQueries, useQuery } from '@tanstack/react-query';

import {
MetadataServiceAsset,
MetadataServiceCandlesTimeframes,
MetadataServiceInfoResponse,
MetadataServicePricesResponse,
} from '@/constants/assetMetadata';
import { timeUnits } from '@/constants/time';

import metadataClient from '@/clients/metadataService';
import { getAssetFromMarketId } from '@/lib/assetUtils';
import { getTickSizeDecimalsFromPrice } from '@/lib/numbers';
import { mapMetadataServiceCandles } from '@/lib/tradingView/utils';

const ASSETS_TO_REMOVE = ['USDC', 'USDT'];

export const useMetadataService = () => {
const metadataQuery = useQueries({
queries: [
{
queryKey: ['marketMapInfo'],
queryFn: async (): Promise<MetadataServiceInfoResponse> => {
return metadataClient.getAssetInfo();
},
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
},
{
queryKey: ['marketMapPrice'],
queryFn: async (): Promise<MetadataServicePricesResponse> => {
return metadataClient.getAssetPrices();
},
refetchInterval: timeUnits.minute * 5,
},
],
combine: (results) => {
const info = results[0].data;
const prices = results[1].data;
const data: Record<string, MetadataServiceAsset> = {};

Object.keys(info ?? {}).forEach((key) => {
const infoKey = info?.[key];
const pricesKey = prices?.[key];

if (infoKey && pricesKey && !ASSETS_TO_REMOVE.includes(key)) {
const tickSizeDecimals = getTickSizeDecimalsFromPrice(pricesKey.price);

data[key] = {
id: key,
name: infoKey.name,
logo: infoKey.logo,
urls: {
website: infoKey.urls.website,
technicalDoc: infoKey.urls.technical_doc,
cmc: infoKey.urls.cmc,
},
sectorTags: infoKey.sector_tags,
exchanges: infoKey.exchanges,
price: pricesKey.price,
percentChange24h: pricesKey.percent_change_24h,
marketCap: pricesKey.market_cap,
volume24h: pricesKey.volume_24h,
reportedMarketCap: pricesKey.self_reported_market_cap,
tickSizeDecimals,
};
}
});

return {
data,
isLoading: results.some((result) => result.isLoading),
isError: results.some((result) => result.isError),
isSuccess: results.every((result) => result.isSuccess),
};
},
});

return metadataQuery;
};

export const useMetadataServiceAssetFromId = (marketId?: string) => {
const metadataServiceData = useMetadataService();

const launchableAsset = useMemo(() => {
if (!metadataServiceData.data || !marketId) {
return null;
}

const assetId = getAssetFromMarketId(marketId);
return metadataServiceData.data[assetId];
}, [metadataServiceData.data, marketId]);

return launchableAsset;
};

export const useMetadataServiceCandles = (
asset?: string,
timeframe?: MetadataServiceCandlesTimeframes
) => {
const candlesQuery = useQuery({
enabled: !!asset && !!timeframe,
queryKey: ['candles', asset, timeframe],
queryFn: async () => {
const candles = await metadataClient.getCandles({ asset: asset!, timeframe: timeframe! });
return candles[asset ?? '']?.map(mapMetadataServiceCandles);
},
refetchInterval: timeUnits.minute * 5,
refetchOnMount: false,
refetchOnWindowFocus: false,
});

return candlesQuery;
};
21 changes: 21 additions & 0 deletions src/hooks/userPerpetualMarkets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useQuery } from '@tanstack/react-query';

import { timeUnits } from '@/constants/time';

import { useDydxClient } from './useDydxClient';

export const usePerpetualMarkets = () => {
const { requestAllPerpetualMarkets } = useDydxClient();

const perpetualMarketsFetch = useQuery({
queryKey: ['requestAllPerpetualMarkets'],
queryFn: requestAllPerpetualMarkets,
refetchInterval: timeUnits.minute,
staleTime: timeUnits.minute,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});

return perpetualMarketsFetch;
};
2 changes: 1 addition & 1 deletion src/pages/trade/TradeHeaderMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from 'styled-components';

import { AppRoute } from '@/constants/routes';

import { useMetadataServiceAssetFromId } from '@/hooks/useLaunchableMarkets';
import { useMetadataServiceAssetFromId } from '@/hooks/useMetadataService';

import { layoutMixins } from '@/styles/layoutMixins';

Expand Down
2 changes: 1 addition & 1 deletion src/styles/constants.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

/* Market Selector constants */
--marketsDropdown-openWidth-deprecated: 45rem;
--marketsDropdown-openWidth: 40rem;
--marketsDropdown-openWidth: 50rem;

/* Form constants */
--form-input-gap: 0.625rem;
Expand Down
Loading

0 comments on commit 7e072b1

Please sign in to comment.