|  |  | @ -63,7 +63,8 @@ import { | 
			
		
	
		
			
				
					|  |  |  |   DataSource, | 
			
		
	
		
			
				
					|  |  |  |   Order, | 
			
		
	
		
			
				
					|  |  |  |   Platform, | 
			
		
	
		
			
				
					|  |  |  |   Prisma | 
			
		
	
		
			
				
					|  |  |  |   Prisma, | 
			
		
	
		
			
				
					|  |  |  |   SymbolProfile | 
			
		
	
		
			
				
					|  |  |  | } from '@prisma/client'; | 
			
		
	
		
			
				
					|  |  |  | import { Big } from 'big.js'; | 
			
		
	
		
			
				
					|  |  |  | import { isUUID } from 'class-validator'; | 
			
		
	
	
		
			
				
					|  |  | @ -337,6 +338,7 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |     userId, | 
			
		
	
		
			
				
					|  |  |  |     withExcludedAccounts = false, | 
			
		
	
		
			
				
					|  |  |  |     withLiabilities = false, | 
			
		
	
		
			
				
					|  |  |  |     withMarkets = false, | 
			
		
	
		
			
				
					|  |  |  |     withSummary = false | 
			
		
	
		
			
				
					|  |  |  |   }: { | 
			
		
	
		
			
				
					|  |  |  |     dateRange?: DateRange; | 
			
		
	
	
		
			
				
					|  |  | @ -345,6 +347,7 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |     userId: string; | 
			
		
	
		
			
				
					|  |  |  |     withExcludedAccounts?: boolean; | 
			
		
	
		
			
				
					|  |  |  |     withLiabilities?: boolean; | 
			
		
	
		
			
				
					|  |  |  |     withMarkets?: boolean; | 
			
		
	
		
			
				
					|  |  |  |     withSummary?: boolean; | 
			
		
	
		
			
				
					|  |  |  |   }): Promise<PortfolioDetails & { hasErrors: boolean }> { | 
			
		
	
		
			
				
					|  |  |  |     userId = await this.getUserId(impersonationId, userId); | 
			
		
	
	
		
			
				
					|  |  | @ -484,77 +487,17 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       const symbolProfile = symbolProfileMap[symbol]; | 
			
		
	
		
			
				
					|  |  |  |       const assetProfile = symbolProfileMap[symbol]; | 
			
		
	
		
			
				
					|  |  |  |       const dataProviderResponse = dataProviderResponses[symbol]; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       const markets: PortfolioPosition['markets'] = { | 
			
		
	
		
			
				
					|  |  |  |         [UNKNOWN_KEY]: 0, | 
			
		
	
		
			
				
					|  |  |  |         developedMarkets: 0, | 
			
		
	
		
			
				
					|  |  |  |         emergingMarkets: 0, | 
			
		
	
		
			
				
					|  |  |  |         otherMarkets: 0 | 
			
		
	
		
			
				
					|  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  |       const marketsAdvanced: PortfolioPosition['marketsAdvanced'] = { | 
			
		
	
		
			
				
					|  |  |  |         [UNKNOWN_KEY]: 0, | 
			
		
	
		
			
				
					|  |  |  |         asiaPacific: 0, | 
			
		
	
		
			
				
					|  |  |  |         emergingMarkets: 0, | 
			
		
	
		
			
				
					|  |  |  |         europe: 0, | 
			
		
	
		
			
				
					|  |  |  |         japan: 0, | 
			
		
	
		
			
				
					|  |  |  |         northAmerica: 0, | 
			
		
	
		
			
				
					|  |  |  |         otherMarkets: 0 | 
			
		
	
		
			
				
					|  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       if (symbolProfile.countries.length > 0) { | 
			
		
	
		
			
				
					|  |  |  |         for (const country of symbolProfile.countries) { | 
			
		
	
		
			
				
					|  |  |  |           if (developedMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |             markets.developedMarkets = new Big(markets.developedMarkets) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else if (emergingMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |             markets.emergingMarkets = new Big(markets.emergingMarkets) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else { | 
			
		
	
		
			
				
					|  |  |  |             markets.otherMarkets = new Big(markets.otherMarkets) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |       let markets: PortfolioPosition['markets']; | 
			
		
	
		
			
				
					|  |  |  |       let marketsAdvanced: PortfolioPosition['marketsAdvanced']; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |           if (country.code === 'JP') { | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.japan = new Big(marketsAdvanced.japan) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else if (country.code === 'CA' || country.code === 'US') { | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.northAmerica = new Big(marketsAdvanced.northAmerica) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else if (asiaPacificMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.asiaPacific = new Big(marketsAdvanced.asiaPacific) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else if (emergingMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.emergingMarkets = new Big( | 
			
		
	
		
			
				
					|  |  |  |               marketsAdvanced.emergingMarkets | 
			
		
	
		
			
				
					|  |  |  |             ) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else if (europeMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.europe = new Big(marketsAdvanced.europe) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } else { | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.otherMarkets = new Big(marketsAdvanced.otherMarkets) | 
			
		
	
		
			
				
					|  |  |  |               .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |               .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |       } else { | 
			
		
	
		
			
				
					|  |  |  |         markets[UNKNOWN_KEY] = new Big(markets[UNKNOWN_KEY]) | 
			
		
	
		
			
				
					|  |  |  |           .plus(valueInBaseCurrency) | 
			
		
	
		
			
				
					|  |  |  |           .toNumber(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         marketsAdvanced[UNKNOWN_KEY] = new Big(marketsAdvanced[UNKNOWN_KEY]) | 
			
		
	
		
			
				
					|  |  |  |           .plus(valueInBaseCurrency) | 
			
		
	
		
			
				
					|  |  |  |           .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |       if (withMarkets) { | 
			
		
	
		
			
				
					|  |  |  |         ({ markets, marketsAdvanced } = this.getMarkets({ | 
			
		
	
		
			
				
					|  |  |  |           assetProfile, | 
			
		
	
		
			
				
					|  |  |  |           valueInBaseCurrency | 
			
		
	
		
			
				
					|  |  |  |         })); | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       holdings[symbol] = { | 
			
		
	
	
		
			
				
					|  |  | @ -568,10 +511,10 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |         allocationInPercentage: filteredValueInBaseCurrency.eq(0) | 
			
		
	
		
			
				
					|  |  |  |           ? 0 | 
			
		
	
		
			
				
					|  |  |  |           : valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(), | 
			
		
	
		
			
				
					|  |  |  |         assetClass: symbolProfile.assetClass, | 
			
		
	
		
			
				
					|  |  |  |         assetSubClass: symbolProfile.assetSubClass, | 
			
		
	
		
			
				
					|  |  |  |         countries: symbolProfile.countries, | 
			
		
	
		
			
				
					|  |  |  |         dataSource: symbolProfile.dataSource, | 
			
		
	
		
			
				
					|  |  |  |         assetClass: assetProfile.assetClass, | 
			
		
	
		
			
				
					|  |  |  |         assetSubClass: assetProfile.assetSubClass, | 
			
		
	
		
			
				
					|  |  |  |         countries: assetProfile.countries, | 
			
		
	
		
			
				
					|  |  |  |         dataSource: assetProfile.dataSource, | 
			
		
	
		
			
				
					|  |  |  |         dateOfFirstActivity: parseDate(firstBuyDate), | 
			
		
	
		
			
				
					|  |  |  |         dividend: dividend?.toNumber() ?? 0, | 
			
		
	
		
			
				
					|  |  |  |         grossPerformance: grossPerformance?.toNumber() ?? 0, | 
			
		
	
	
		
			
				
					|  |  | @ -582,7 +525,7 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |           grossPerformanceWithCurrencyEffect?.toNumber() ?? 0, | 
			
		
	
		
			
				
					|  |  |  |         investment: investment.toNumber(), | 
			
		
	
		
			
				
					|  |  |  |         marketState: dataProviderResponse?.marketState ?? 'delayed', | 
			
		
	
		
			
				
					|  |  |  |         name: symbolProfile.name, | 
			
		
	
		
			
				
					|  |  |  |         name: assetProfile.name, | 
			
		
	
		
			
				
					|  |  |  |         netPerformance: netPerformance?.toNumber() ?? 0, | 
			
		
	
		
			
				
					|  |  |  |         netPerformancePercent: netPerformancePercentage?.toNumber() ?? 0, | 
			
		
	
		
			
				
					|  |  |  |         netPerformancePercentWithCurrencyEffect: | 
			
		
	
	
		
			
				
					|  |  | @ -590,8 +533,8 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |         netPerformanceWithCurrencyEffect: | 
			
		
	
		
			
				
					|  |  |  |           netPerformanceWithCurrencyEffect?.toNumber() ?? 0, | 
			
		
	
		
			
				
					|  |  |  |         quantity: quantity.toNumber(), | 
			
		
	
		
			
				
					|  |  |  |         sectors: symbolProfile.sectors, | 
			
		
	
		
			
				
					|  |  |  |         url: symbolProfile.url, | 
			
		
	
		
			
				
					|  |  |  |         sectors: assetProfile.sectors, | 
			
		
	
		
			
				
					|  |  |  |         url: assetProfile.url, | 
			
		
	
		
			
				
					|  |  |  |         valueInBaseCurrency: valueInBaseCurrency.toNumber() | 
			
		
	
		
			
				
					|  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
	
		
			
				
					|  |  | @ -1630,6 +1573,86 @@ export class PortfolioService { | 
			
		
	
		
			
				
					|  |  |  |     }; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   private getMarkets({ | 
			
		
	
		
			
				
					|  |  |  |     assetProfile, | 
			
		
	
		
			
				
					|  |  |  |     valueInBaseCurrency | 
			
		
	
		
			
				
					|  |  |  |   }: { | 
			
		
	
		
			
				
					|  |  |  |     assetProfile: EnhancedSymbolProfile; | 
			
		
	
		
			
				
					|  |  |  |     valueInBaseCurrency: Big; | 
			
		
	
		
			
				
					|  |  |  |   }) { | 
			
		
	
		
			
				
					|  |  |  |     const markets = { | 
			
		
	
		
			
				
					|  |  |  |       [UNKNOWN_KEY]: 0, | 
			
		
	
		
			
				
					|  |  |  |       developedMarkets: 0, | 
			
		
	
		
			
				
					|  |  |  |       emergingMarkets: 0, | 
			
		
	
		
			
				
					|  |  |  |       otherMarkets: 0 | 
			
		
	
		
			
				
					|  |  |  |     }; | 
			
		
	
		
			
				
					|  |  |  |     const marketsAdvanced = { | 
			
		
	
		
			
				
					|  |  |  |       [UNKNOWN_KEY]: 0, | 
			
		
	
		
			
				
					|  |  |  |       asiaPacific: 0, | 
			
		
	
		
			
				
					|  |  |  |       emergingMarkets: 0, | 
			
		
	
		
			
				
					|  |  |  |       europe: 0, | 
			
		
	
		
			
				
					|  |  |  |       japan: 0, | 
			
		
	
		
			
				
					|  |  |  |       northAmerica: 0, | 
			
		
	
		
			
				
					|  |  |  |       otherMarkets: 0 | 
			
		
	
		
			
				
					|  |  |  |     }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (assetProfile.countries.length > 0) { | 
			
		
	
		
			
				
					|  |  |  |       for (const country of assetProfile.countries) { | 
			
		
	
		
			
				
					|  |  |  |         if (developedMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |           markets.developedMarkets = new Big(markets.developedMarkets) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else if (emergingMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |           markets.emergingMarkets = new Big(markets.emergingMarkets) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |           markets.otherMarkets = new Big(markets.otherMarkets) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         if (country.code === 'JP') { | 
			
		
	
		
			
				
					|  |  |  |           marketsAdvanced.japan = new Big(marketsAdvanced.japan) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else if (country.code === 'CA' || country.code === 'US') { | 
			
		
	
		
			
				
					|  |  |  |           marketsAdvanced.northAmerica = new Big(marketsAdvanced.northAmerica) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else if (asiaPacificMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |           marketsAdvanced.asiaPacific = new Big(marketsAdvanced.asiaPacific) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else if (emergingMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |           marketsAdvanced.emergingMarkets = new Big( | 
			
		
	
		
			
				
					|  |  |  |             marketsAdvanced.emergingMarkets | 
			
		
	
		
			
				
					|  |  |  |           ) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else if (europeMarkets.includes(country.code)) { | 
			
		
	
		
			
				
					|  |  |  |           marketsAdvanced.europe = new Big(marketsAdvanced.europe) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |           marketsAdvanced.otherMarkets = new Big(marketsAdvanced.otherMarkets) | 
			
		
	
		
			
				
					|  |  |  |             .plus(country.weight) | 
			
		
	
		
			
				
					|  |  |  |             .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |       markets[UNKNOWN_KEY] = new Big(markets[UNKNOWN_KEY]) | 
			
		
	
		
			
				
					|  |  |  |         .plus(valueInBaseCurrency) | 
			
		
	
		
			
				
					|  |  |  |         .toNumber(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       marketsAdvanced[UNKNOWN_KEY] = new Big(marketsAdvanced[UNKNOWN_KEY]) | 
			
		
	
		
			
				
					|  |  |  |         .plus(valueInBaseCurrency) | 
			
		
	
		
			
				
					|  |  |  |         .toNumber(); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     return { markets, marketsAdvanced }; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   private getStreaks({ | 
			
		
	
		
			
				
					|  |  |  |     investments, | 
			
		
	
		
			
				
					|  |  |  |     savingsRate | 
			
		
	
	
		
			
				
					|  |  | 
 |