|
|
@ -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 |
|
|
|