feat(market-depth): additional orderbook grouping levels (#4658)
This commit is contained in:
parent
b5ba4f99d9
commit
1208d3f2a8
@ -1,117 +0,0 @@
|
|||||||
const orderbookTab = 'Orderbook';
|
|
||||||
const orderbookTable = 'tab-orderbook';
|
|
||||||
const askPrice = 'price-9894185';
|
|
||||||
const bidPrice = 'price-9889001';
|
|
||||||
const askVolume = 'ask-vol-9894185';
|
|
||||||
const bidVolume = 'bid-vol-9889001';
|
|
||||||
const askCumulative = 'cumulative-vol-9894185';
|
|
||||||
const bidCumulative = 'cumulative-vol-9889001';
|
|
||||||
const midPrice = 'last-traded-4612690000';
|
|
||||||
const priceResolution = 'resolution';
|
|
||||||
const dealTicketPrice = 'order-price';
|
|
||||||
const dealTicketSize = 'order-size';
|
|
||||||
const resPrice = 'price-990';
|
|
||||||
|
|
||||||
describe('order book', { tags: '@smoke' }, () => {
|
|
||||||
before(() => {
|
|
||||||
cy.setOnBoardingViewed();
|
|
||||||
cy.mockTradingPage();
|
|
||||||
cy.mockSubscription();
|
|
||||||
cy.visit('/#/markets/market-0');
|
|
||||||
cy.wait('@Markets');
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.mockTradingPage();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('show order book', () => {
|
|
||||||
// 6003-ORDB-001
|
|
||||||
// 6003-ORDB-002
|
|
||||||
cy.getByTestId(orderbookTab).click();
|
|
||||||
cy.getByTestId(orderbookTable).should('be.visible');
|
|
||||||
cy.getByTestId(orderbookTable).should('not.be.empty');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('show orders prices', () => {
|
|
||||||
// 6003-ORDB-003
|
|
||||||
cy.getByTestId(askPrice).should('have.text', '98.94185');
|
|
||||||
cy.getByTestId(bidPrice).should('have.text', '98.89001');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('show prices volumes', () => {
|
|
||||||
// 6003-ORDB-004
|
|
||||||
cy.getByTestId(askVolume).should('have.text', '1');
|
|
||||||
cy.getByTestId(bidVolume).should('have.text', '1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('show prices cumulative volumes', () => {
|
|
||||||
// 6003-ORDB-005
|
|
||||||
cy.getByTestId(askCumulative).should('have.text', '38');
|
|
||||||
cy.getByTestId(bidCumulative).should('have.text', '7');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('show mid price', () => {
|
|
||||||
// 6003-ORDB-006
|
|
||||||
cy.getByTestId(midPrice).should('have.text', '46,126.90');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sort prices descending', () => {
|
|
||||||
// 6003-ORDB-007
|
|
||||||
const prices: number[] = [];
|
|
||||||
cy.getByTestId(orderbookTable).within(() => {
|
|
||||||
cy.get('[data-testid*=price]')
|
|
||||||
.each(($el) => {
|
|
||||||
prices.push(Number($el.text()));
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
expect(prices).to.deep.equal(prices.sort((a, b) => b - a));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('copy price to deal ticket form', () => {
|
|
||||||
// 6003-ORDB-009
|
|
||||||
cy.getByTestId(askPrice).click();
|
|
||||||
cy.getByTestId(dealTicketPrice).should('have.value', '98.94185');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('copy size to deal ticket form', () => {
|
|
||||||
// 6003-ORDB-009
|
|
||||||
cy.getByTestId(bidCumulative).click();
|
|
||||||
cy.getByTestId(dealTicketSize).should('have.value', '7');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('copy size to deal ticket form', () => {
|
|
||||||
// 6003-ORDB-009
|
|
||||||
cy.getByTestId(bidVolume).click();
|
|
||||||
cy.getByTestId(dealTicketSize).should('have.value', '1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('change price resolution', () => {
|
|
||||||
// 6003-ORDB-008
|
|
||||||
const resolutions = [
|
|
||||||
'0.00000',
|
|
||||||
'0.0000',
|
|
||||||
'0.000',
|
|
||||||
'0.00',
|
|
||||||
'0.0',
|
|
||||||
'0',
|
|
||||||
'10',
|
|
||||||
'100',
|
|
||||||
'1,000',
|
|
||||||
'10,000',
|
|
||||||
];
|
|
||||||
cy.getByTestId(priceResolution).click();
|
|
||||||
cy.get('[role="menu"]')
|
|
||||||
.find('[role="menuitem"]')
|
|
||||||
.each(($el, index) => {
|
|
||||||
expect($el.text()).to.equal(resolutions[index]);
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('[role="menuitem"]').eq(4).click();
|
|
||||||
cy.getByTestId(resPrice).should('have.text', '99.0');
|
|
||||||
cy.getByTestId(askPrice).should('not.exist');
|
|
||||||
cy.getByTestId(bidPrice).should('not.exist');
|
|
||||||
});
|
|
||||||
});
|
|
@ -7,7 +7,7 @@ import {
|
|||||||
TradingDropdownContent,
|
TradingDropdownContent,
|
||||||
TradingDropdownItem,
|
TradingDropdownItem,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { formatNumberFixed } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
export const OrderbookControls = ({
|
export const OrderbookControls = ({
|
||||||
lastTradedPrice,
|
lastTradedPrice,
|
||||||
@ -15,27 +15,14 @@ export const OrderbookControls = ({
|
|||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
setResolution,
|
setResolution,
|
||||||
}: {
|
}: {
|
||||||
lastTradedPrice: string | undefined;
|
lastTradedPrice: string;
|
||||||
resolution: number;
|
resolution: number;
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
setResolution: (resolution: number) => void;
|
setResolution: (resolution: number) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const [isOpen, setOpen] = useState(false);
|
const [isOpen, setOpen] = useState(false);
|
||||||
|
|
||||||
const resolutions = new Array(
|
const resolutions = createResolutions(lastTradedPrice, decimalPlaces);
|
||||||
Math.max(lastTradedPrice?.toString().length ?? 0, decimalPlaces + 1)
|
|
||||||
)
|
|
||||||
.fill(null)
|
|
||||||
.map((v, i) => Math.pow(10, i));
|
|
||||||
|
|
||||||
const formatResolution = (r: number) => {
|
|
||||||
return formatNumberFixed(
|
|
||||||
Math.log10(r) - decimalPlaces > 0
|
|
||||||
? Math.pow(10, Math.log10(r) - decimalPlaces)
|
|
||||||
: 0,
|
|
||||||
decimalPlaces - Math.log10(r)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const increaseResolution = () => {
|
const increaseResolution = () => {
|
||||||
const index = resolutions.indexOf(resolution);
|
const index = resolutions.indexOf(resolution);
|
||||||
@ -56,7 +43,7 @@ export const OrderbookControls = ({
|
|||||||
<button
|
<button
|
||||||
onClick={increaseResolution}
|
onClick={increaseResolution}
|
||||||
disabled={resolutions.indexOf(resolution) >= resolutions.length - 1}
|
disabled={resolutions.indexOf(resolution) >= resolutions.length - 1}
|
||||||
className="flex items-center px-2 border-r cursor-pointer border-default"
|
className="flex items-center px-2 border-r cursor-pointer border-default disabled:cursor-default"
|
||||||
data-testid="plus-button"
|
data-testid="plus-button"
|
||||||
>
|
>
|
||||||
<VegaIcon size={12} name={VegaIconNames.PLUS} />
|
<VegaIcon size={12} name={VegaIconNames.PLUS} />
|
||||||
@ -67,12 +54,14 @@ export const OrderbookControls = ({
|
|||||||
trigger={
|
trigger={
|
||||||
<TradingDropdownTrigger data-testid="resolution">
|
<TradingDropdownTrigger data-testid="resolution">
|
||||||
<button
|
<button
|
||||||
className="flex items-center px-2 text-left gap-1"
|
className="flex items-center justify-between px-2 gap-1"
|
||||||
style={{
|
style={{
|
||||||
minWidth: `${
|
minWidth: `${
|
||||||
Math.max.apply(
|
Math.max.apply(
|
||||||
null,
|
null,
|
||||||
resolutions.map((item) => formatResolution(item).length)
|
resolutions.map(
|
||||||
|
(item) => formatResolution(item, decimalPlaces).length
|
||||||
|
)
|
||||||
) + 5
|
) + 5
|
||||||
}ch`,
|
}ch`,
|
||||||
}}
|
}}
|
||||||
@ -83,15 +72,19 @@ export const OrderbookControls = ({
|
|||||||
isOpen ? VegaIconNames.CHEVRON_UP : VegaIconNames.CHEVRON_DOWN
|
isOpen ? VegaIconNames.CHEVRON_UP : VegaIconNames.CHEVRON_DOWN
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{formatResolution(resolution)}
|
{formatResolution(resolution, decimalPlaces)}
|
||||||
</button>
|
</button>
|
||||||
</TradingDropdownTrigger>
|
</TradingDropdownTrigger>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TradingDropdownContent align="start">
|
<TradingDropdownContent align="start">
|
||||||
{resolutions.map((r) => (
|
{resolutions.map((r) => (
|
||||||
<TradingDropdownItem key={r} onClick={() => setResolution(r)}>
|
<TradingDropdownItem
|
||||||
{formatResolution(r)}
|
key={r}
|
||||||
|
onClick={() => setResolution(r)}
|
||||||
|
className="justify-end"
|
||||||
|
>
|
||||||
|
{formatResolution(r, decimalPlaces)}
|
||||||
</TradingDropdownItem>
|
</TradingDropdownItem>
|
||||||
))}
|
))}
|
||||||
</TradingDropdownContent>
|
</TradingDropdownContent>
|
||||||
@ -99,7 +92,7 @@ export const OrderbookControls = ({
|
|||||||
<button
|
<button
|
||||||
onClick={decreaseResolution}
|
onClick={decreaseResolution}
|
||||||
disabled={resolutions.indexOf(resolution) <= 0}
|
disabled={resolutions.indexOf(resolution) <= 0}
|
||||||
className="flex items-center px-2 cursor-pointer border-x border-default"
|
className="flex items-center px-2 cursor-pointer border-x border-default disabled:cursor-default"
|
||||||
data-testid="minus-button"
|
data-testid="minus-button"
|
||||||
>
|
>
|
||||||
<VegaIcon size={12} name={VegaIconNames.MINUS} />
|
<VegaIcon size={12} name={VegaIconNames.MINUS} />
|
||||||
@ -107,3 +100,49 @@ export const OrderbookControls = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const formatResolution = (r: number, decimalPlaces: number) => {
|
||||||
|
let num = addDecimalsFormatNumber(r, decimalPlaces);
|
||||||
|
|
||||||
|
// Remove trailing zeroes
|
||||||
|
num = num.replace(/\.?0+$/, '');
|
||||||
|
|
||||||
|
return num;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list of resolutions based on the largest and smallest
|
||||||
|
* possible values using the last traded price and the market
|
||||||
|
* decimal places
|
||||||
|
*/
|
||||||
|
export const createResolutions = (
|
||||||
|
lastTradedPrice: string,
|
||||||
|
decimalPlaces: number
|
||||||
|
) => {
|
||||||
|
// number of levels determined by either the number
|
||||||
|
// of digits in the last traded price OR the number of decimal
|
||||||
|
// places. For example:
|
||||||
|
//
|
||||||
|
// last traded = 1 (0.001)
|
||||||
|
// dps = 3
|
||||||
|
// result = 3
|
||||||
|
//
|
||||||
|
// last traded = 100001 (1000.01
|
||||||
|
// dps = 2
|
||||||
|
// result = 6
|
||||||
|
const levelCount = Math.max(lastTradedPrice.length ?? 0, decimalPlaces + 1);
|
||||||
|
const generatedResolutions = new Array(levelCount)
|
||||||
|
.fill(null)
|
||||||
|
.map((_, i) => Math.pow(10, i));
|
||||||
|
const customResolutions = [2, 5, 20, 50, 200, 500];
|
||||||
|
const combined = customResolutions.concat(generatedResolutions);
|
||||||
|
combined.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
// Remove any resolutions higher than the generated ones as
|
||||||
|
// we dont want a custom resolution higher than necessary
|
||||||
|
const resolutions = combined.filter((r) => {
|
||||||
|
return r <= generatedResolutions[generatedResolutions.length - 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return resolutions;
|
||||||
|
};
|
||||||
|
@ -12,7 +12,7 @@ export interface OrderbookRowData {
|
|||||||
cumulativeVol: number;
|
cumulativeVol: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPriceLevel = (price: string | bigint, resolution: number) => {
|
export const getPriceLevel = (price: string, resolution: number) => {
|
||||||
const p = BigInt(price);
|
const p = BigInt(price);
|
||||||
const r = BigInt(resolution);
|
const r = BigInt(resolution);
|
||||||
let priceLevel = (p / r) * r;
|
let priceLevel = (p / r) * r;
|
||||||
@ -43,7 +43,7 @@ const updateCumulativeVolumeByType = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const compactRows = (
|
export const compactRows = (
|
||||||
data: PriceLevelFieldsFragment[] | null | undefined,
|
data: PriceLevelFieldsFragment[],
|
||||||
dataType: VolumeType,
|
dataType: VolumeType,
|
||||||
resolution: number
|
resolution: number
|
||||||
) => {
|
) => {
|
||||||
|
@ -13,6 +13,7 @@ interface OrderbookRowProps {
|
|||||||
cumulativeVolume: number;
|
cumulativeVolume: number;
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
positionDecimalPlaces: number;
|
positionDecimalPlaces: number;
|
||||||
|
priceFormatDecimalPlaces: number;
|
||||||
price: string;
|
price: string;
|
||||||
onClick: (args: { price?: string; size?: string }) => void;
|
onClick: (args: { price?: string; size?: string }) => void;
|
||||||
type: VolumeType;
|
type: VolumeType;
|
||||||
@ -26,6 +27,7 @@ export const OrderbookRow = memo(
|
|||||||
cumulativeVolume,
|
cumulativeVolume,
|
||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
positionDecimalPlaces,
|
positionDecimalPlaces,
|
||||||
|
priceFormatDecimalPlaces,
|
||||||
price,
|
price,
|
||||||
onClick,
|
onClick,
|
||||||
type,
|
type,
|
||||||
@ -35,6 +37,7 @@ export const OrderbookRow = memo(
|
|||||||
const txtId = type === VolumeType.bid ? 'bid' : 'ask';
|
const txtId = type === VolumeType.bid ? 'bid' : 'ask';
|
||||||
const cols =
|
const cols =
|
||||||
width >= HIDE_CUMULATIVE_VOL_WIDTH ? 3 : width >= HIDE_VOL_WIDTH ? 2 : 1;
|
width >= HIDE_CUMULATIVE_VOL_WIDTH ? 3 : width >= HIDE_VOL_WIDTH ? 2 : 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative px-1">
|
<div className="relative px-1">
|
||||||
<CumulationBar
|
<CumulationBar
|
||||||
@ -54,7 +57,8 @@ export const OrderbookRow = memo(
|
|||||||
value={BigInt(price)}
|
value={BigInt(price)}
|
||||||
valueFormatted={addDecimalsFixedFormatNumber(
|
valueFormatted={addDecimalsFixedFormatNumber(
|
||||||
price,
|
price,
|
||||||
decimalPlaces
|
decimalPlaces,
|
||||||
|
priceFormatDecimalPlaces
|
||||||
)}
|
)}
|
||||||
className={classNames({
|
className={classNames({
|
||||||
'text-market-red dark:text-market-red': type === VolumeType.ask,
|
'text-market-red dark:text-market-red': type === VolumeType.ask,
|
||||||
|
@ -3,6 +3,7 @@ import userEvent from '@testing-library/user-event';
|
|||||||
import { generateMockData, VolumeType } from './orderbook-data';
|
import { generateMockData, VolumeType } from './orderbook-data';
|
||||||
import { Orderbook, OrderbookMid } from './orderbook';
|
import { Orderbook, OrderbookMid } from './orderbook';
|
||||||
import * as orderbookData from './orderbook-data';
|
import * as orderbookData from './orderbook-data';
|
||||||
|
import { createResolutions, formatResolution } from './orderbook-controls';
|
||||||
|
|
||||||
function mockOffsetSize(width: number, height: number) {
|
function mockOffsetSize(width: number, height: number) {
|
||||||
Object.defineProperty(HTMLElement.prototype, 'getBoundingClientRect', {
|
Object.defineProperty(HTMLElement.prototype, 'getBoundingClientRect', {
|
||||||
@ -37,7 +38,8 @@ describe('Orderbook', () => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
mockOffsetSize(800, 768);
|
mockOffsetSize(800, 768);
|
||||||
});
|
});
|
||||||
it('markPrice should be in the middle', async () => {
|
|
||||||
|
it('lastTradedPrice should be in the middle', async () => {
|
||||||
render(
|
render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
@ -71,6 +73,7 @@ describe('Orderbook', () => {
|
|||||||
expect(
|
expect(
|
||||||
await screen.findByTestId(`last-traded-${params.lastTradedPrice}`)
|
await screen.findByTestId(`last-traded-${params.lastTradedPrice}`)
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
|
||||||
// Before resolution change the price is 122.934
|
// Before resolution change the price is 122.934
|
||||||
await userEvent.click(screen.getByTestId('price-122901'));
|
await userEvent.click(screen.getByTestId('price-122901'));
|
||||||
expect(onClickSpy).toBeCalledWith({ price: '122.901' });
|
expect(onClickSpy).toBeCalledWith({ price: '122.901' });
|
||||||
@ -86,15 +89,16 @@ describe('Orderbook', () => {
|
|||||||
expect(orderbookData.compactRows).toHaveBeenCalledWith(
|
expect(orderbookData.compactRows).toHaveBeenCalledWith(
|
||||||
mockedData.bids,
|
mockedData.bids,
|
||||||
VolumeType.bid,
|
VolumeType.bid,
|
||||||
10
|
2
|
||||||
);
|
);
|
||||||
expect(orderbookData.compactRows).toHaveBeenCalledWith(
|
expect(orderbookData.compactRows).toHaveBeenCalledWith(
|
||||||
mockedData.asks,
|
mockedData.asks,
|
||||||
VolumeType.ask,
|
VolumeType.ask,
|
||||||
10
|
2
|
||||||
);
|
);
|
||||||
await userEvent.click(screen.getByTestId('price-12294'));
|
|
||||||
expect(onClickSpy).toBeCalledWith({ price: '122.94' });
|
await userEvent.click(screen.getByTestId('price-122938'));
|
||||||
|
expect(onClickSpy).toBeCalledWith({ price: '122.938' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('plus - minus buttons should change resolution', async () => {
|
it('plus - minus buttons should change resolution', async () => {
|
||||||
@ -114,26 +118,30 @@ describe('Orderbook', () => {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('minus-button')).toBeDisabled();
|
expect(screen.getByTestId('minus-button')).toBeDisabled();
|
||||||
userEvent.click(screen.getByTestId('plus-button'));
|
await userEvent.click(screen.getByTestId('plus-button'));
|
||||||
|
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
|
await userEvent.click(screen.getByTestId('plus-button'));
|
||||||
|
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||||
|
5
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('minus-button')).not.toBeDisabled();
|
||||||
|
await userEvent.click(screen.getByTestId('minus-button'));
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||||
10
|
2
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
expect(screen.getByTestId('minus-button')).not.toBeDisabled();
|
expect(screen.getByTestId('minus-button')).not.toBeDisabled();
|
||||||
userEvent.click(screen.getByTestId('minus-button'));
|
|
||||||
await waitFor(() => {
|
|
||||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
|
||||||
1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
expect(screen.getByTestId('minus-button')).toBeDisabled();
|
|
||||||
await userEvent.click(screen.getByTestId('resolution'));
|
|
||||||
|
|
||||||
|
await userEvent.click(screen.getByTestId('resolution'));
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
await userEvent.click(screen.getAllByRole('menuitem')[5]);
|
await userEvent.click(screen.getAllByRole('menuitem')[11]);
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||||
100000
|
100000
|
||||||
@ -223,3 +231,58 @@ describe('OrderbookMid', () => {
|
|||||||
expect(screen.getByTestId('icon-arrow-down')).toBeInTheDocument();
|
expect(screen.getByTestId('icon-arrow-down')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('createResolutions', () => {
|
||||||
|
it('create resolutions relative to the market', () => {
|
||||||
|
expect(
|
||||||
|
createResolutions(
|
||||||
|
'1', // 0.001
|
||||||
|
3
|
||||||
|
)
|
||||||
|
).toEqual([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
createResolutions(
|
||||||
|
'190017', // 1900.17
|
||||||
|
2
|
||||||
|
)
|
||||||
|
).toEqual([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 10000, 100000]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
createResolutions(
|
||||||
|
'123456789', // 1234.56789
|
||||||
|
5
|
||||||
|
)
|
||||||
|
).toEqual([
|
||||||
|
1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 10000, 100000, 1000000,
|
||||||
|
10000000, 100000000,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes resolutions that arent precise enough for the market', () => {
|
||||||
|
expect(
|
||||||
|
createResolutions(
|
||||||
|
'1', // 0.01
|
||||||
|
2
|
||||||
|
)
|
||||||
|
).toEqual([1, 2, 5, 10, 20, 50, 100]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('formatResolution', () => {
|
||||||
|
it('formats less than 1', () => {
|
||||||
|
expect(formatResolution(1, 2)).toEqual('0.01');
|
||||||
|
expect(formatResolution(1, 3)).toEqual('0.001');
|
||||||
|
expect(formatResolution(2, 4)).toEqual('0.0002');
|
||||||
|
expect(formatResolution(5, 8)).toEqual('0.00000005');
|
||||||
|
expect(formatResolution(10000, 5)).toEqual('0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('formats greater than 1', () => {
|
||||||
|
expect(formatResolution(1000, 2)).toEqual('10');
|
||||||
|
expect(formatResolution(100000, 4)).toEqual('10');
|
||||||
|
expect(formatResolution(10000000, 2)).toEqual('100,000');
|
||||||
|
expect(formatResolution(500, 2)).toEqual('5');
|
||||||
|
expect(formatResolution(500, 1)).toEqual('50');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -23,6 +23,7 @@ const OrderbookSide = ({
|
|||||||
type,
|
type,
|
||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
positionDecimalPlaces,
|
positionDecimalPlaces,
|
||||||
|
priceFormatDecimalPlaces,
|
||||||
onClick,
|
onClick,
|
||||||
width,
|
width,
|
||||||
maxVol,
|
maxVol,
|
||||||
@ -31,6 +32,7 @@ const OrderbookSide = ({
|
|||||||
resolution: number;
|
resolution: number;
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
positionDecimalPlaces: number;
|
positionDecimalPlaces: number;
|
||||||
|
priceFormatDecimalPlaces: number;
|
||||||
type: VolumeType;
|
type: VolumeType;
|
||||||
onClick: (args: { price?: string; size?: string }) => void;
|
onClick: (args: { price?: string; size?: string }) => void;
|
||||||
width: number;
|
width: number;
|
||||||
@ -53,10 +55,11 @@ const OrderbookSide = ({
|
|||||||
{rows.map((data) => (
|
{rows.map((data) => (
|
||||||
<OrderbookRow
|
<OrderbookRow
|
||||||
key={data.price}
|
key={data.price}
|
||||||
price={(BigInt(data.price) / BigInt(resolution)).toString()}
|
price={data.price}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
decimalPlaces={decimalPlaces - Math.log10(resolution)}
|
decimalPlaces={decimalPlaces}
|
||||||
positionDecimalPlaces={positionDecimalPlaces}
|
positionDecimalPlaces={positionDecimalPlaces}
|
||||||
|
priceFormatDecimalPlaces={priceFormatDecimalPlaces}
|
||||||
volume={data.volume}
|
volume={data.volume}
|
||||||
cumulativeVolume={data.cumulativeVol}
|
cumulativeVolume={data.cumulativeVol}
|
||||||
type={type}
|
type={type}
|
||||||
@ -165,6 +168,12 @@ export const Orderbook = ({
|
|||||||
const bestAskPrice = asks[0] ? asks[0].price : '0';
|
const bestAskPrice = asks[0] ? asks[0].price : '0';
|
||||||
const bestBidPrice = bids[0] ? bids[0].price : '0';
|
const bestBidPrice = bids[0] ? bids[0].price : '0';
|
||||||
|
|
||||||
|
// we'll want to only display a relevant number of dps based on the
|
||||||
|
// current resolution selection
|
||||||
|
const priceFormatDecimalPlaces = Math.ceil(
|
||||||
|
decimalPlaces - Math.log10(resolution)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full text-xs grid grid-rows-[1fr_min-content]">
|
<div className="h-full text-xs grid grid-rows-[1fr_min-content]">
|
||||||
<div>
|
<div>
|
||||||
@ -203,6 +212,7 @@ export const Orderbook = ({
|
|||||||
resolution={resolution}
|
resolution={resolution}
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
positionDecimalPlaces={positionDecimalPlaces}
|
positionDecimalPlaces={positionDecimalPlaces}
|
||||||
|
priceFormatDecimalPlaces={priceFormatDecimalPlaces}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
width={width}
|
width={width}
|
||||||
maxVol={maxVol}
|
maxVol={maxVol}
|
||||||
@ -220,6 +230,7 @@ export const Orderbook = ({
|
|||||||
resolution={resolution}
|
resolution={resolution}
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
positionDecimalPlaces={positionDecimalPlaces}
|
positionDecimalPlaces={positionDecimalPlaces}
|
||||||
|
priceFormatDecimalPlaces={priceFormatDecimalPlaces}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
width={width}
|
width={width}
|
||||||
maxVol={maxVol}
|
maxVol={maxVol}
|
||||||
|
Loading…
Reference in New Issue
Block a user