| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -11,17 +11,22 @@ import { Portfolio } from '@ghostfolio/api/models/portfolio'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DataProviderService } from '@ghostfolio/api/services/data-provider.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { IOrder } from '@ghostfolio/api/services/interfaces/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Type } from '@ghostfolio/api/services/interfaces/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { IOrder, Type } from '@ghostfolio/api/services/interfaces/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { RulesService } from '@ghostfolio/api/services/rules.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioItem, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioOverview, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioPerformance, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  Position | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioPosition, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  Position, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  TimelinePosition | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from '@ghostfolio/common/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DateRange, RequestWithUser } from '@ghostfolio/common/types'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  DateRange, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  OrderWithAccount, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  RequestWithUser | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from '@ghostfolio/common/types'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Inject, Injectable } from '@nestjs/common'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { REQUEST } from '@nestjs/core'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DataSource } from '@prisma/client'; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -52,6 +57,10 @@ import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  HistoricalDataItem, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  PortfolioPositionDetail | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from './interfaces/portfolio-position-detail.interface'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { UNKNOWN_KEY } from '@ghostfolio/common/config'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { EnhancedSymbolProfile } from '@ghostfolio/api/services/interfaces/symbol-profile.interface'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { TransactionPoint } from '@ghostfolio/api/app/core/interfaces/transaction-point.interface'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					@Injectable() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					export class PortfolioService { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -65,7 +74,8 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    private readonly redisCacheService: RedisCacheService, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    @Inject(REQUEST) private readonly request: RequestWithUser, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    private readonly rulesService: RulesService, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    private readonly userService: UserService | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    private readonly userService: UserService, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    private readonly symbolProfileService: SymbolProfileService | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ) {} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async createPortfolio(aUserId: string): Promise<Portfolio> { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -158,7 +168,7 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.request.user.Settings.currency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const transactionPoints = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const { transactionPoints } = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    portfolioCalculator.setTransactionPoints(transactionPoints); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (transactionPoints.length === 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return []; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -221,20 +231,99 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async getPosition( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async getDetails( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aImpersonationId: string, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aSymbol: string | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<PortfolioPositionDetail> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const impersonationUserId = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      await this.impersonationService.validateImpersonationId( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        aImpersonationId, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.request.user.id | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aDateRange: DateRange = 'max' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<{ [symbol: string]: PortfolioPosition }> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const userId = await this.getUserId(aImpersonationId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const userCurrency = this.request.user.Settings.currency; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioCalculator = new PortfolioCalculator( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.currentRateService, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      userCurrency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolio = await this.createPortfolio( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      impersonationUserId || this.request.user.id | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const { transactionPoints, orders } = await this.getTransactionPoints( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      userId | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (transactionPoints?.length <= 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    portfolioCalculator.setTransactionPoints(transactionPoints); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioStart = parseDate(transactionPoints[0].date); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const startDate = this.getStartDate(aDateRange, portfolioStart); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const currentPositions = await portfolioCalculator.getCurrentPositions( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      startDate | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (currentPositions.hasErrors) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      throw new Error('Missing information'); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const result: { [symbol: string]: PortfolioPosition } = {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const totalValue = currentPositions.currentValue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const symbols = currentPositions.positions.map( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      (position) => position.symbol | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const [dataProviderResponses, symbolProfiles] = await Promise.all([ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.dataProviderService.get(symbols), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.symbolProfileService.getSymbolProfiles(symbols) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ]); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const symbolProfileMap: { [symbol: string]: EnhancedSymbolProfile } = {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (const symbolProfile of symbolProfiles) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      symbolProfileMap[symbolProfile.symbol] = symbolProfile; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioItemsNow: { [symbol: string]: TimelinePosition } = {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (const position of currentPositions.positions) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      portfolioItemsNow[position.symbol] = position; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const accounts = this.getAccounts(orders, portfolioItemsNow, userCurrency); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (const item of currentPositions.positions) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const value = item.quantity.mul(item.marketPrice); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const symbolProfile = symbolProfileMap[item.symbol]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const dataProviderResponse = dataProviderResponses[item.symbol]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      result[item.symbol] = { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        accounts, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        allocationCurrent: value.div(totalValue).toNumber(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        allocationInvestment: item.investment | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          .div(currentPositions.totalInvestment) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          .toNumber(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        countries: symbolProfile.countries, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currency: item.currency, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        exchange: dataProviderResponse.exchange, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        grossPerformance: item.grossPerformance.toNumber(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        grossPerformancePercent: item.grossPerformancePercentage.toNumber(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        investment: item.investment.toNumber(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        marketPrice: item.marketPrice, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        marketState: dataProviderResponse.marketState, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        name: item.name, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        quantity: item.quantity.toNumber(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        sectors: symbolProfile.sectors, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        symbol: item.symbol, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        transactionCount: item.transactionCount, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        type: dataProviderResponse.type, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        value: value.toNumber() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return result; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async getPosition( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aImpersonationId: string, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aSymbol: string | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<PortfolioPositionDetail> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const userId = await this.getUserId(aImpersonationId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolio = await this.createPortfolio(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const position = portfolio.getPositions(new Date())[aSymbol]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (position) { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -396,20 +485,14 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aImpersonationId: string, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aDateRange: DateRange = 'max' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<{ hasErrors: boolean; positions: Position[] }> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const impersonationUserId = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      await this.impersonationService.validateImpersonationId( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        aImpersonationId, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.request.user.id | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const userId = impersonationUserId || this.request.user.id; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const userId = await this.getUserId(aImpersonationId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioCalculator = new PortfolioCalculator( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.currentRateService, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.request.user.Settings.currency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const transactionPoints = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const { transactionPoints } = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (transactionPoints?.length <= 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -461,7 +544,7 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.request.user.Settings.currency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const transactionPoints = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const { transactionPoints } = await this.getTransactionPoints(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (transactionPoints?.length <= 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -521,11 +604,14 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return portfolioStart; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private async getTransactionPoints(userId: string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private async getTransactionPoints(userId: string): Promise<{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    transactionPoints: TransactionPoint[]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    orders: OrderWithAccount[]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  }> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const orders = await this.getOrders(userId); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (orders.length <= 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return []; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return { transactionPoints: [], orders: [] }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const portfolioOrders: PortfolioOrder[] = orders.map((order) => ({ | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -543,7 +629,10 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.request.user.Settings.currency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    portfolioCalculator.computeTransactionPoints(portfolioOrders); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return portfolioCalculator.getTransactionPoints(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      transactionPoints: portfolioCalculator.getTransactionPoints(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      orders | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private convertDateRangeToDate(aDateRange: DateRange, aMinDate: Date) { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -593,6 +682,44 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private getAccounts( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    orders: OrderWithAccount[], | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    portfolioItemsNow: { [p: string]: TimelinePosition }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    userCurrency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const accounts: PortfolioPosition['accounts'] = {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (const order of orders) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      let currentValueOfSymbol = this.exchangeRateDataService.toCurrency( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        order.quantity * portfolioItemsNow[order.symbol].marketPrice, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        order.currency, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        userCurrency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      let originalValueOfSymbol = this.exchangeRateDataService.toCurrency( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        order.quantity * order.unitPrice, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        order.currency, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        userCurrency | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      if (order.type === 'SELL') { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        currentValueOfSymbol *= -1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        originalValueOfSymbol *= -1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      if (accounts[order.Account?.name || UNKNOWN_KEY]?.current) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        accounts[order.Account?.name || UNKNOWN_KEY].current += | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          currentValueOfSymbol; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        accounts[order.Account?.name || UNKNOWN_KEY].original += | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          originalValueOfSymbol; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        accounts[order.Account?.name || UNKNOWN_KEY] = { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          current: currentValueOfSymbol, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          original: originalValueOfSymbol | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return accounts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private getOrders(aUserId: string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return this.orderService.orders({ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      include: { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -605,4 +732,14 @@ export class PortfolioService { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      where: { userId: aUserId } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private async getUserId(aImpersonationId: string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const impersonationUserId = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      await this.impersonationService.validateImpersonationId( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        aImpersonationId, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.request.user.id | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return impersonationUserId || this.request.user.id; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
					 | 
				
				 | 
				
					
  |