Skip to content

Commit

Permalink
Slippage and HLP graph
Browse files Browse the repository at this point in the history
* Can select by coin in slippage graph
* HLP hedged pnl now hedges all coins
  • Loading branch information
tradermohamed authored Aug 1, 2023
2 parents d6ee9fc + 6468f7b commit 3184ff1
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 35 deletions.
75 changes: 49 additions & 26 deletions components/home/charts/hlp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function Hlp() {
[],
'chart_data'
);
const [ethOraclePxs, setEthOraclePxs] = useState<Map<string, number>>(new Map());
const [oraclePxs, setOraclePxs] = useState<Map<string, number>>(new Map());
const [hlpPnL, setHlpPnL] = useState<Map<string, HlpPnl>>(new Map());
const [formattedHlpPnL, setFormattedHlpPnL] = useState<HlpPnl[]>([]);
const [formattedData, setFormattedData] = useState<GroupedData[]>([]);
Expand Down Expand Up @@ -79,12 +79,10 @@ export default function Hlp() {
hedged_pnl: number;
};

const getEthOraclePxs = (assetCtxs: AssetCtx[]): Map<string, number> => {
const getOraclePxs = (assetCtxs: AssetCtx[]): Map<string, number> => {
const map = new Map<string, number>();
assetCtxs.forEach((item) => {
if (item.coin === 'ETH') {
map.set(item.time, item.first_oracle_px);
}
map.set(item.coin + item.time, item.first_oracle_px);
});
return map;
};
Expand Down Expand Up @@ -125,35 +123,43 @@ export default function Hlp() {

let prevTime: string | null = null;
let hedgedCumulativePnl = 0;

hlpPositions.forEach((item: HlpPosition) => {
let { time, coin, daily_ntl } = item;
if (!map.has(time)) {
const pnl = hlpPnL.get(time)?.pnl;
const ethOraclePx = ethOraclePxs.get(time);
let hedgedPnl = pnl ?? 0;
const nextTime = getNextTime(time);
let ethOraclePxNext = ethOraclePxs.get(nextTime);
let prevDayNtlPosition = prevTime ? map.get(prevTime)?.daily_ntl : null;
if (ethOraclePxNext && ethOraclePx && prevDayNtlPosition) {
const ethPxChange = 1 - ethOraclePx / ethOraclePxNext;
const ethPnL = -1 * prevDayNtlPosition * ethPxChange;
hedgedPnl += ethPnL;
}
hedgedCumulativePnl += hedgedPnl;
const pnl = hlpPnL.get(time)?.pnl || 0;
hedgedCumulativePnl += pnl;
map.set(time, {
time: new Date(time),
daily_ntl: daily_ntl,
[`${coin}`]: daily_ntl,
hedged_pnl: hedgedPnl,
daily_ntl: 0,
hedged_pnl: pnl,
hedged_cumulative_pnl: hedgedCumulativePnl,
Other: 0,
});
prevTime = time;
} else {
const existingEntry = map.get(time)!;
existingEntry[`${coin}`] = (existingEntry[`${coin}`] || 0) + daily_ntl;
existingEntry.daily_ntl += daily_ntl;
}

const existingEntry = map.get(time)!;
existingEntry[`${coin}`] = (existingEntry[`${coin}`] || 0) + daily_ntl;
existingEntry.daily_ntl += daily_ntl;

const oraclePx = oraclePxs.get(coin + time);
let hedgedPnl = 0;
const nextTime = getNextTime(time);
let oraclePxNext = oraclePxs.get(coin + nextTime);

let prevTimeData = prevTime ? map.get(prevTime) : null;
let prevDayNtlPosition = prevTimeData ? prevTimeData[`${coin}`] : null;

if (oraclePxNext && oraclePx && prevDayNtlPosition) {
const pxChange = 1 - oraclePx / oraclePxNext;
const pnl = -1 * prevDayNtlPosition * pxChange;
hedgedPnl += pnl;
}

existingEntry.hedged_pnl += hedgedPnl;
hedgedCumulativePnl += hedgedPnl;
existingEntry.hedged_cumulative_pnl = hedgedCumulativePnl;
});

map.forEach((entry) => {
Expand Down Expand Up @@ -213,8 +219,8 @@ export default function Hlp() {

const formatData = () => {
if (dataHlpPositions && assetCtxs && dataHlpPnL) {
const newEthOraclePxs = getEthOraclePxs(assetCtxs);
setEthOraclePxs(newEthOraclePxs);
const newOraclePxs = getOraclePxs(assetCtxs);
setOraclePxs(newOraclePxs);
const newHlpPnL = makeHlpPnl(dataHlpPnL);
setFormattedHlpPnL(Array.from(newHlpPnL.values()));
setHlpPnL(newHlpPnL);
Expand Down Expand Up @@ -349,6 +355,23 @@ export default function Hlp() {
<Text color='#bbb'>Top 10 Coins grouped daily and remaining coins grouped by Other</Text>
)}
</Box>
<Box w='100%' mt='3'>
{dataMode === 'PNL' && (
<Text color='#bbb'>PNL over time</Text>
)}
</Box>

<Box w='100%' mt='3'>
{dataMode === 'HEDGED' && (
<Text color='#bbb'>Hedged PNL over time. Hedge the previous day's position and add to today's PNL.</Text>
)}
</Box>

<Box w='100%' mt='3'>
{dataMode === 'NET' && (
<Text color='#bbb'>Net notional position over time</Text>
)}
</Box>
</ChartWrapper>
);
}
2 changes: 1 addition & 1 deletion components/home/charts/liquidator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ export default function LiquidatorChart() {
zIndex={7}
>
<ResponsiveContainer width='100%' height={CHART_HEIGHT}>
<ComposedChart data={dataModeToData(dataMode)} syncId='syncA'>
<ComposedChart data={dataModeToData(dataMode)} syncId='liquidatorSync'>
<CartesianGrid strokeDasharray='15 15' opacity={0.1} />
<XAxis
dataKey='time'
Expand Down
48 changes: 43 additions & 5 deletions components/home/charts/liquidity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { useEffect, useState } from 'react';
import { Box, Text, useMediaQuery } from '@chakra-ui/react';
import { useRequest } from '@/hooks/useRequest';
import ChartWrapper from '../../common/chartWrapper';
import ChartWrapper, { CoinSelector } from '../../common/chartWrapper';
import { CHART_HEIGHT } from '../../../constants';
import {
tooltipFormatter,
Expand All @@ -31,6 +31,7 @@ export default function Liquidity() {
const [formattedData3000, setFormattedData3000] = useState<any[]>([]);
const [formattedData10000, setFormattedData10000] = useState<any[]>([]);

const [coinKeys, setCoinKeys] = useState<any[]>([]);
const [coinKeys0, setCoinKeys0] = useState<any[]>([]);
const [coinKeys1000, setCoinKeys1000] = useState<any[]>([]);
const [coinKeys3000, setCoinKeys3000] = useState<any[]>([]);
Expand Down Expand Up @@ -85,6 +86,14 @@ export default function Liquidity() {
median_slippage_10000: { time: Date; [key: string]: number | Date | string }[];
};

const extractCoins = (data: InputData): string[] => {
let coins = [];
for (let coin of Object.keys(data)) {
coins.push(coin);
}
return coins;
}

const transformData = (data: InputData): OutputData => {
// Filter data for each category by top 10 coins
const filteredData: InputData = {};
Expand Down Expand Up @@ -148,7 +157,7 @@ export default function Liquidity() {
data:
| OutputData['median_slippage_1000']
| OutputData['median_slippage_10000']
| OutputData['median_slippage_1000']
| OutputData['median_slippage_3000']
): string[] => {
const coinSet = new Set<string>();
data.forEach((record) => {
Expand All @@ -162,6 +171,8 @@ export default function Liquidity() {
};

const formatData = () => {
const extractedCoinKeys = extractCoins(dataLiqudity);
setCoinKeys(extractedCoinKeys);
const formattedData = transformData(dataLiqudity);
setFormattedData0(formattedData.median_slippage_0);
setFormattedData1000(formattedData.median_slippage_1000);
Expand All @@ -171,6 +182,7 @@ export default function Liquidity() {
const formattedUniqueCoinKeys1000 = extractUniqueCoins(formattedData.median_slippage_1000);
const formattedUniqueCoinKeys3000 = extractUniqueCoins(formattedData.median_slippage_3000);
const formattedUniqueCoinKeys10000 = extractUniqueCoins(formattedData.median_slippage_10000);

setCoinKeys0(formattedUniqueCoinKeys0);
setCoinKeys1000(formattedUniqueCoinKeys1000);
setCoinKeys3000(formattedUniqueCoinKeys3000);
Expand Down Expand Up @@ -201,13 +213,42 @@ export default function Liquidity() {
? coinKeys3000
: coinKeys10000;

const coinSelectorsSort = (a: CoinSelector, b: CoinSelector) => {
if (a.isChecked !== b.isChecked) {
return a.isChecked ? -1 : 1;
}
return a.name.localeCompare(b.name);
};

const coinSelectors = coinKeys
.map((coinKey: string) => {
return {
name: coinKey,
event: () =>
setCoinsSelected((coinsSelected) => {
let newCoinsSelected = coinsSelected;
if (coinsSelected.includes(coinKey)) {
newCoinsSelected = coinsSelected.filter((e) => {
return e !== coinKey;
});
} else {
newCoinsSelected.push(coinKey);
}
formatData();
return newCoinsSelected;
}),
isChecked: coinsSelected.includes(coinKey),
};
})
.sort((a: CoinSelector, b: CoinSelector) => coinSelectorsSort(a, b));
return (
<ChartWrapper
title='Slippage % by Trade Size'
loading={loading}
data={chartData}
controls={controls}
zIndex={8}
coinSelectors={coinSelectors}
>
<ResponsiveContainer width='100%' height={CHART_HEIGHT}>
<LineChart data={chartData}>
Expand Down Expand Up @@ -256,9 +297,6 @@ export default function Liquidity() {
})}
</LineChart>
</ResponsiveContainer>
<Box w='100%' mt='3'>
<Text color='#bbb'>Top 10 Coins over time</Text>
</Box>
</ChartWrapper>
);
}
2 changes: 1 addition & 1 deletion components/home/charts/retail-volume.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ export default function RetailVolumeChart() {
<ResponsiveContainer width='100%' height={CHART_HEIGHT}>
<ComposedChart
data={dataMode === 'COINS' ? formattedDataCoins : formattedDataMargin}
syncId='syncA'
syncId='retailSync'
>
<CartesianGrid strokeDasharray='15 15' opacity={0.1} />
<XAxis
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"framer-motion": "^10.12.16",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"next": "13.4.4",
"next": "^13.4.4",
"polished": "^4.2.2",
"prettier": "^3.0.0",
"react": "18.2.0",
Expand Down

0 comments on commit 3184ff1

Please sign in to comment.