|  |  | @ -22,6 +22,7 @@ import { | 
			
		
	
		
			
				
					|  |  |  |   format, | 
			
		
	
		
			
				
					|  |  |  |   isBefore, | 
			
		
	
		
			
				
					|  |  |  |   isSameDay, | 
			
		
	
		
			
				
					|  |  |  |   max, | 
			
		
	
		
			
				
					|  |  |  |   subDays | 
			
		
	
		
			
				
					|  |  |  | } from 'date-fns'; | 
			
		
	
		
			
				
					|  |  |  | import { cloneDeep, first, isNumber, last, sortBy, uniq } from 'lodash'; | 
			
		
	
	
		
			
				
					|  |  | @ -449,16 +450,27 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public async getCurrentPositions( | 
			
		
	
		
			
				
					|  |  |  |     start: Date, | 
			
		
	
		
			
				
					|  |  |  |     end = new Date(Date.now()) | 
			
		
	
		
			
				
					|  |  |  |     end?: Date | 
			
		
	
		
			
				
					|  |  |  |   ): Promise<CurrentPositions> { | 
			
		
	
		
			
				
					|  |  |  |     const transactionPointsBeforeEndDate = | 
			
		
	
		
			
				
					|  |  |  |       this.transactionPoints?.filter((transactionPoint) => { | 
			
		
	
		
			
				
					|  |  |  |         return isBefore(parseDate(transactionPoint.date), end); | 
			
		
	
		
			
				
					|  |  |  |       }) ?? []; | 
			
		
	
		
			
				
					|  |  |  |     const lastTransactionPoint = last(this.transactionPoints); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     let endDate = end; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (!endDate) { | 
			
		
	
		
			
				
					|  |  |  |       endDate = new Date(Date.now()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (!transactionPointsBeforeEndDate.length) { | 
			
		
	
		
			
				
					|  |  |  |       if (lastTransactionPoint) { | 
			
		
	
		
			
				
					|  |  |  |         endDate = max([endDate, parseDate(lastTransactionPoint.date)]); | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     const transactionPoints = this.transactionPoints?.filter(({ date }) => { | 
			
		
	
		
			
				
					|  |  |  |       return isBefore(parseDate(date), endDate); | 
			
		
	
		
			
				
					|  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (!transactionPoints.length) { | 
			
		
	
		
			
				
					|  |  |  |       return { | 
			
		
	
		
			
				
					|  |  |  |         currentValue: new Big(0), | 
			
		
	
		
			
				
					|  |  |  |         currentValueInBaseCurrency: new Big(0), | 
			
		
	
		
			
				
					|  |  |  |         grossPerformance: new Big(0), | 
			
		
	
		
			
				
					|  |  |  |         grossPerformancePercentage: new Big(0), | 
			
		
	
		
			
				
					|  |  |  |         grossPerformancePercentageWithCurrencyEffect: new Big(0), | 
			
		
	
	
		
			
				
					|  |  | @ -473,41 +485,40 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     const lastTransactionPoint = | 
			
		
	
		
			
				
					|  |  |  |       transactionPointsBeforeEndDate[transactionPointsBeforeEndDate.length - 1]; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     const currencies: { [symbol: string]: string } = {}; | 
			
		
	
		
			
				
					|  |  |  |     const dataGatheringItems: IDataGatheringItem[] = []; | 
			
		
	
		
			
				
					|  |  |  |     let dates: Date[] = []; | 
			
		
	
		
			
				
					|  |  |  |     let firstIndex = transactionPointsBeforeEndDate.length; | 
			
		
	
		
			
				
					|  |  |  |     let firstIndex = transactionPoints.length; | 
			
		
	
		
			
				
					|  |  |  |     let firstTransactionPoint: TransactionPoint = null; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     dates.push(resetHours(start)); | 
			
		
	
		
			
				
					|  |  |  |     for (const item of transactionPointsBeforeEndDate[firstIndex - 1].items) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     for (const { currency, dataSource, symbol } of transactionPoints[ | 
			
		
	
		
			
				
					|  |  |  |       firstIndex - 1 | 
			
		
	
		
			
				
					|  |  |  |     ].items) { | 
			
		
	
		
			
				
					|  |  |  |       dataGatheringItems.push({ | 
			
		
	
		
			
				
					|  |  |  |         dataSource: item.dataSource, | 
			
		
	
		
			
				
					|  |  |  |         symbol: item.symbol | 
			
		
	
		
			
				
					|  |  |  |         dataSource, | 
			
		
	
		
			
				
					|  |  |  |         symbol | 
			
		
	
		
			
				
					|  |  |  |       }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       currencies[item.symbol] = item.currency; | 
			
		
	
		
			
				
					|  |  |  |       currencies[symbol] = currency; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     for (let i = 0; i < transactionPointsBeforeEndDate.length; i++) { | 
			
		
	
		
			
				
					|  |  |  |     for (let i = 0; i < transactionPoints.length; i++) { | 
			
		
	
		
			
				
					|  |  |  |       if ( | 
			
		
	
		
			
				
					|  |  |  |         !isBefore(parseDate(transactionPointsBeforeEndDate[i].date), start) && | 
			
		
	
		
			
				
					|  |  |  |         !isBefore(parseDate(transactionPoints[i].date), start) && | 
			
		
	
		
			
				
					|  |  |  |         firstTransactionPoint === null | 
			
		
	
		
			
				
					|  |  |  |       ) { | 
			
		
	
		
			
				
					|  |  |  |         firstTransactionPoint = transactionPointsBeforeEndDate[i]; | 
			
		
	
		
			
				
					|  |  |  |         firstTransactionPoint = transactionPoints[i]; | 
			
		
	
		
			
				
					|  |  |  |         firstIndex = i; | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       if (firstTransactionPoint !== null) { | 
			
		
	
		
			
				
					|  |  |  |         dates.push( | 
			
		
	
		
			
				
					|  |  |  |           resetHours(parseDate(transactionPointsBeforeEndDate[i].date)) | 
			
		
	
		
			
				
					|  |  |  |         ); | 
			
		
	
		
			
				
					|  |  |  |         dates.push(resetHours(parseDate(transactionPoints[i].date))); | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     dates.push(resetHours(end)); | 
			
		
	
		
			
				
					|  |  |  |     dates.push(resetHours(endDate)); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // Add dates of last week for fallback
 | 
			
		
	
		
			
				
					|  |  |  |     dates.push(subDays(resetHours(new Date()), 7)); | 
			
		
	
	
		
			
				
					|  |  | @ -534,7 +545,7 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |     let exchangeRatesByCurrency = | 
			
		
	
		
			
				
					|  |  |  |       await this.exchangeRateDataService.getExchangeRatesByCurrency({ | 
			
		
	
		
			
				
					|  |  |  |         currencies: uniq(Object.values(currencies)), | 
			
		
	
		
			
				
					|  |  |  |         endDate: endOfDay(end), | 
			
		
	
		
			
				
					|  |  |  |         endDate: endOfDay(endDate), | 
			
		
	
		
			
				
					|  |  |  |         startDate: parseDate(this.transactionPoints?.[0]?.date), | 
			
		
	
		
			
				
					|  |  |  |         targetCurrency: this.currency | 
			
		
	
		
			
				
					|  |  |  |       }); | 
			
		
	
	
		
			
				
					|  |  | @ -570,7 +581,7 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     const endDateString = format(end, DATE_FORMAT); | 
			
		
	
		
			
				
					|  |  |  |     const endDateString = format(endDate, DATE_FORMAT); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (firstIndex > 0) { | 
			
		
	
		
			
				
					|  |  |  |       firstIndex--; | 
			
		
	
	
		
			
				
					|  |  | @ -582,9 +593,9 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |     const errors: ResponseError['errors'] = []; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     for (const item of lastTransactionPoint.items) { | 
			
		
	
		
			
				
					|  |  |  |       const marketPriceInBaseCurrency = marketSymbolMap[endDateString]?.[ | 
			
		
	
		
			
				
					|  |  |  |         item.symbol | 
			
		
	
		
			
				
					|  |  |  |       ]?.mul( | 
			
		
	
		
			
				
					|  |  |  |       const marketPriceInBaseCurrency = ( | 
			
		
	
		
			
				
					|  |  |  |         marketSymbolMap[endDateString]?.[item.symbol] ?? item.averagePrice | 
			
		
	
		
			
				
					|  |  |  |       ).mul( | 
			
		
	
		
			
				
					|  |  |  |         exchangeRatesByCurrency[`${item.currency}${this.currency}`]?.[ | 
			
		
	
		
			
				
					|  |  |  |           endDateString | 
			
		
	
		
			
				
					|  |  |  |         ] | 
			
		
	
	
		
			
				
					|  |  | @ -607,9 +618,9 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |         totalInvestment, | 
			
		
	
		
			
				
					|  |  |  |         totalInvestmentWithCurrencyEffect | 
			
		
	
		
			
				
					|  |  |  |       } = this.getSymbolMetrics({ | 
			
		
	
		
			
				
					|  |  |  |         end, | 
			
		
	
		
			
				
					|  |  |  |         marketSymbolMap, | 
			
		
	
		
			
				
					|  |  |  |         start, | 
			
		
	
		
			
				
					|  |  |  |         end: endDate, | 
			
		
	
		
			
				
					|  |  |  |         exchangeRates: | 
			
		
	
		
			
				
					|  |  |  |           exchangeRatesByCurrency[`${item.currency}${this.currency}`], | 
			
		
	
		
			
				
					|  |  |  |         symbol: item.symbol | 
			
		
	
	
		
			
				
					|  |  | @ -656,7 +667,10 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |         quantity: item.quantity, | 
			
		
	
		
			
				
					|  |  |  |         symbol: item.symbol, | 
			
		
	
		
			
				
					|  |  |  |         tags: item.tags, | 
			
		
	
		
			
				
					|  |  |  |         transactionCount: item.transactionCount | 
			
		
	
		
			
				
					|  |  |  |         transactionCount: item.transactionCount, | 
			
		
	
		
			
				
					|  |  |  |         valueInBaseCurrency: new Big(marketPriceInBaseCurrency).mul( | 
			
		
	
		
			
				
					|  |  |  |           item.quantity | 
			
		
	
		
			
				
					|  |  |  |         ) | 
			
		
	
		
			
				
					|  |  |  |       }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       if ( | 
			
		
	
	
		
			
				
					|  |  | @ -725,7 +739,7 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   private calculateOverallPerformance(positions: TimelinePosition[]) { | 
			
		
	
		
			
				
					|  |  |  |     let currentValue = new Big(0); | 
			
		
	
		
			
				
					|  |  |  |     let currentValueInBaseCurrency = new Big(0); | 
			
		
	
		
			
				
					|  |  |  |     let grossPerformance = new Big(0); | 
			
		
	
		
			
				
					|  |  |  |     let grossPerformanceWithCurrencyEffect = new Big(0); | 
			
		
	
		
			
				
					|  |  |  |     let hasErrors = false; | 
			
		
	
	
		
			
				
					|  |  | @ -737,14 +751,9 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |     let totalTimeWeightedInvestmentWithCurrencyEffect = new Big(0); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     for (const currentPosition of positions) { | 
			
		
	
		
			
				
					|  |  |  |       if ( | 
			
		
	
		
			
				
					|  |  |  |         currentPosition.investment && | 
			
		
	
		
			
				
					|  |  |  |         currentPosition.marketPriceInBaseCurrency | 
			
		
	
		
			
				
					|  |  |  |       ) { | 
			
		
	
		
			
				
					|  |  |  |         currentValue = currentValue.plus( | 
			
		
	
		
			
				
					|  |  |  |           new Big(currentPosition.marketPriceInBaseCurrency).mul( | 
			
		
	
		
			
				
					|  |  |  |             currentPosition.quantity | 
			
		
	
		
			
				
					|  |  |  |           ) | 
			
		
	
		
			
				
					|  |  |  |       if (currentPosition.valueInBaseCurrency) { | 
			
		
	
		
			
				
					|  |  |  |         currentValueInBaseCurrency = currentValueInBaseCurrency.plus( | 
			
		
	
		
			
				
					|  |  |  |           currentPosition.valueInBaseCurrency | 
			
		
	
		
			
				
					|  |  |  |         ); | 
			
		
	
		
			
				
					|  |  |  |       } else { | 
			
		
	
		
			
				
					|  |  |  |         hasErrors = true; | 
			
		
	
	
		
			
				
					|  |  | @ -801,7 +810,7 @@ export class PortfolioCalculator { | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     return { | 
			
		
	
		
			
				
					|  |  |  |       currentValue, | 
			
		
	
		
			
				
					|  |  |  |       currentValueInBaseCurrency, | 
			
		
	
		
			
				
					|  |  |  |       grossPerformance, | 
			
		
	
		
			
				
					|  |  |  |       grossPerformanceWithCurrencyEffect, | 
			
		
	
		
			
				
					|  |  |  |       hasErrors, | 
			
		
	
	
		
			
				
					|  |  | 
 |