Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add realized & unrealized P&L to portfolio/prime pages #2388

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,24 @@ export function CardPortfolioValue({
<Shelf gap={1} alignContent="center" height="48px">
<Box width="3px" backgroundColor="#1253FF" height="48px" />
<Shelf gap={4}>
<Stack gap="4px">
<Text {...headingProps}>Current portfolio value</Text>
<TextWithPlaceholder {...balanceProps} isLoading={!currentPortfolioValue}>
{formatBalance(currentPortfolioValue || 0, config.baseCurrency)}
</TextWithPlaceholder>
</Stack>
{/* <Stack gap="4px">
<Text {...headingProps}>Profit</Text>
<TextWithPlaceholder {...balanceProps} isLoading={!portfolioValue} color="#519B10">
+ {formatBalance(Dec(portfolioValue || 0), config.baseCurrency)}
</TextWithPlaceholder>
</Stack> */}
<Shelf gap="4px" display="flex">
<Box>
<Text {...headingProps}>Current portfolio value</Text>
<TextWithPlaceholder {...balanceProps} isLoading={!currentPortfolioValue}>
{formatBalance(currentPortfolioValue || 0, config.baseCurrency)}
</TextWithPlaceholder>
</Box>
<Box marginLeft={40}>
<Text {...headingProps}>Total P&L</Text>
<TextWithPlaceholder
style={{ color: colors.statusOk }}
isLoading={!currentPortfolioValue}
{...balanceProps}
>
{formatBalance(currentPortfolioValue || 0, config.baseCurrency)}
</TextWithPlaceholder>
</Box>
</Shelf>
</Shelf>
</Shelf>
</Stack>
Expand Down
28 changes: 27 additions & 1 deletion centrifuge-app/src/components/Portfolio/Holdings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Token, evmToSubstrateAddress } from '@centrifuge/centrifuge-js'
import { CurrencyBalance, Token, evmToSubstrateAddress } from '@centrifuge/centrifuge-js'
import { formatBalance, useBalances, useCentrifuge, useWallet } from '@centrifuge/centrifuge-react'
import { Box, Grid, IconDownload, IconMinus, IconPlus, IconSend, Shelf, Text, Thumbnail } from '@centrifuge/fabric'
import Decimal from 'decimal.js-light'
Expand Down Expand Up @@ -36,6 +36,8 @@ type Row = {
showActions?: boolean
address?: string
connectedNetwork?: string | null
realizedProfit?: CurrencyBalance | undefined
unrealizedProfit?: CurrencyBalance | undefined
}

const columns: Column[] = [
Expand Down Expand Up @@ -81,6 +83,30 @@ const columns: Column[] = [
sortKey: 'marketValue',
align: 'left',
},
{
header: <Tooltips type="realizedPL" label="Realized P&L" />,
cell: ({ currency, unrealizedProfit }: Row) => {
return (
<Text textOverflow="ellipsis" variant="body3">
{unrealizedProfit ? formatBalanceAbbreviated(unrealizedProfit, currency?.symbol, 2) : '-'}
</Text>
)
},
sortKey: 'realizedProfit',
align: 'left',
},
{
header: <Tooltips type="unrealizedPL" label="Unrealized P&L" />,
cell: ({ currency, unrealizedProfit }: Row) => {
return (
<Text textOverflow="ellipsis" variant="body3">
{unrealizedProfit ? formatBalanceAbbreviated(unrealizedProfit, currency?.symbol, 2) : '-'}
</Text>
)
},
sortKey: 'unrealizedProfit',
align: 'left',
},
{
align: 'left',
header: '', // invest redeem buttons
Expand Down
31 changes: 29 additions & 2 deletions centrifuge-app/src/components/Portfolio/usePortfolio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export function usePortfolio(substrateAddress?: string) {
sumClaimedTrancheTokens
trancheId
poolId
unrealizedProfit
tranche {
tokenPrice
}
Expand Down Expand Up @@ -176,6 +177,12 @@ export function usePortfolio(substrateAddress?: string) {
trancheId
}
}
investorTransactions {
nodes {
realizedProfitFifo
trancheId
}
}
}
}`,
{
Expand All @@ -187,7 +194,12 @@ export function usePortfolio(substrateAddress?: string) {
)

const data = useMemo(() => {
const trancheBalances: Record<string, { totalTrancheTokens: TokenBalance; tokenPrice: Price }> = {}
const trancheBalances: Record<
string,
{ totalTrancheTokens: TokenBalance; tokenPrice: Price; unrealizedProfit: CurrencyBalance | undefined }
> = {}

console.log('sub', subData)

subData?.account?.investorPositions.nodes.forEach((position: any) => {
const pool = pools?.find((p) => p.id === position.poolId)
Expand All @@ -196,12 +208,24 @@ export function usePortfolio(substrateAddress?: string) {
const tokenPrice = pool?.tranches.find((t) => trancheId === t.id)?.tokenPrice ?? Price.fromFloat(1)
const balance = new TokenBalance(position.holdingQuantity, decimals)
const existing = trancheBalances[trancheId]

const unrealizedProfit = subData?.account?.trancheBalances?.nodes.find(
(tb: any) => tb.trancheId === position.trancheId
)

if (existing) {
existing.totalTrancheTokens.iadd(balance)
} else {
trancheBalances[trancheId] = { totalTrancheTokens: balance, tokenPrice }
trancheBalances[trancheId] = {
totalTrancheTokens: balance,
tokenPrice,
unrealizedProfit: unrealizedProfit
? new CurrencyBalance(unrealizedProfit.unrealizedProfit, decimals)
: undefined,
}
}
})

// return (
// (subData?.account as undefined | {}) &&
// (Object.fromEntries(
Expand Down Expand Up @@ -265,6 +289,7 @@ export function usePortfolio(substrateAddress?: string) {
// }
// >)
// )

return trancheBalances
}, [subData, pools])

Expand All @@ -278,6 +303,7 @@ type PortfolioToken = {
trancheId: string
poolId: string
currency: Token['currency']
unrealizedProfit: CurrencyBalance | undefined
}

export function usePortfolioTokens(address?: string) {
Expand Down Expand Up @@ -310,6 +336,7 @@ export function usePortfolioTokens(address?: string) {
trancheId: trancheId,
poolId: trancheTokenPrices[trancheId].poolId,
currency: trancheTokenPrices[trancheId].currency,
unrealizedProfit: tranche.unrealizedProfit,
}
}, [] as PortfolioToken[])
}
Expand Down
8 changes: 8 additions & 0 deletions centrifuge-app/src/components/Tooltips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ export const tooltipText = {
label: 'Linear accrual',
body: 'If enabled, the price of the asset is updated continuously based on linear accrual from the latest known market price to the value at maturity.',
},
unrealizedPL: {
label: 'Unrealized P&L',
body: 'Unrealized profit / loss from current holdings (based on FiFo-weighted sales at the current token price)',
},
realizedPL: {
label: 'Realized P&L',
body: 'Realized profit / loss from executed redemptions',
},
}

export type TooltipsProps = {
Expand Down
Loading