| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -15,6 +15,7 @@ import { RulesService } from '@ghostfolio/api/services/rules.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioItem, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioOverview, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioPerformance, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  Position | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from '@ghostfolio/common/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DateRange, RequestWithUser } from '@ghostfolio/common/types'; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -438,6 +439,64 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async getPerformance( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aImpersonationId: string, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aDateRange: DateRange = 'max' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<{ hasErrors: boolean; performance: PortfolioPerformance }> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const impersonationUserId = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      await this.impersonationService.validateImpersonationId( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        aImpersonationId, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.request.user.id | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const userId = impersonationUserId || this.request.user.id; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioCalculator = new PortfolioCalculator( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.currentRateService, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.request.user.Settings.currency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const transactionPoints = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    portfolioCalculator.setTransactionPoints(transactionPoints); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioStart = parseDate(transactionPoints[0].date); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const startDate = this.getStartDate(aDateRange, portfolioStart); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const currentPositions = await portfolioCalculator.getCurrentPositions( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      startDate | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    let currentValue = new Big(0); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    let grossPerformance = new Big(0); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    let grossPerformancePercentage = new Big(1); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (const currentPosition of currentPositions.positions) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      currentValue = currentValue.add( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        new Big(currentPosition.marketPrice).mul(currentPosition.quantity) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      grossPerformance = grossPerformance.plus( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentPosition.grossPerformance | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      grossPerformancePercentage = grossPerformancePercentage.mul( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentPosition.grossPerformancePercentage.plus(1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const currentGrossPerformance = grossPerformance.toNumber(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const currentGrossPerformancePercent = grossPerformancePercentage | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      .minus(1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      .toNumber(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      hasErrors: currentPositions.hasErrors, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      performance: { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentGrossPerformance, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentGrossPerformancePercent, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // TODO: the next two should include fees
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentNetPerformance: currentGrossPerformance, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentNetPerformancePercent: currentGrossPerformancePercent, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentValue: currentValue.toNumber() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private getStartDate(aDateRange: DateRange, portfolioStart: Date) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    switch (aDateRange) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      case '1d': | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |