Skip to content

Commit

Permalink
Merge pull request #82 from berachain/fix/berps-total-pnl
Browse files Browse the repository at this point in the history
fix(perp): calculate total unrealized pnl correctly
  • Loading branch information
bearpong authored Sep 19, 2024
2 parents 9333fe5 + d058d1b commit 2137a3b
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
IClosedTrade,
ILimitOrder,
IMarketOrder,
IOpenTradeCalculated,
IOpenTrade,
} from "~/types/order-history";
import { getHistoryListItems } from "./history";
import { getLimitListItems } from "./orders";
Expand All @@ -18,7 +18,7 @@ export const getAssetCardList = ({
markets,
closedTradesItems,
}: {
openPositionsItems: IOpenTradeCalculated[];
openPositionsItems: IOpenTrade[];
openOrderItems: ILimitOrder[];
closedTradesItems: IClosedTrade[];
markets: IMarket[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { PositionLiquidationPrice } from "~/app/components/table-columns/positio
import { MarketTradePNL } from "~/app/components/market-trade-pnl";
import { UpdatePositionModal } from "~/app/components/update-position-modal";
import { type IMarket } from "~/types/market";
import type { ICards, IOpenTradeCalculated } from "~/types/order-history";
import type { ICards, IOpenTrade } from "~/types/order-history";

export const getMarketListItems = (
marketOrderItems: IOpenTradeCalculated[],
marketOrderItems: IOpenTrade[],
markets: IMarket[],
): ICards[] => {
const cards = marketOrderItems.map((item) => {
Expand Down
14 changes: 7 additions & 7 deletions apps/perp/src/app/berpetuals/components/order-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
type ResolutionString,
} from "~/types/charting-library";
import { type IMarket } from "~/types/market";
import { ILimitOrder, IOpenTradeCalculated } from "~/types/order-history";
import { ILimitOrder, IOpenTrade } from "~/types/order-history";
import { type TableStateProps } from "~/types/table";
import { ClosePositionModal } from "../../components/close-position-modal";
import type { ChartProps } from "./TVChartContainer";
Expand Down Expand Up @@ -67,16 +67,16 @@ export function OrderChart({
);

const openPositions = useMemo(() => {
if (!openPositionData) {
return [];
}

const positions = generateMarketOrders(openPositionData, markets);
return positions.map((position, index) => {
return {
...position,
borrowing_fee:
openPositionsLiqFeesData?.at(1)?.at(index)?.toString() ?? "0",
liq_price:
openPositionsLiqFeesData?.at(0)?.at(index)?.toString() ?? "0",
};
}) as IOpenTradeCalculated[];
}) as IOpenTrade[];
}, [openPositionData, markets, openPositionsLiqFeesData]);

const openOrders = useMemo(() => {
Expand All @@ -85,7 +85,7 @@ export function OrderChart({

const [positionOpenState, setPositionOpenState] = useState(false);
const [orderOpenState, setOrderOpenState] = useState(false);
const [position, setPosition] = useState<IOpenTradeCalculated>();
const [position, setPosition] = useState<IOpenTrade>();
const [order, setOrder] = useState<ILimitOrder>();

const defaultWidgetProps: Partial<ChartingLibraryWidgetOptions> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export function OrderHistoryHeader({ markets }: { markets: IMarket[] }) {
} = usePollOpenPositions(tableState);

const openPositions = useMemo(
() => generateMarketOrders(openPositionsData, markets) as IOpenTrade[],
() =>
openPositionsData
? (generateMarketOrders(openPositionsData, markets) as IOpenTrade[])
: [],
[openPositionsData, markets],
);

Expand Down
44 changes: 15 additions & 29 deletions apps/perp/src/app/berpetuals/components/order-history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import type {
IClosedTrade,
ILimitOrder,
IMarketOrder,
IOpenTradeCalculated,
IOpenTrade,
} from "~/types/order-history";
import { TotalAmount } from "../../components/total-amount";
import { getAssetCardList } from "./asset-cards/getAssetCards";
Expand All @@ -41,12 +41,8 @@ export function OrderHistory({
markets: IMarket[];
size: "sm" | "md" | "lg";
}) {
const [updateOpen, setUpdateOpen] = useState<boolean | IOpenTradeCalculated>(
false,
);
const [deleteOpen, setDeleteOpen] = useState<boolean | IOpenTradeCalculated>(
false,
);
const [updateOpen, setUpdateOpen] = useState<boolean | IOpenTrade>(false);
const [deleteOpen, setDeleteOpen] = useState<boolean | IOpenTrade>(false);

const { tableState, setTableState } = useContext(TableContext);
const { isConnected } = useBeraJs();
Expand Down Expand Up @@ -98,7 +94,10 @@ export function OrderHistory({
);

const openMarketPositions = useMemo(
() => generateMarketOrders(openPositionData, markets) ?? [],
() =>
openPositionData
? (generateMarketOrders(openPositionData, markets) as IOpenTrade[])
: [],
[markets, openPositionData],
);
const openMarketOrders = useMemo(
Expand All @@ -115,11 +114,11 @@ export function OrderHistory({
);

// edge case for selection when new orders are opened or closed
const prevPositionLength = usePrevious(openPositionData?.length ?? 0);
const prevPositionLength = usePrevious(openPositionData?.result?.length ?? 0);
useEffect(() => {
if (
tableState.tabType === "positions" &&
(openPositionData?.length ?? 0) !== prevPositionLength
(openPositionData?.result?.length ?? 0) !== prevPositionLength
) {
setTableState((prev) => ({ ...prev, selection: {} }));
}
Expand All @@ -136,14 +135,9 @@ export function OrderHistory({

// props generation
const tableProps = useMemo(() => {
let data: (
| IOpenTradeCalculated
| ILimitOrder
| IMarketOrder
| IClosedTrade
)[] = [];
let data: (IOpenTrade | ILimitOrder | IMarketOrder | IClosedTrade)[] = [];
let columns:
| ColumnDef<IOpenTradeCalculated>[]
| ColumnDef<IOpenTrade>[]
| ColumnDef<ILimitOrder>[]
| ColumnDef<IMarketOrder>[]
| ColumnDef<IClosedTrade>[] = [];
Expand All @@ -154,15 +148,7 @@ export function OrderHistory({

switch (tableState.tabType) {
case "positions":
data = openMarketPositions.map((position, index) => {
return {
...position,
borrowing_fee:
openPositionsLiqFeesData?.at(1)?.at(index)?.toString() ?? "0",
liq_price:
openPositionsLiqFeesData?.at(0)?.at(index)?.toString() ?? "0",
};
});
data = openMarketPositions as IOpenTrade[];
columns = markets
? generatePositionColumns(markets, setUpdateOpen, setDeleteOpen)
: [];
Expand Down Expand Up @@ -246,7 +232,7 @@ export function OrderHistory({

const assetCardItems = useMemo(() => {
return getAssetCardList({
openPositionsItems: openMarketPositions as IOpenTradeCalculated[],
openPositionsItems: openMarketPositions as IOpenTrade[],
openOrderItems: openMarketOrders as ILimitOrder[],
marketOrdersItems: marketOrders as IMarketOrder[],
closedTradesItems: closedMarketTrades as IClosedTrade[],
Expand All @@ -269,12 +255,12 @@ export function OrderHistory({
tabType={tableState.tabType ?? "positions"}
/>
<UpdatePositionModal
openPosition={updateOpen as IOpenTradeCalculated}
openPosition={updateOpen as IOpenTrade}
controlledOpen={!!updateOpen}
onOpenChange={setUpdateOpen}
/>
<ClosePositionModal
openPosition={deleteOpen as IOpenTradeCalculated}
openPosition={deleteOpen as IOpenTrade}
controlledOpen={!!deleteOpen}
onOpenChange={setDeleteOpen}
/>
Expand Down
4 changes: 2 additions & 2 deletions apps/perp/src/app/components/close-position-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { TableContext } from "~/context/table-context";
import { usePollMarketOrders } from "~/hooks/usePollMarketOrders";
import { usePollOpenPositions } from "~/hooks/usePollOpenPositions";
import { usePollPrices } from "~/hooks/usePollPrices";
import type { IOpenTradeCalculated } from "~/types/order-history";
import type { IOpenTrade } from "~/types/order-history";
import { MarketTradePNL } from "./market-trade-pnl";

export function ClosePositionModal({
Expand All @@ -33,7 +33,7 @@ export function ClosePositionModal({
}: {
trigger?: any;
disabled?: boolean;
openPosition: IOpenTradeCalculated;
openPosition: IOpenTrade;
className?: string;
controlledOpen?: boolean;
onOpenChange?: (state: boolean) => void;
Expand Down
12 changes: 6 additions & 6 deletions apps/perp/src/app/components/table-columns/positions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { PositionTitle } from "~/app/components/position-title";
import { useCalculateLiqPrice } from "~/hooks/useCalculateLiqPrice";
import { usePollPrices } from "~/hooks/usePollPrices";
import type { IMarket } from "~/types/market";
import type { IOpenTradeCalculated } from "~/types/order-history";
import type { IOpenTrade } from "~/types/order-history";
import { MarketTradePNL } from "../market-trade-pnl";

const MarkPrice = ({ position }: { position: IOpenTradeCalculated }) => {
const MarkPrice = ({ position }: { position: IOpenTrade }) => {
const { marketPrices } = usePollPrices();
const price = marketPrices[position?.market?.pair_index ?? ""] ?? "0";

Expand All @@ -33,7 +33,7 @@ export const PositionLiquidationPrice = ({
position,
className,
}: {
position: IOpenTradeCalculated;
position: IOpenTrade;
className?: string;
}) => {
const formattedPrice = formatFromBaseUnit(
Expand Down Expand Up @@ -62,10 +62,10 @@ export const PositionLiquidationPrice = ({

export const generatePositionColumns = (
markets: IMarket[],
setUpdateOpen: (state: boolean | IOpenTradeCalculated) => void,
setDeleteOpen: (state: boolean | IOpenTradeCalculated) => void,
setUpdateOpen: (state: boolean | IOpenTrade) => void,
setDeleteOpen: (state: boolean | IOpenTrade) => void,
) => {
const positionsColumns: ColumnDef<IOpenTradeCalculated>[] = [
const positionsColumns: ColumnDef<IOpenTrade>[] = [
{
header: "Market / Action",
cell: ({ row }) => (
Expand Down
9 changes: 6 additions & 3 deletions apps/perp/src/app/components/total-amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@ export function TotalAmount({
const { data: openPositions } = usePollOpenPositions(tableState);
const { marketPrices } = usePollPrices();
const unrealizedPnl = useMemo(() => {
if (!openPositions) {
return BigNumber(totalUnrealizedPnl);
}
const pnl = calculateUnrealizedPnl(openPositions, marketPrices);
return pnl ? BigNumber(pnl) : formatFromBaseUnit(totalUnrealizedPnl, 18);
return BigNumber(pnl ?? totalUnrealizedPnl);
}, [openPositions, marketPrices, totalUnrealizedPnl]);
const { useAccountTradingSummary } = usePollAccountTradingSummary();
const { data } = useAccountTradingSummary();
const realizedPnl = data?.pnl ?? "0";
const { data: accountTradingSummary } = useAccountTradingSummary();
const realizedPnl = accountTradingSummary?.pnl ?? "0";
const totalPnlBN = unrealizedPnl.plus(realizedPnl);

const totalRelativePnL = () => {
Expand Down
4 changes: 2 additions & 2 deletions apps/perp/src/app/components/update-position-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { usePriceData, useVaa } from "~/context/price-context";
import { TableContext } from "~/context/table-context";
import { usePollOpenPositions } from "~/hooks/usePollOpenPositions";
import { usePollPrices } from "~/hooks/usePollPrices";
import type { IOpenTradeCalculated } from "~/types/order-history";
import type { IOpenTrade } from "~/types/order-history";
import { TPSL } from "../berpetuals/components/tpsl";
import { MarketTradePNL } from "./market-trade-pnl";

Expand All @@ -32,7 +32,7 @@ export function UpdatePositionModal({
}: {
trigger?: any;
disabled?: boolean;
openPosition: IOpenTradeCalculated;
openPosition: IOpenTrade;
className?: string;
controlledOpen?: boolean;
onOpenChange?: (state: boolean) => void;
Expand Down
5 changes: 3 additions & 2 deletions apps/perp/src/app/portfolio/components/stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@ export default function Stats({ markets }: { markets: IMarket[] }) {
onValueChange={(value) => setTabType(value as "Volume" | "PnL")}
className="h-full w-full sm:w-fit"
>
<TabsList className="h-full w-full border border-border sm:w-fit">
<TabsList className="h-full w-full border border-border sm:w-fit px-1">
{["Volume", "PnL"].map((status) => (
<TabsTrigger
value={status}
key={status}
className="variant w-full flex-1 capitalize data-[state=active]:bg-secondary data-[state=active]:text-foreground sm:w-fit"
variant="compact"
className="variant w-full flex-1 capitalize data-[state=active]:bg-secondary data-[state=active]:text-foreground sm:w-fit"
onClick={() => setTabType(status as "Volume" | "PnL")}
>
{status}{" "}
Expand Down
31 changes: 10 additions & 21 deletions apps/perp/src/app/portfolio/components/user-assets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import React, {
useMemo,
useState,
} from "react";
import { usePollPositionsLiqFeePrices, usePrevious } from "@bera/berajs";
import type { OpenTrade } from "@bera/proto/src";
import { usePrevious } from "@bera/berajs";
import { SimpleTable, useAsyncTable } from "@bera/shared-ui";
import {
TableState,
Expand All @@ -27,7 +26,7 @@ import { TableContext } from "~/context/table-context";
import { usePollMarketOrders } from "~/hooks/usePollMarketOrders";
import { usePollOpenPositions } from "~/hooks/usePollOpenPositions";
import type { IMarket } from "~/types/market";
import type { IOpenTrade, IOpenTradeCalculated } from "~/types/order-history";
import type { IOpenTrade } from "~/types/order-history";
import { FilterableTableState } from "~/types/table";
import { TotalAmount } from "../../components/total-amount";

Expand All @@ -40,30 +39,20 @@ export default function UserOpenPositions({ markets }: { markets: IMarket[] }) {
isValidating,
refresh: refetchPositions,
} = usePollOpenPositions(tableState);
const { data: openPositionsLiqFeesData } = usePollPositionsLiqFeePrices(
data?.result
? data.result.map((position: OpenTrade) => Number(position.index))
: [],
);

const { refresh: refetchMarketHistory } = usePollMarketOrders(tableState);

let openPositions = generateMarketOrders(data, markets) as IOpenTrade[];
let openPositions = data
? (generateMarketOrders(data, markets) as IOpenTrade[])
: [];
openPositions = openPositions.map((position, index) => {
return {
...position,
borrowing_fee:
openPositionsLiqFeesData?.at(1)?.at(index)?.toString() ?? "0",
liq_price: openPositionsLiqFeesData?.at(0)?.at(index)?.toString() ?? "0",
};
});

const [updateOpen, setUpdateOpen] = useState<boolean | IOpenTradeCalculated>(
false,
);
const [deleteOpen, setDeleteOpen] = useState<boolean | IOpenTradeCalculated>(
false,
);
const [updateOpen, setUpdateOpen] = useState<boolean | IOpenTrade>(false);
const [deleteOpen, setDeleteOpen] = useState<boolean | IOpenTrade>(false);

const prevPositionLength = usePrevious(openPositions?.length ?? 0);
useEffect(() => {
Expand Down Expand Up @@ -140,7 +129,7 @@ export default function UserOpenPositions({ markets }: { markets: IMarket[] }) {
);

const table = useAsyncTable({
data: (openPositions as IOpenTradeCalculated[]) ?? [],
data: (openPositions as IOpenTrade[]) ?? [],
columns: markets
? generatePositionColumns(markets, setUpdateOpen, setDeleteOpen)
: [],
Expand Down Expand Up @@ -202,12 +191,12 @@ export default function UserOpenPositions({ markets }: { markets: IMarket[] }) {
</div>
</div>
<UpdatePositionModal
openPosition={updateOpen as IOpenTradeCalculated}
openPosition={updateOpen as IOpenTrade}
controlledOpen={!!updateOpen}
onOpenChange={setUpdateOpen}
/>
<ClosePositionModal
openPosition={deleteOpen as IOpenTradeCalculated}
openPosition={deleteOpen as IOpenTrade}
controlledOpen={!!deleteOpen}
onOpenChange={setDeleteOpen}
/>
Expand Down
Loading

0 comments on commit 2137a3b

Please sign in to comment.