Skip to content

Conversation

@gkoch78
Copy link
Contributor

@gkoch78 gkoch78 commented Feb 21, 2025

Implementation of PNL into Portfolio service

@gkoch78 gkoch78 changed the title Feature portfolio positions Feature portfolio PNL Feb 21, 2025
def __init__(self, bought: PortfolioSwap, selling_price: Decimal, asset_sold: Decimal, is_realized: bool) -> None:
self._bought = bought
self._selling_price = selling_price
self._assert_sold = asset_sold
Copy link
Collaborator

@dvdmllr dvdmllr Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling mistake in asset ("assert")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same applies to other parts of code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, that is one I'm making constanstly

return sum([pnl for asset, pnl in self.pnl_per_asset(mode).items()], Decimal(0))


class PortfolioPNLDetail:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does a PortfolioPNLDetail represent? My understanding reading through the code is that these could be individual trading lots (single purchases or sells for an asset)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • PortfolioSwap represents either a buy or a sell transaction, depending on which token is the base token.
  • PortfolioPNLDetail represents either a partial lot of a full lot. It also represent a line item in the PNL report.
  • PortfolioRealizedPNLDetail: this represent either a partial of full lot that has a matching sell transaction. The sold asset represent the amount of the position that was sold. sold_asset is computed in a way so that there is only one buying and selling price.
  • PortoflioUnrealizedPNLDetail: a full or partial lot that has no matching sell transaction

def add_details(self, asset: str, details: Iterable[PortfolioPNLDetail]) -> None:
self._details_per_asset[asset] = list(details)

def pnl_per_asset(self, mode: PnlMode = PnlMode.TOTAL) -> Dict[str, Decimal]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we know the PNL without setting a base currency we check against?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the computation of the PNL is call, the base currency/token is passed as a parameter. That base token is passed to the PNL report.
This function here is a helper function on the report itself, so the base token is already known



class PortfolioRealizedPNLDetail(PortfolioPNLDetail):
def __init__(self, bought: PortfolioSwap, sold: PortfolioSwap, asset_sold: Decimal) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the PortfolioSwap sold not already include the assets sold?

Copy link
Contributor Author

@gkoch78 gkoch78 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asset_sold, represents the amount of asset being sold for that line item. Maybe a better name would be amount_sold.
It is different than the PortfolioSwap sold because the sell transaction may impact multiple positions.

@gkoch78 gkoch78 marked this pull request as ready for review February 25, 2025 20:10
return self._wallet.chain

@classmethod
def compute_pnl(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to PortfolioPNL

Copy link
Contributor

@aflament aflament left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with comments

gkoch78 and others added 3 commits February 26, 2025 09:21
Co-authored-by: Arnaud Flament <17051690+aflament@users.noreply.github.com>
@gkoch78 gkoch78 merged commit 310b126 into main Feb 26, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants