diff --git a/src/subdomains/core/custody/services/custody.service.ts b/src/subdomains/core/custody/services/custody.service.ts index 7feda31aad..e375233e68 100644 --- a/src/subdomains/core/custody/services/custody.service.ts +++ b/src/subdomains/core/custody/services/custody.service.ts @@ -151,13 +151,13 @@ export class CustodyService { const custodyUserIds = account.users.filter((u) => u.role === UserRole.CUSTODY).map((u) => u.id); const custodyOrders = await this.custodyOrderRepo.find({ where: { user: { id: In(custodyUserIds) }, status: CustodyOrderStatus.COMPLETED }, - order: { id: 'ASC' }, + order: { updated: 'ASC' }, }); if (!custodyOrders.length) return { totalValue: [] }; const orderMap = custodyOrders.reduce((map, order) => { - const key = Util.isoDate(order.created); + const key = Util.isoDate(order.updated); const dayMap = map.get(key) ?? new Map(); [ @@ -178,33 +178,38 @@ export class CustodyService { const assets = Array.from(new Map(allAssets.map((a) => [a.id, a])).values()); // get all prices (by date) - const startDate = new Date(custodyOrders[0].created); + const startDate = new Date(custodyOrders[0].updated); startDate.setHours(0, 0, 0, 0); const prices = await this.assetPricesService.getAssetPrices(assets, startDate); const priceMap = Util.groupByAccessor(prices, (p) => Util.isoDate(p.created)); - // process by day + // process by day: apply order volumes before calculating value const assetBalancesMap = new Map(); const totalValue: CustodyHistoryEntryDto[] = []; + const sortedOrderDays = [...orderMap.keys()].sort(); + let orderDayIndex = 0; + + for (const [day, dayPrices] of priceMap.entries()) { + // apply all order balance changes up to and including this day + while (orderDayIndex < sortedOrderDays.length && sortedOrderDays[orderDayIndex] <= day) { + const dayOrders = orderMap.get(sortedOrderDays[orderDayIndex]); + if (dayOrders) { + for (const [assetId, orders] of dayOrders.entries()) { + const currentBalance = assetBalancesMap.get(assetId) ?? 0; + assetBalancesMap.set(assetId, currentBalance + Util.sum(orders.map((o) => o.amount))); + } + } + orderDayIndex++; + } - for (const [day, prices] of priceMap.entries()) { - const dailyValue = prices.reduce( + // calculate daily portfolio value from current balances and available prices + const dailyValue = dayPrices.reduce( (value, price) => { - // update asset balance - const currentBalance = assetBalancesMap.get(price.asset.id) ?? 0; - - const ordersToday = orderMap.get(day)?.get(price.asset.id) ?? []; - const dayVolume = Util.sum(ordersToday.map((o) => o.amount)); - - const newBalance = currentBalance + dayVolume; - assetBalancesMap.set(price.asset.id, newBalance); - - // update value - value.chf += newBalance * price.priceChf; - value.eur += newBalance * price.priceEur; - value.usd += newBalance * price.priceUsd; - + const balance = assetBalancesMap.get(price.asset.id) ?? 0; + value.chf += balance * price.priceChf; + value.eur += balance * price.priceEur; + value.usd += balance * price.priceUsd; return value; }, { chf: 0, eur: 0, usd: 0 }, diff --git a/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts b/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts index 1b3c00962c..dbf48536df 100644 --- a/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts +++ b/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts @@ -72,8 +72,8 @@ export class SepaParser { return Util.asyncMap(entries, async (entry) => { const accountServiceRef = - entry?.NtryDtls?.TxDtls?.Refs?.AcctSvcrRef ?? - entry?.AcctSvcrRef ?? + this.toString(entry?.NtryDtls?.TxDtls?.Refs?.AcctSvcrRef) ?? + this.toString(entry?.AcctSvcrRef) ?? `CUSTOM/${file.BkToCstmrStmt.Stmt?.Acct?.Id?.IBAN}/${entry.BookgDt.Dt}/${entry.AddtlNtryInf}`; const creditDebitIndicator = this.toString(entry?.NtryDtls?.TxDtls?.CdtDbtInd);