diff --git a/components/account/AccountChart.tsx b/components/account/AccountChart.tsx index 488548b4..09799b6f 100644 --- a/components/account/AccountChart.tsx +++ b/components/account/AccountChart.tsx @@ -4,18 +4,18 @@ import { formatYAxis } from 'utils/formatting' import { HourlyFundingChartData, PerformanceDataItem } from 'types' import { ContentType } from 'recharts/types/component/Tooltip' import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart' -import { ChartToShow } from './AccountPage' +import { ViewToShow } from './AccountPage' import { ArrowLeftIcon, NoSymbolIcon } from '@heroicons/react/20/solid' -const CHART_TABS: ChartToShow[] = [ +const CHART_TABS: ViewToShow[] = [ 'account-value', 'pnl', 'cumulative-interest-value', ] const AccountChart = ({ - chartToShow, - setChartToShow, + chartName, + handleViewChange, customTooltip, data, hideChart, @@ -23,8 +23,8 @@ const AccountChart = ({ yDecimals, yKey, }: { - chartToShow: ChartToShow - setChartToShow: (chart: ChartToShow) => void + chartName: ViewToShow + handleViewChange: (view: ViewToShow) => void customTooltip?: ContentType data: PerformanceDataItem[] | HourlyFundingChartData[] | undefined hideChart: () => void @@ -37,7 +37,7 @@ const AccountChart = ({ const chartData = useMemo(() => { if (!data || !data.length) return [] - if (chartToShow === 'cumulative-interest-value') { + if (chartName === 'cumulative-interest-value') { return data.map((d) => ({ interest_value: d.borrow_interest_cumulative_usd * -1 + @@ -46,7 +46,7 @@ const AccountChart = ({ })) } return data - }, [data, chartToShow]) + }, [data, chartName]) return ( <> @@ -61,11 +61,11 @@ const AccountChart = ({ {CHART_TABS.map((tab) => ( +

{t('account:health-contributions')}

+ + {mangoAccountAddress ? ( + <> +
+
+ +

+ {t('account:init-health-contributions')} +

+
+ +
+
+ +

+ {t('account:maint-health-contributions')} +

+
+ +
+
+ {[...maintChartData] + .sort((a, b) => b.contribution - a.contribution) + .map((d, i) => { + return ( +
handleLegendClick(d)} + onMouseEnter={() => handleLegendMouseEnter(d)} + onMouseLeave={handleLegendMouseLeave} + > + {renderLegendLogo(d.asset)} + {d.asset} +
+ ) + })} +
+
+ {maintHealthTokens.length ? ( +
+

{t('tokens')}

+ +
+ ) : null} + {maintHealthMarkets.length ? ( +
+

{t('markets')}

+ +
+ ) : null} + + ) : ( +
+ +

{t('account:no-data')}

+
+ )} + + ) : null +} + +export default HealthContributions diff --git a/components/account/HealthContributionsChart.tsx b/components/account/HealthContributionsChart.tsx new file mode 100644 index 00000000..18cf57ed --- /dev/null +++ b/components/account/HealthContributionsChart.tsx @@ -0,0 +1,148 @@ +import { useTranslation } from 'next-i18next' +import { useTheme } from 'next-themes' +import { + Cell, + Pie, + PieChart, + ResponsiveContainer, + Sector, + SectorProps, +} from 'recharts' +import { COLORS } from 'styles/colors' +import { useMemo } from 'react' +import { formatCurrencyValue } from 'utils/numbers' +import { useViewport } from 'hooks/useViewport' +import { breakpoints } from 'utils/theme' +import { HealthContribution } from 'types' + +const HealthContributionsChart = ({ + data, + activeIndex, + setActiveIndex, +}: { + data: HealthContribution[] + activeIndex: number | undefined + setActiveIndex: (i: number | undefined) => void +}) => { + const { t } = useTranslation(['common', 'account']) + const { theme } = useTheme() + const { width } = useViewport() + const isMobile = width ? width < breakpoints.sm : false + + const handleClick = (index: number) => { + setActiveIndex(index) + } + + const handleMouseEnter = (data: HealthContribution, index: number) => { + setActiveIndex(index) + } + + const handleMouseLeave = () => { + setActiveIndex(undefined) + } + + const pieSizes = isMobile + ? { size: 160, outerRadius: 80, innerRadius: 64 } + : { size: 240, outerRadius: 120, innerRadius: 96 } + const { size, outerRadius, innerRadius } = pieSizes + + const [chartHeroAsset, chartHeroValue] = useMemo(() => { + if (!data.length) return [undefined, undefined] + if (activeIndex === undefined) { + const value = data.reduce((a, c) => { + const assetOrLiabMultiplier = c.isAsset ? 1 : -1 + return a + c.contribution * assetOrLiabMultiplier + }, 0) + return [t('total'), value] + } else { + const asset = data[activeIndex] + const assetOrLiabMultiplier = asset.isAsset ? 1 : -1 + const value = asset.contribution * assetOrLiabMultiplier + return [asset.asset, value] + } + }, [activeIndex, data]) + + const renderActiveShape = ({ + cx, + cy, + innerRadius, + outerRadius, + startAngle, + endAngle, + fill, + }: SectorProps) => { + return ( + + + + ) + } + + return data.length ? ( +
+
+ + + + {data.map((entry, index) => { + const fillColor = entry.isAsset + ? COLORS.UP[theme] + : COLORS.DOWN[theme] + + let opacity + + if (entry.isAsset) { + opacity = 1 - index * 0.1 + } else { + opacity = 1 - Math.abs((index - (data.length - 1)) * 0.1) + } + return ( + + ) + })} + + + + {chartHeroValue !== undefined ? ( +
+

{chartHeroAsset}

+ + {formatCurrencyValue(chartHeroValue, 2)} + +
+ ) : null} +
+
+ ) : null +} + +export default HealthContributionsChart diff --git a/components/account/MarketsHealthTable.tsx b/components/account/MarketsHealthTable.tsx new file mode 100644 index 00000000..ae5a6175 --- /dev/null +++ b/components/account/MarketsHealthTable.tsx @@ -0,0 +1,276 @@ +import FormatNumericValue from '@components/shared/FormatNumericValue' +import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' +import Tooltip from '@components/shared/Tooltip' +import { Disclosure, Transition } from '@headlessui/react' +import { ChevronDownIcon } from '@heroicons/react/20/solid' +import { useTranslation } from 'next-i18next' +import useMangoGroup from 'hooks/useMangoGroup' +import useMangoAccount from 'hooks/useMangoAccount' +import { useViewport } from 'hooks/useViewport' +import { breakpoints } from 'utils/theme' +import { MouseEventHandler } from 'react' +import MarketLogos from '@components/trade/MarketLogos' +import { HealthContribution } from 'types' + +const MarketsHealthTable = ({ + initMarkets, + maintMarkets, + handleLegendClick, + handleLegendMouseEnter, + handleLegendMouseLeave, +}: { + initMarkets: HealthContribution[] + maintMarkets: HealthContribution[] + handleLegendClick: (cont: HealthContribution) => void + handleLegendMouseEnter: (cont: HealthContribution) => void + handleLegendMouseLeave: MouseEventHandler +}) => { + const { t } = useTranslation(['common', 'account', 'trade']) + const { group } = useMangoGroup() + const { mangoAccount } = useMangoAccount() + const { width } = useViewport() + const isMobile = width ? width < breakpoints.sm : false + return group && mangoAccount ? ( + !isMobile ? ( + + + + + + + + + + {maintMarkets + .sort((a, b) => b.contribution - a.contribution) + .map((cont) => { + const { asset, contribution, isAsset } = cont + const market = group.getSerum3MarketByName(asset) + const bank = group.banksMapByTokenIndex.get( + market.baseTokenIndex + )?.[0] + + let initAssetWeight = 0 + let initLiabWeight = 0 + let maintAssetWeight = 0 + let maintLiabWeight = 0 + + if (bank) { + initAssetWeight = bank + .scaledInitAssetWeight(bank.price) + .toNumber() + initLiabWeight = bank + .scaledInitLiabWeight(bank.price) + .toNumber() + maintAssetWeight = bank.maintAssetWeight.toNumber() + maintLiabWeight = bank.maintLiabWeight.toNumber() + } + + const assetOrLiabMultiplier = isAsset ? 1 : -1 + + const initContribution = + (initMarkets.find((cont) => cont.asset === asset) + ?.contribution || 0) * assetOrLiabMultiplier + + const maintContribution = contribution * assetOrLiabMultiplier + + return ( + handleLegendClick(cont)} + onMouseEnter={() => handleLegendMouseEnter(cont)} + onMouseLeave={handleLegendMouseLeave} + > + + + + + ) + })} + +
{t('market')} +
+ + + {t('account:init-health-contribution')} + + +
+
+
+ + + {t('account:maint-health-contribution')} + + +
+
+
+ +

