Skip to content

Commit

Permalink
feat(trading): use candles service for sparklines (#82)
Browse files Browse the repository at this point in the history
* feat: use candles service for markets page sparklines

* feat: use candles service market selector sparkline

* chore: mock candles data from service hok

* fix: sparkline candle direction
  • Loading branch information
oldalbus authored Nov 14, 2024
1 parent e48c8f6 commit 870a927
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 179 deletions.
75 changes: 41 additions & 34 deletions apps/trading/client-pages/markets/top-market-list.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
import { Emblem } from '@vegaprotocol/emblem';
import type { MarketMaybeWithCandles } from '@vegaprotocol/markets';
import { Link } from 'react-router-dom';
import {
priceValueFormatter,
priceChangeRenderer,
priceChangeSparklineRenderer,
} from './use-column-defs';
import { priceValueFormatter } from './use-column-defs';
import { Links } from '../../lib/links';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import { cn, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
import { useCandleData } from '@vegaprotocol/rest';
import { formatNumber } from '@vegaprotocol/utils';
import { signedNumberCssClass } from '@vegaprotocol/datagrid';

export const TopMarketList = ({
markets,
}: {
markets?: MarketMaybeWithCandles[];
}) => {
return (
<div className="flex flex-col justify-between gap-5">
<ul className="flex flex-col justify-between gap-3">
{markets?.map((market) => {
return (
<div
className="grid auto-rows-min grid-cols-8 gap-3 text-sm"
key={market.id}
>
<span className="col-span-3 overflow-hidden">
<Tooltip description={market.tradableInstrument.instrument.name}>
<Link to={Links.MARKET(market.id)}>
<span className="flex items-center gap-2">
<Emblem market={market.id} size={26} />
<span className="text-sm overflow-hidden text-ellipsis">
{market.tradableInstrument.instrument.code}
</span>
</span>
</Link>
</Tooltip>
</span>
<span className="col-span-2 text-right font-mono">
{priceValueFormatter(market, 2)}
</span>
<span className="col-span-3 flex justify-end gap-1 text-xs">
{priceChangeRenderer(market, false)}
{priceChangeSparklineRenderer(market)}
</span>
</div>
);
return <TopMarket key={market.id} market={market} />;
})}
</div>
</ul>
);
};

const TopMarket = (props: { market: MarketMaybeWithCandles }) => {
const { sparkline, pctChange } = useCandleData(props.market.id);
return (
<li className="grid auto-rows-min grid-cols-3 gap-3">
<span className="overflow-hidden">
<Tooltip description={props.market.tradableInstrument.instrument.name}>
<Link to={Links.MARKET(props.market.id)}>
<span className="flex items-center gap-2">
<Emblem market={props.market.id} size={26} />
<span className="overflow-hidden text-ellipsis">
{props.market.tradableInstrument.instrument.code}
</span>
</span>
</Link>
</Tooltip>
</span>
<span className="text-right font-mono">
{priceValueFormatter(props.market, 2)}
</span>
<span className="flex justify-end gap-2 text-xs">
{pctChange && (
<span
className={cn('font-mono text-sm', signedNumberCssClass(pctChange))}
>
{formatNumber(pctChange, 2)}%
</span>
)}
{sparkline && <Sparkline data={sparkline} />}
</span>
</li>
);
};
86 changes: 36 additions & 50 deletions apps/trading/client-pages/markets/use-column-defs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@ import type {
VegaValueFormatterParams,
VegaValueGetterParams,
} from '@vegaprotocol/datagrid';
import { MarketProductPill, StackedCell } from '@vegaprotocol/datagrid';
import {
MarketProductPill,
signedNumberCssClass,
StackedCell,
} from '@vegaprotocol/datagrid';
import {
addDecimalsFormatNumber,
formatNumber,
formatNumberPercentage,
priceChangePercentage,
toBigNum,
} from '@vegaprotocol/utils';
import { Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
import { Arrow, cn, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
import type {
MarketMaybeWithData,
MarketMaybeWithDataAndCandles,
} from '@vegaprotocol/markets';
import {
Last24hPriceChange,
calcCandleVolume,
calcCandleVolumePrice,
getAsset,
Expand All @@ -29,6 +33,8 @@ import {
import { useT } from '../../lib/use-t';
import { Emblem } from '@vegaprotocol/emblem';
import { MarketIcon, getMarketStateTooltip } from './market-icon';
import { useCandleData } from '@vegaprotocol/rest';
import BigNumber from 'bignumber.js';

const openInterestValues = (data: MarketMaybeWithData) => {
if (!data) return null;
Expand Down Expand Up @@ -90,47 +96,6 @@ const getOpenInterestCellUnits = (
return getQuoteName(data);
};

export const priceChangeRenderer = (
data: MarketMaybeWithDataAndCandles | undefined,
showChangeValue = true
) => {
if (!data) return null;
return (
<Last24hPriceChange
marketId={data.id}
decimalPlaces={data.decimalPlaces}
orientation="vertical"
showChangeValue={showChangeValue}
fallback={
<span className="leading-4">
<div className="text-ellipsis whitespace-nowrap overflow-hidden">
<span data-testid="price-change-percentage">{'0.00%'}</span>
</div>
{showChangeValue && (
<span
data-testid="price-change"
className="text-ellipsis whitespace-nowrap overflow-hidden text-surface-1-fg-muted text-xs"
>
({'0.00'})
</span>
)}
</span>
}
/>
);
};

export const priceChangeSparklineRenderer = (
data: MarketMaybeWithDataAndCandles | undefined
) => {
if (!data) return null;
const candles = data.candles
?.filter((c) => c.close)
.map((c) => Number(c.close));
if (!candles?.length) return null;
return <Sparkline width={80} height={20} data={candles || [0]} />;
};

export const priceValueFormatter = (
data: MarketMaybeWithData | undefined,
formatDecimalPlaces?: number
Expand Down Expand Up @@ -240,12 +205,8 @@ export const useMarketsColumnDefs = () => {
cellRenderer: ({
data,
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
return (
<div className="flex gap-2 justify-end">
<span>{priceChangeSparklineRenderer(data)}</span>
<span>{priceChangeRenderer(data)}</span>
</div>
);
if (!data) return '-';
return <PriceChangeCell data={data} />;
},
valueGetter: ({
data,
Expand Down Expand Up @@ -358,3 +319,28 @@ const isSpotMarket = (
const product = market?.tradableInstrument?.instrument?.product;
return product && isSpot(product);
};

const PriceChangeCell = (props: { data: MarketMaybeWithData }) => {
const { sparkline, priceChange, pctChange } = useCandleData(props.data.id);
return (
<div className="flex gap-2 items-center justify-end">
<span>
{sparkline && <Sparkline data={sparkline} width={76} height={20} />}
</span>
<span className={cn('leading-4', signedNumberCssClass(pctChange || 0))}>
<span className="flex items-center justify-end gap-1 text-ellipsis whitespace-nowrap overflow-hidden">
<Arrow value={pctChange || 0} />
<span data-testid="price-change-percentage">
{formatNumberPercentage(BigNumber(pctChange || 0), 2)}
</span>
</span>
<span
data-testid="price-change"
className="text-ellipsis whitespace-nowrap overflow-hidden text-surface-0-fg-muted text-xs"
>
({formatNumber(priceChange || 0, 3)})
</span>
</span>
</div>
);
};
69 changes: 33 additions & 36 deletions apps/trading/components/amm/stats/volume-24.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
import { useCandleData, type Market } from '@vegaprotocol/rest';

import { LoaderCircleIcon } from 'lucide-react';
import { Currency } from '../currency';
import { CompactNumber } from '@vegaprotocol/react-helpers';
import BigNumber from 'bignumber.js';
import type { Market } from '@vegaprotocol/rest';

export const Volume24 = ({ market }: { market: Market }) => {
const { notional, status } = useCandleData(market.id);
throw new Error('candles service does not contain notional value');
// const { notional, status } = useCandleData(market.id);

if (status === 'pending') {
return (
<div className="h-4 py-1">
<LoaderCircleIcon size={16} className="animate-spin" />
</div>
);
}
// if (status === 'pending') {
// return (
// <div className="h-4 py-1">
// <LoaderCircleIcon size={16} className="animate-spin" />
// </div>
// );
// }

return (
<Currency
value={notional}
symbol={market.quoteSymbol}
formatDecimals={market.positionDecimalPlaces}
/>
);
// return (
// <Currency
// value={notional}
// symbol={market.quoteSymbol}
// formatDecimals={market.positionDecimalPlaces}
// />
// );
};

export const CompactVolume24 = ({ market }: { market: Market }) => {
const { notional, status } = useCandleData(market.id);
throw new Error('candles service does not contain notional value');
// const { notional, status } = useCandleData(market.id);

if (status === 'pending') {
return (
<div className="h-4 py-1">
<LoaderCircleIcon size={14} className="animate-spin" />
</div>
);
}
// if (status === 'pending') {
// return (
// <div className="h-4 py-1">
// <LoaderCircleIcon size={14} className="animate-spin" />
// </div>
// );
// }

return (
<CompactNumber
number={notional || BigNumber(0)}
decimals={2}
compactAbove={1000}
/>
);
// return (
// <CompactNumber
// number={notional || BigNumber(0)}
// decimals={2}
// compactAbove={1000}
// />
// );
};
6 changes: 3 additions & 3 deletions apps/trading/components/market-card/market-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ export const MarketCard = ({ marketId }: { marketId: string }) => {
{priceChange && (
<p
className={cn('text-sm flex items-center justify-end gap-1', {
'text-dir-up-fg': priceChange?.isPositive(),
'text-dir-down-fg': priceChange?.isNegative(),
'text-dir-up-fg': priceChange > 0,
'text-dir-down-fg': priceChange < 0,
})}
>
<VegaIcon
size={10}
name={
priceChange?.isPositive()
priceChange > 0
? VegaIconNames.CHEVRON_UP
: VegaIconNames.CHEVRON_DOWN
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ jest.mock('@vegaprotocol/wallet-react', () => ({
useChainId: jest.fn(() => '1'),
}));

jest.mock('@vegaprotocol/rest', () => ({
useCandleData: () => ({ sparkline: [] }),
}));

describe('MarketSelectorItem', () => {
const yesterday = new Date();
yesterday.setHours(yesterday.getHours() - 20);
Expand Down
10 changes: 3 additions & 7 deletions apps/trading/components/market-selector/market-selector-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useT } from '../../lib/use-t';
import { Emblem } from '@vegaprotocol/emblem';
import { MarketIcon } from '../../client-pages/markets/market-icon';
import { MarketProductPill } from '@vegaprotocol/datagrid';
import { useCandleData } from '@vegaprotocol/rest';

export const MarketSelectorItem = ({
market,
Expand Down Expand Up @@ -66,6 +67,7 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
: '-';

const { oneDayCandles } = useCandles({ marketId: market.id });
const { sparkline } = useCandleData(market.id);

const vol = oneDayCandles ? calcCandleVolume(oneDayCandles) : '0';
const volume =
Expand Down Expand Up @@ -105,13 +107,7 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
{volume}
</div>
<div className="hidden col-span-2 sm:flex justify-end" role="gridcell">
{oneDayCandles && (
<Sparkline
width={64}
height={15}
data={oneDayCandles.map((c) => Number(c.close))}
/>
)}
{sparkline && <Sparkline width={64} height={15} data={sparkline} />}
</div>
</>
);
Expand Down
Loading

0 comments on commit 870a927

Please sign in to comment.