From 8f0d5429d108d4a1f9f737a319970e87798f97b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Pr=C3=A9vost?= <998369+prevostc@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:32:05 +0200 Subject: [PATCH] Update Pnl --- src/utils/pnl.ts | 11 ++++++----- tests/utils/pnl.test.ts | 37 ++++++++++--------------------------- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/utils/pnl.ts b/src/utils/pnl.ts index 73c5633..cd76a1b 100644 --- a/src/utils/pnl.ts +++ b/src/utils/pnl.ts @@ -3,7 +3,6 @@ import { ZERO_BD, bigDecMin } from "./decimal" class PnLStateEntry { constructor( - public boughtShares: BigDecimal, public remainingShares: BigDecimal, public entryPrice: BigDecimal, ) {} @@ -20,7 +19,6 @@ export class PnLState { res.push(this.realizedPnl) for (let idx = 0; idx < this.sharesFifo.length; idx++) { let entry = this.sharesFifo[idx] - res.push(entry.boughtShares) res.push(entry.remainingShares) res.push(entry.entryPrice) } @@ -32,10 +30,9 @@ export class PnLState { let realizedPnl = data.shift() as BigDecimal let sharesFifo = new Array() while (data.length > 0) { - let boughtShares = data.shift() as BigDecimal let remainingShares = data.shift() as BigDecimal let entryPrice = data.shift() as BigDecimal - sharesFifo.push(new PnLStateEntry(boughtShares, remainingShares, entryPrice)) + sharesFifo.push(new PnLStateEntry(remainingShares, entryPrice)) } return new PnLState(realizedPnl, sharesFifo) @@ -58,8 +55,9 @@ export class PnLCalc { return } + // bought shares if (trxShares.gt(ZERO_BD)) { - this.state.sharesFifo.push(new PnLStateEntry(trxShares, trxShares, trxPrice)) + this.state.sharesFifo.push(new PnLStateEntry(trxShares, trxPrice)) return } @@ -83,6 +81,9 @@ export class PnLCalc { } this.state.realizedPnl = this.state.realizedPnl.plus(trxPnl) + + // evict empty entries + this.state.sharesFifo = this.state.sharesFifo.filter((entry) => !entry.remainingShares.equals(ZERO_BD)) return } diff --git a/tests/utils/pnl.test.ts b/tests/utils/pnl.test.ts index 76ea2f1..9af23c6 100644 --- a/tests/utils/pnl.test.ts +++ b/tests/utils/pnl.test.ts @@ -12,59 +12,42 @@ describe("PnLState", () => { test("Can serialize and deserialize pnl state with one entry", () => { const realizedPnl = BigDecimal.fromString("100") - const boughtShares = BigDecimal.fromString("10") const remainingShares = BigDecimal.fromString("5") const entryPrice = BigDecimal.fromString("20") - const state = PnLState.deserialize([realizedPnl, boughtShares, remainingShares, entryPrice]) + const state = PnLState.deserialize([realizedPnl, remainingShares, entryPrice]) assert.assertTrue(state.realizedPnl.equals(realizedPnl)) assert.assertTrue(state.sharesFifo.length === 1) - assert.assertTrue(state.sharesFifo[0].boughtShares.equals(boughtShares)) assert.assertTrue(state.sharesFifo[0].remainingShares.equals(remainingShares)) assert.assertTrue(state.sharesFifo[0].entryPrice.equals(entryPrice)) const serialized = state.serialize() - assert.assertTrue(serialized.length === 4) + assert.assertTrue(serialized.length === 3) assert.assertTrue(serialized[0].equals(realizedPnl)) - assert.assertTrue(serialized[1].equals(boughtShares)) - assert.assertTrue(serialized[2].equals(remainingShares)) - assert.assertTrue(serialized[3].equals(entryPrice)) + assert.assertTrue(serialized[1].equals(remainingShares)) + assert.assertTrue(serialized[2].equals(entryPrice)) }) test("Can serialize and deserialize pnl state with multiple entries", () => { const realizedPnl = BigDecimal.fromString("100") - const boughtShares1 = BigDecimal.fromString("10") const remainingShares1 = BigDecimal.fromString("5") const entryPrice1 = BigDecimal.fromString("20") - const boughtShares2 = BigDecimal.fromString("20") const remainingShares2 = BigDecimal.fromString("10") const entryPrice2 = BigDecimal.fromString("30") - const state = PnLState.deserialize([ - realizedPnl, - boughtShares1, - remainingShares1, - entryPrice1, - boughtShares2, - remainingShares2, - entryPrice2, - ]) + const state = PnLState.deserialize([realizedPnl, remainingShares1, entryPrice1, remainingShares2, entryPrice2]) assert.assertTrue(state.realizedPnl.equals(realizedPnl)) assert.assertTrue(state.sharesFifo.length === 2) - assert.assertTrue(state.sharesFifo[0].boughtShares.equals(boughtShares1)) assert.assertTrue(state.sharesFifo[0].remainingShares.equals(remainingShares1)) assert.assertTrue(state.sharesFifo[0].entryPrice.equals(entryPrice1)) - assert.assertTrue(state.sharesFifo[1].boughtShares.equals(boughtShares2)) assert.assertTrue(state.sharesFifo[1].remainingShares.equals(remainingShares2)) assert.assertTrue(state.sharesFifo[1].entryPrice.equals(entryPrice2)) const serialized = state.serialize() - assert.assertTrue(serialized.length === 7) + assert.assertTrue(serialized.length === 5) assert.assertTrue(serialized[0].equals(realizedPnl)) - assert.assertTrue(serialized[1].equals(boughtShares1)) - assert.assertTrue(serialized[2].equals(remainingShares1)) - assert.assertTrue(serialized[3].equals(entryPrice1)) - assert.assertTrue(serialized[4].equals(boughtShares2)) - assert.assertTrue(serialized[5].equals(remainingShares2)) - assert.assertTrue(serialized[6].equals(entryPrice2)) + assert.assertTrue(serialized[1].equals(remainingShares1)) + assert.assertTrue(serialized[2].equals(entryPrice1)) + assert.assertTrue(serialized[3].equals(remainingShares2)) + assert.assertTrue(serialized[4].equals(entryPrice2)) }) })