{asset}

+
+
+
+

+ +

+

+ {initContribution > 0 + ? initAssetWeight.toFixed(2) + : initContribution < 0 + ? initLiabWeight.toFixed(2) + : 0} + x +

+
+
+
+

+ +

+

+ {maintContribution > 0 + ? maintAssetWeight.toFixed(2) + : maintContribution < 0 + ? maintLiabWeight.toFixed(2) + : 0} + x +

+
+
+ ) : ( +
+ {maintMarkets + .sort((a, b) => b.contribution - a.contribution) + .map((cont) => { + const { asset, contribution, isAsset } = cont + const market = group.getSerum3MarketByName(asset) + const bank = group.banksMapByTokenIndex.get( + market.baseTokenIndex + )?.[0] + + let initAssetWeight = 0 + let initLiabWeight = 0 + let maintAssetWeight = 0 + let maintLiabWeight = 0 + + if (bank) { + initAssetWeight = bank + .scaledInitAssetWeight(bank.price) + .toNumber() + initLiabWeight = bank.scaledInitLiabWeight(bank.price).toNumber() + maintAssetWeight = bank.maintAssetWeight.toNumber() + maintLiabWeight = bank.maintLiabWeight.toNumber() + } + + const assetOrLiabMultiplier = isAsset ? 1 : -1 + + const initContribution = + (initMarkets.find((cont) => cont.asset === asset)?.contribution || + 0) * assetOrLiabMultiplier + + const maintContribution = contribution * assetOrLiabMultiplier + + return ( + + {({ open }) => ( + <> + +
+
+ +
+

{asset}

+
+
+ +
+
+ + +
+
+

+ + + {t('account:init-health-contribution')} + + +

+

+ +

+

+ {initContribution > 0 + ? initAssetWeight.toFixed(2) + : initContribution < 0 + ? initLiabWeight.toFixed(2) + : 0} + x +

+
+
+

+ + + {t('account:maint-health-contribution')} + + +

+

+ +

+

+ {maintContribution > 0 + ? maintAssetWeight.toFixed(2) + : maintContribution < 0 + ? maintLiabWeight.toFixed(2) + : 0} + x +

+
+
+
+
+ + )} +
+ ) + })} +
+ ) + ) : null +} + +export default MarketsHealthTable diff --git a/components/account/TokensHealthTable.tsx b/components/account/TokensHealthTable.tsx new file mode 100644 index 00000000..df4eca95 --- /dev/null +++ b/components/account/TokensHealthTable.tsx @@ -0,0 +1,406 @@ +import FormatNumericValue from '@components/shared/FormatNumericValue' +import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' +import TokenLogo from '@components/shared/TokenLogo' +import Tooltip from '@components/shared/Tooltip' +import { Disclosure, Transition } from '@headlessui/react' +import { ChevronDownIcon } from '@heroicons/react/20/solid' +import { useTranslation } from 'next-i18next' +import useMangoGroup from 'hooks/useMangoGroup' +import useMangoAccount from 'hooks/useMangoAccount' +import { useViewport } from 'hooks/useViewport' +import { breakpoints } from 'utils/theme' +import { MouseEventHandler } from 'react' +import { ContributionDetails, HealthContribution } from 'types' + +const TokensHealthTable = ({ + initTokens, + maintTokens, + handleLegendClick, + handleLegendMouseEnter, + handleLegendMouseLeave, +}: { + initTokens: HealthContribution[] + maintTokens: HealthContribution[] + handleLegendClick: (cont: HealthContribution) => void + handleLegendMouseEnter: (cont: HealthContribution) => void + handleLegendMouseLeave: MouseEventHandler +}) => { + const { t } = useTranslation(['common', 'account', 'trade']) + const { group } = useMangoGroup() + const { mangoAccount } = useMangoAccount() + const { width } = useViewport() + const isMobile = width ? width < breakpoints.sm : false + + return group && mangoAccount ? ( + !isMobile ? ( + + + + + + + + + + + {maintTokens + .sort((a, b) => b.contribution - a.contribution) + .map((cont) => { + const { + asset, + contribution, + contributionDetails, + isAsset, + hasPerp, + } = cont + const bank = group.banksMapByName.get(asset)?.[0] + + let initAssetWeight = 0 + let initLiabWeight = 0 + let maintAssetWeight = 0 + let maintLiabWeight = 0 + + let balance = 0 + + if (bank) { + initAssetWeight = bank + .scaledInitAssetWeight(bank.price) + .toNumber() + initLiabWeight = bank + .scaledInitLiabWeight(bank.price) + .toNumber() + maintAssetWeight = bank.maintAssetWeight.toNumber() + maintLiabWeight = bank.maintLiabWeight.toNumber() + + balance = mangoAccount.getTokenBalanceUi(bank) + } + + const assetOrLiabMultiplier = isAsset ? 1 : -1 + const initToken = initTokens.find((cont) => cont.asset === asset) + const initContribution = + (initToken?.contribution || 0) * assetOrLiabMultiplier + + const maintContribution = contribution * assetOrLiabMultiplier + + return ( + handleLegendClick(cont)} + onMouseEnter={() => handleLegendMouseEnter(cont)} + onMouseLeave={handleLegendMouseLeave} + > + + + + + + ) + })} + +
{t('token')}{t('trade:notional')} +
+ + + {t('account:init-health-contribution')} + + +
+
+
+ + + {t('account:maint-health-contribution')} + + +
+
+
+
+ +
+

{asset}

+
+
+ {bank ? ( +

+ {' '} + + + +

+ ) : ( + '–' + )} +
+
+ + } + > +

+ +

+
+

+ {initContribution > 0 + ? initAssetWeight.toFixed(2) + : initContribution < 0 + ? initLiabWeight.toFixed(2) + : 0} + x +

+
+
+
+ + } + > +

+ +

+
+

+ {maintContribution > 0 + ? maintAssetWeight.toFixed(2) + : maintContribution < 0 + ? maintLiabWeight.toFixed(2) + : 0} + x +

+
+
+ ) : ( +
+ {maintTokens + .sort((a, b) => b.contribution - a.contribution) + .map((cont) => { + const { + asset, + contribution, + contributionDetails, + isAsset, + hasPerp, + } = cont + const bank = group.banksMapByName.get(asset)?.[0] + + let initAssetWeight = 0 + let initLiabWeight = 0 + let maintAssetWeight = 0 + let maintLiabWeight = 0 + + let balance = 0 + + if (bank) { + initAssetWeight = bank + .scaledInitAssetWeight(bank.price) + .toNumber() + initLiabWeight = bank.scaledInitLiabWeight(bank.price).toNumber() + maintAssetWeight = bank.maintAssetWeight.toNumber() + maintLiabWeight = bank.maintLiabWeight.toNumber() + + balance = mangoAccount.getTokenBalanceUi(bank) + } + + const assetOrLiabMultiplier = isAsset ? 1 : -1 + + const initToken = initTokens.find((cont) => cont.asset === asset) + const initContribution = + (initToken?.contribution || 0) * assetOrLiabMultiplier + + const maintContribution = contribution * assetOrLiabMultiplier + + return ( + + {({ open }) => ( + <> + +
+
+
+ +
+
+

{asset}

+
+
+ +
+
+ + +
+
+

+ {t('trade:notional')} +

+

+ {bank ? ( + + {' '} + + + + + ) : ( + '–' + )} +

+
+
+

+ {t('account:init-health-contribution')} +

+ + } + > +

+ +

+
+

+ {initContribution > 0 + ? initAssetWeight.toFixed(2) + : initContribution < 0 + ? initLiabWeight.toFixed(2) + : 0} + x +

+
+
+

+ {t('account:maint-health-contribution')} +

+ + } + > +

+ +

+
+

+ {maintContribution > 0 + ? maintAssetWeight.toFixed(2) + : maintContribution < 0 + ? maintLiabWeight.toFixed(2) + : 0} + x +

+
+
+
+
+ + )} +
+ ) + })} +
+ ) + ) : null +} + +export default TokensHealthTable + +const UsdcTooltipContent = ({ + contributions, +}: { + contributions: ContributionDetails | undefined +}) => { + const { t } = useTranslation('common') + if (!contributions) return null + const { perpMarketContributions, spotUi } = contributions + return ( + <> +
+
+

{t('spot')}

+ + + +
+ {perpMarketContributions + .filter((cont) => Math.abs(cont.contributionUi) > 0.01) + .map((perp) => ( +
+

{perp.market}

+ + + +
+ ))} +
+ + ) +} diff --git a/components/account/VolumeChart.tsx b/components/account/VolumeChart.tsx index e13d6bc9..2e64710f 100644 --- a/components/account/VolumeChart.tsx +++ b/components/account/VolumeChart.tsx @@ -24,18 +24,15 @@ import { ArrowLeftIcon, NoSymbolIcon } from '@heroicons/react/20/solid' import { FadeInFadeOut } from '@components/shared/Transitions' import ContentBox from '@components/shared/ContentBox' import SheenLoader from '@components/shared/SheenLoader' +import useAccountHourlyVolumeStats from 'hooks/useAccountHourlyVolumeStats' +import useMangoAccount from 'hooks/useMangoAccount' import { DAILY_MILLISECONDS } from 'utils/constants' -const VolumeChart = ({ - chartData, - hideChart, - loading, -}: { - chartData: FormattedHourlyAccountVolumeData[] | undefined - hideChart: () => void - loading: boolean -}) => { +const VolumeChart = ({ hideChart }: { hideChart: () => void }) => { const { t } = useTranslation(['account', 'common', 'stats']) + const { mangoAccountAddress } = useMangoAccount() + const { hourlyVolumeData: chartData, loadingHourlyVolume: loading } = + useAccountHourlyVolumeStats() const [daysToShow, setDaysToShow] = useState('30') const { theme } = useTheme() @@ -160,8 +157,8 @@ const VolumeChart = ({ onChange={(v) => setDaysToShow(v)} /> - {loading ? ( - + {loading && mangoAccountAddress ? ( +
diff --git a/components/shared/BalancesTable.tsx b/components/shared/BalancesTable.tsx index df74c192..cfaf6e21 100644 --- a/components/shared/BalancesTable.tsx +++ b/components/shared/BalancesTable.tsx @@ -6,11 +6,7 @@ import { useViewport } from 'hooks/useViewport' import { useTranslation } from 'next-i18next' import { useRouter } from 'next/router' import { useCallback, useMemo } from 'react' -import { - floorToDecimal, - formatNumericValue, - getDecimalCount, -} from 'utils/numbers' +import { floorToDecimal, getDecimalCount } from 'utils/numbers' import { breakpoints } from 'utils/theme' import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm' import { LinkButton } from './Button' @@ -28,6 +24,9 @@ import { Disclosure, Transition } from '@headlessui/react' import TokenLogo from './TokenLogo' import useHealthContributions from 'hooks/useHealthContributions' import Tooltip from './Tooltip' +import { PublicKey } from '@solana/web3.js' +import { USDC_MINT } from 'utils/constants' +import { WRAPPED_SOL_MINT } from '@project-serum/serum/lib/token-instructions' const BalancesTable = () => { const { t } = useTranslation(['common', 'account', 'trade']) @@ -329,12 +328,20 @@ const Balance = ({ bank }: { bank: BankWithBalance }) => { const handleSwapFormBalanceClick = useCallback( (balance: number) => { const set = mangoStore.getState().set + const group = mangoStore.getState().group + const swap = mangoStore.getState().swap + const usdcBank = group?.getFirstBankByMint(new PublicKey(USDC_MINT)) + const solBank = group?.getFirstBankByMint(WRAPPED_SOL_MINT) if (balance >= 0) { set((s) => { s.swap.inputBank = tokenBank s.swap.amountIn = balance.toString() s.swap.amountOut = '' s.swap.swapMode = 'ExactIn' + if (tokenBank.name === swap.outputBank?.name) { + s.swap.outputBank = + swap.outputBank.name === 'USDC' ? solBank : usdcBank + } }) } else { set((s) => { @@ -342,6 +349,10 @@ const Balance = ({ bank }: { bank: BankWithBalance }) => { s.swap.amountIn = '' s.swap.amountOut = Math.abs(balance).toString() s.swap.swapMode = 'ExactOut' + if (tokenBank.name === swap.inputBank?.name) { + s.swap.inputBank = + swap.inputBank.name === 'USDC' ? solBank : usdcBank + } }) } }, @@ -382,7 +393,7 @@ const Balance = ({ bank }: { bank: BankWithBalance }) => { className="font-normal underline underline-offset-2 md:underline-offset-4 md:hover:no-underline" onClick={() => handleSwapFormBalanceClick( - Number(formatNumericValue(balance, tokenBank.mintDecimals)) + Number(floorToDecimal(balance, tokenBank.mintDecimals)) ) } > diff --git a/components/shared/TableElements.tsx b/components/shared/TableElements.tsx index 79cb7c9d..5f3895ad 100644 --- a/components/shared/TableElements.tsx +++ b/components/shared/TableElements.tsx @@ -1,5 +1,6 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import dayjs from 'dayjs' -import { ReactNode, forwardRef } from 'react' +import { MouseEventHandler, ReactNode, forwardRef } from 'react' export const Table = ({ children, @@ -43,15 +44,19 @@ interface TrBodyProps { children: ReactNode className?: string onClick?: () => void + onMouseEnter?: (x: any) => void + onMouseLeave?: MouseEventHandler } export const TrBody = forwardRef( (props, ref) => { - const { children, className, onClick } = props + const { children, className, onClick, onMouseEnter, onMouseLeave } = props return ( {children} diff --git a/hooks/useAccountHourlyVolumeStats.ts b/hooks/useAccountHourlyVolumeStats.ts index 1b56478a..0a062fdd 100644 --- a/hooks/useAccountHourlyVolumeStats.ts +++ b/hooks/useAccountHourlyVolumeStats.ts @@ -26,8 +26,6 @@ export default function useAccountHourlyVolumeStats() { return { hourlyVolumeData, - loadingHourlyVolumeData, - fetchingHourlyVolumeData, loadingHourlyVolume, } } diff --git a/public/locales/en/account.json b/public/locales/en/account.json index 9e25cabf..71df1eeb 100644 --- a/public/locales/en/account.json +++ b/public/locales/en/account.json @@ -6,15 +6,22 @@ "daily-volume": "24h Volume", "export": "Export {{dataType}}", "funding-chart": "Funding Chart", + "health-contributions": "Health Contributions", + "init-health-contribution": "Init Health Contribution", + "init-health-contributions": "Init Health Contributions", "liabilities": "Liabilities", "lifetime-volume": "Lifetime Trade Volume", + "maint-health-contribution": "Maint Health Contribution", + "maint-health-contributions": "Maint Health Contributions", "no-data": "No data to display", "no-pnl-history": "No PnL History", "pnl-chart": "PnL Chart", "pnl-history": "PnL History", "tooltip-collateral-value": "The amount of capital this token gives you to use for trades and loans.", "tooltip-free-collateral": "The amount of capital you have to use for trades and loans. When your free collateral reaches $0 you won't be able to trade, borrow or withdraw", + "tooltip-init-health": "The contribution an asset gives to your initial account health. Initial health affects your ability to open new positions and withdraw collateral from your account. The sum of these values is equal to your account's free collateral.", "tooltip-leverage": "Total assets value divided by account equity value", + "tooltip-maint-health": "The contribution an asset gives to your maintenance account health. If your maintenance health reaches 0 your account will be liquidated.", "tooltip-pnl": "The amount your account has profited or lost", "tooltip-total-collateral": "Total value of collateral for trading and borrowing (including unsettled PnL)", "tooltip-total-funding": "The sum of perp position funding earned and paid", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index bcc7a73c..ca004c03 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -101,6 +101,7 @@ "mango": "Mango", "mango-stats": "Mango Stats", "market": "Market", + "markets": "Markets", "max": "Max", "max-borrow": "Max Borrow", "more": "More", diff --git a/public/locales/es/account.json b/public/locales/es/account.json index 9e25cabf..71df1eeb 100644 --- a/public/locales/es/account.json +++ b/public/locales/es/account.json @@ -6,15 +6,22 @@ "daily-volume": "24h Volume", "export": "Export {{dataType}}", "funding-chart": "Funding Chart", + "health-contributions": "Health Contributions", + "init-health-contribution": "Init Health Contribution", + "init-health-contributions": "Init Health Contributions", "liabilities": "Liabilities", "lifetime-volume": "Lifetime Trade Volume", + "maint-health-contribution": "Maint Health Contribution", + "maint-health-contributions": "Maint Health Contributions", "no-data": "No data to display", "no-pnl-history": "No PnL History", "pnl-chart": "PnL Chart", "pnl-history": "PnL History", "tooltip-collateral-value": "The amount of capital this token gives you to use for trades and loans.", "tooltip-free-collateral": "The amount of capital you have to use for trades and loans. When your free collateral reaches $0 you won't be able to trade, borrow or withdraw", + "tooltip-init-health": "The contribution an asset gives to your initial account health. Initial health affects your ability to open new positions and withdraw collateral from your account. The sum of these values is equal to your account's free collateral.", "tooltip-leverage": "Total assets value divided by account equity value", + "tooltip-maint-health": "The contribution an asset gives to your maintenance account health. If your maintenance health reaches 0 your account will be liquidated.", "tooltip-pnl": "The amount your account has profited or lost", "tooltip-total-collateral": "Total value of collateral for trading and borrowing (including unsettled PnL)", "tooltip-total-funding": "The sum of perp position funding earned and paid", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index bcc7a73c..ca004c03 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -101,6 +101,7 @@ "mango": "Mango", "mango-stats": "Mango Stats", "market": "Market", + "markets": "Markets", "max": "Max", "max-borrow": "Max Borrow", "more": "More", diff --git a/public/locales/ru/account.json b/public/locales/ru/account.json index 9e25cabf..71df1eeb 100644 --- a/public/locales/ru/account.json +++ b/public/locales/ru/account.json @@ -6,15 +6,22 @@ "daily-volume": "24h Volume", "export": "Export {{dataType}}", "funding-chart": "Funding Chart", + "health-contributions": "Health Contributions", + "init-health-contribution": "Init Health Contribution", + "init-health-contributions": "Init Health Contributions", "liabilities": "Liabilities", "lifetime-volume": "Lifetime Trade Volume", + "maint-health-contribution": "Maint Health Contribution", + "maint-health-contributions": "Maint Health Contributions", "no-data": "No data to display", "no-pnl-history": "No PnL History", "pnl-chart": "PnL Chart", "pnl-history": "PnL History", "tooltip-collateral-value": "The amount of capital this token gives you to use for trades and loans.", "tooltip-free-collateral": "The amount of capital you have to use for trades and loans. When your free collateral reaches $0 you won't be able to trade, borrow or withdraw", + "tooltip-init-health": "The contribution an asset gives to your initial account health. Initial health affects your ability to open new positions and withdraw collateral from your account. The sum of these values is equal to your account's free collateral.", "tooltip-leverage": "Total assets value divided by account equity value", + "tooltip-maint-health": "The contribution an asset gives to your maintenance account health. If your maintenance health reaches 0 your account will be liquidated.", "tooltip-pnl": "The amount your account has profited or lost", "tooltip-total-collateral": "Total value of collateral for trading and borrowing (including unsettled PnL)", "tooltip-total-funding": "The sum of perp position funding earned and paid", diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index bcc7a73c..ca004c03 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -101,6 +101,7 @@ "mango": "Mango", "mango-stats": "Mango Stats", "market": "Market", + "markets": "Markets", "max": "Max", "max-borrow": "Max Borrow", "more": "More", diff --git a/public/locales/zh/account.json b/public/locales/zh/account.json index 9e25cabf..71df1eeb 100644 --- a/public/locales/zh/account.json +++ b/public/locales/zh/account.json @@ -6,15 +6,22 @@ "daily-volume": "24h Volume", "export": "Export {{dataType}}", "funding-chart": "Funding Chart", + "health-contributions": "Health Contributions", + "init-health-contribution": "Init Health Contribution", + "init-health-contributions": "Init Health Contributions", "liabilities": "Liabilities", "lifetime-volume": "Lifetime Trade Volume", + "maint-health-contribution": "Maint Health Contribution", + "maint-health-contributions": "Maint Health Contributions", "no-data": "No data to display", "no-pnl-history": "No PnL History", "pnl-chart": "PnL Chart", "pnl-history": "PnL History", "tooltip-collateral-value": "The amount of capital this token gives you to use for trades and loans.", "tooltip-free-collateral": "The amount of capital you have to use for trades and loans. When your free collateral reaches $0 you won't be able to trade, borrow or withdraw", + "tooltip-init-health": "The contribution an asset gives to your initial account health. Initial health affects your ability to open new positions and withdraw collateral from your account. The sum of these values is equal to your account's free collateral.", "tooltip-leverage": "Total assets value divided by account equity value", + "tooltip-maint-health": "The contribution an asset gives to your maintenance account health. If your maintenance health reaches 0 your account will be liquidated.", "tooltip-pnl": "The amount your account has profited or lost", "tooltip-total-collateral": "Total value of collateral for trading and borrowing (including unsettled PnL)", "tooltip-total-funding": "The sum of perp position funding earned and paid", diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index cd76d608..21d10db5 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -101,6 +101,7 @@ "mango": "Mango", "mango-stats": "Mango统计", "market": "市场", + "markets": "Markets", "max": "最多", "max-borrow": "最多借贷", "more": "更多", diff --git a/public/locales/zh_tw/account.json b/public/locales/zh_tw/account.json index 9e25cabf..71df1eeb 100644 --- a/public/locales/zh_tw/account.json +++ b/public/locales/zh_tw/account.json @@ -6,15 +6,22 @@ "daily-volume": "24h Volume", "export": "Export {{dataType}}", "funding-chart": "Funding Chart", + "health-contributions": "Health Contributions", + "init-health-contribution": "Init Health Contribution", + "init-health-contributions": "Init Health Contributions", "liabilities": "Liabilities", "lifetime-volume": "Lifetime Trade Volume", + "maint-health-contribution": "Maint Health Contribution", + "maint-health-contributions": "Maint Health Contributions", "no-data": "No data to display", "no-pnl-history": "No PnL History", "pnl-chart": "PnL Chart", "pnl-history": "PnL History", "tooltip-collateral-value": "The amount of capital this token gives you to use for trades and loans.", "tooltip-free-collateral": "The amount of capital you have to use for trades and loans. When your free collateral reaches $0 you won't be able to trade, borrow or withdraw", + "tooltip-init-health": "The contribution an asset gives to your initial account health. Initial health affects your ability to open new positions and withdraw collateral from your account. The sum of these values is equal to your account's free collateral.", "tooltip-leverage": "Total assets value divided by account equity value", + "tooltip-maint-health": "The contribution an asset gives to your maintenance account health. If your maintenance health reaches 0 your account will be liquidated.", "tooltip-pnl": "The amount your account has profited or lost", "tooltip-total-collateral": "Total value of collateral for trading and borrowing (including unsettled PnL)", "tooltip-total-funding": "The sum of perp position funding earned and paid", diff --git a/public/locales/zh_tw/common.json b/public/locales/zh_tw/common.json index 2d6b7053..8bb7df73 100644 --- a/public/locales/zh_tw/common.json +++ b/public/locales/zh_tw/common.json @@ -101,6 +101,7 @@ "mango": "Mango", "mango-stats": "Mango統計", "market": "市場", + "markets": "Markets", "max": "最多", "max-borrow": "最多借貸", "more": "更多", diff --git a/types/index.ts b/types/index.ts index 481a2864..dc18512c 100644 --- a/types/index.ts +++ b/types/index.ts @@ -413,3 +413,21 @@ export type TickerData = { target_volume: string ticker_id: string } + +export interface HealthContribution { + asset: string + contribution: number + contributionDetails?: ContributionDetails + hasPerp?: boolean + isAsset: boolean +} + +export interface PerpMarketContribution { + market: string + contributionUi: number +} + +export interface ContributionDetails { + perpMarketContributions: PerpMarketContribution[] + spotUi: number +}