|
@ -312,15 +312,17 @@ export class PortfolioService { |
|
|
filters, |
|
|
filters, |
|
|
groupBy, |
|
|
groupBy, |
|
|
impersonationId, |
|
|
impersonationId, |
|
|
savingsRate |
|
|
savingsRate, |
|
|
|
|
|
userId |
|
|
}: { |
|
|
}: { |
|
|
dateRange: DateRange; |
|
|
dateRange: DateRange; |
|
|
filters?: Filter[]; |
|
|
filters?: Filter[]; |
|
|
groupBy?: GroupBy; |
|
|
groupBy?: GroupBy; |
|
|
impersonationId: string; |
|
|
impersonationId: string; |
|
|
savingsRate: number; |
|
|
savingsRate: number; |
|
|
|
|
|
userId: string; |
|
|
}): Promise<PortfolioInvestments> { |
|
|
}): Promise<PortfolioInvestments> { |
|
|
const userId = await this.getUserId(impersonationId, this.request.user.id); |
|
|
userId = await this.getUserId(impersonationId, userId); |
|
|
const user = await this.userService.user({ id: userId }); |
|
|
const user = await this.userService.user({ id: userId }); |
|
|
const userCurrency = this.getUserCurrency(user); |
|
|
const userCurrency = this.getUserCurrency(user); |
|
|
|
|
|
|
|
@ -676,12 +678,18 @@ export class PortfolioService { |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public async getHolding( |
|
|
public async getHolding({ |
|
|
aDataSource: DataSource, |
|
|
dataSource, |
|
|
aImpersonationId: string, |
|
|
impersonationId, |
|
|
aSymbol: string |
|
|
symbol, |
|
|
): Promise<PortfolioHoldingResponse> { |
|
|
userId |
|
|
const userId = await this.getUserId(aImpersonationId, this.request.user.id); |
|
|
}: { |
|
|
|
|
|
dataSource: DataSource; |
|
|
|
|
|
impersonationId: string; |
|
|
|
|
|
symbol: string; |
|
|
|
|
|
userId: string; |
|
|
|
|
|
}): Promise<PortfolioHoldingResponse> { |
|
|
|
|
|
userId = await this.getUserId(impersonationId, userId); |
|
|
const user = await this.userService.user({ id: userId }); |
|
|
const user = await this.userService.user({ id: userId }); |
|
|
const userCurrency = this.getUserCurrency(user); |
|
|
const userCurrency = this.getUserCurrency(user); |
|
|
|
|
|
|
|
@ -724,7 +732,7 @@ export class PortfolioService { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const [SymbolProfile] = await this.symbolProfileService.getSymbolProfiles([ |
|
|
const [SymbolProfile] = await this.symbolProfileService.getSymbolProfiles([ |
|
|
{ dataSource: aDataSource, symbol: aSymbol } |
|
|
{ dataSource, symbol } |
|
|
]); |
|
|
]); |
|
|
|
|
|
|
|
|
const portfolioCalculator = this.calculatorFactory.createCalculator({ |
|
|
const portfolioCalculator = this.calculatorFactory.createCalculator({ |
|
@ -739,26 +747,33 @@ export class PortfolioService { |
|
|
|
|
|
|
|
|
const { positions } = await portfolioCalculator.getSnapshot(); |
|
|
const { positions } = await portfolioCalculator.getSnapshot(); |
|
|
|
|
|
|
|
|
const position = positions.find(({ dataSource, symbol }) => { |
|
|
const holding = positions.find((position) => { |
|
|
return dataSource === aDataSource && symbol === aSymbol; |
|
|
return position.dataSource === dataSource && position.symbol === symbol; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if (position) { |
|
|
if (holding) { |
|
|
const { |
|
|
const { |
|
|
averagePrice, |
|
|
averagePrice, |
|
|
currency, |
|
|
currency, |
|
|
dataSource, |
|
|
|
|
|
dividendInBaseCurrency, |
|
|
dividendInBaseCurrency, |
|
|
fee, |
|
|
fee, |
|
|
firstBuyDate, |
|
|
firstBuyDate, |
|
|
|
|
|
grossPerformance, |
|
|
|
|
|
grossPerformancePercentage, |
|
|
|
|
|
grossPerformancePercentageWithCurrencyEffect, |
|
|
|
|
|
grossPerformanceWithCurrencyEffect, |
|
|
|
|
|
investmentWithCurrencyEffect, |
|
|
marketPrice, |
|
|
marketPrice, |
|
|
|
|
|
netPerformance, |
|
|
|
|
|
netPerformancePercentage, |
|
|
|
|
|
netPerformancePercentageWithCurrencyEffectMap, |
|
|
|
|
|
netPerformanceWithCurrencyEffectMap, |
|
|
quantity, |
|
|
quantity, |
|
|
symbol, |
|
|
|
|
|
tags, |
|
|
tags, |
|
|
timeWeightedInvestment, |
|
|
timeWeightedInvestment, |
|
|
timeWeightedInvestmentWithCurrencyEffect, |
|
|
timeWeightedInvestmentWithCurrencyEffect, |
|
|
transactionCount |
|
|
transactionCount |
|
|
} = position; |
|
|
} = holding; |
|
|
|
|
|
|
|
|
const activitiesOfHolding = activities.filter(({ SymbolProfile }) => { |
|
|
const activitiesOfHolding = activities.filter(({ SymbolProfile }) => { |
|
|
return ( |
|
|
return ( |
|
@ -787,7 +802,7 @@ export class PortfolioService { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const historicalData = await this.dataProviderService.getHistorical( |
|
|
const historicalData = await this.dataProviderService.getHistorical( |
|
|
[{ dataSource, symbol: aSymbol }], |
|
|
[{ dataSource, symbol }], |
|
|
'day', |
|
|
'day', |
|
|
parseISO(firstBuyDate), |
|
|
parseISO(firstBuyDate), |
|
|
new Date() |
|
|
new Date() |
|
@ -807,10 +822,10 @@ export class PortfolioService { |
|
|
marketPrice |
|
|
marketPrice |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
if (historicalData[aSymbol]) { |
|
|
if (historicalData[symbol]) { |
|
|
let j = -1; |
|
|
let j = -1; |
|
|
for (const [date, { marketPrice }] of Object.entries( |
|
|
for (const [date, { marketPrice }] of Object.entries( |
|
|
historicalData[aSymbol] |
|
|
historicalData[symbol] |
|
|
)) { |
|
|
)) { |
|
|
while ( |
|
|
while ( |
|
|
j + 1 < transactionPoints.length && |
|
|
j + 1 < transactionPoints.length && |
|
@ -823,8 +838,8 @@ export class PortfolioService { |
|
|
let currentQuantity = 0; |
|
|
let currentQuantity = 0; |
|
|
|
|
|
|
|
|
const currentSymbol = transactionPoints[j]?.items.find( |
|
|
const currentSymbol = transactionPoints[j]?.items.find( |
|
|
({ symbol }) => { |
|
|
(transactionPointSymbol) => { |
|
|
return symbol === aSymbol; |
|
|
return transactionPointSymbol.symbol === symbol; |
|
|
} |
|
|
} |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
@ -888,24 +903,21 @@ export class PortfolioService { |
|
|
SymbolProfile.currency, |
|
|
SymbolProfile.currency, |
|
|
userCurrency |
|
|
userCurrency |
|
|
), |
|
|
), |
|
|
grossPerformance: position.grossPerformance?.toNumber(), |
|
|
grossPerformance: grossPerformance?.toNumber(), |
|
|
grossPerformancePercent: |
|
|
grossPerformancePercent: grossPerformancePercentage?.toNumber(), |
|
|
position.grossPerformancePercentage?.toNumber(), |
|
|
|
|
|
grossPerformancePercentWithCurrencyEffect: |
|
|
grossPerformancePercentWithCurrencyEffect: |
|
|
position.grossPerformancePercentageWithCurrencyEffect?.toNumber(), |
|
|
grossPerformancePercentageWithCurrencyEffect?.toNumber(), |
|
|
grossPerformanceWithCurrencyEffect: |
|
|
grossPerformanceWithCurrencyEffect: |
|
|
position.grossPerformanceWithCurrencyEffect?.toNumber(), |
|
|
grossPerformanceWithCurrencyEffect?.toNumber(), |
|
|
historicalData: historicalDataArray, |
|
|
historicalData: historicalDataArray, |
|
|
investmentInBaseCurrencyWithCurrencyEffect: |
|
|
investmentInBaseCurrencyWithCurrencyEffect: |
|
|
position.investmentWithCurrencyEffect?.toNumber(), |
|
|
investmentWithCurrencyEffect?.toNumber(), |
|
|
netPerformance: position.netPerformance?.toNumber(), |
|
|
netPerformance: netPerformance?.toNumber(), |
|
|
netPerformancePercent: position.netPerformancePercentage?.toNumber(), |
|
|
netPerformancePercent: netPerformancePercentage?.toNumber(), |
|
|
netPerformancePercentWithCurrencyEffect: |
|
|
netPerformancePercentWithCurrencyEffect: |
|
|
position.netPerformancePercentageWithCurrencyEffectMap?.[ |
|
|
netPerformancePercentageWithCurrencyEffectMap?.['max']?.toNumber(), |
|
|
'max' |
|
|
|
|
|
]?.toNumber(), |
|
|
|
|
|
netPerformanceWithCurrencyEffect: |
|
|
netPerformanceWithCurrencyEffect: |
|
|
position.netPerformanceWithCurrencyEffectMap?.['max']?.toNumber(), |
|
|
netPerformanceWithCurrencyEffectMap?.['max']?.toNumber(), |
|
|
performances: { |
|
|
performances: { |
|
|
allTimeHigh: { |
|
|
allTimeHigh: { |
|
|
performancePercent, |
|
|
performancePercent, |
|
@ -922,12 +934,12 @@ export class PortfolioService { |
|
|
} else { |
|
|
} else { |
|
|
const currentData = await this.dataProviderService.getQuotes({ |
|
|
const currentData = await this.dataProviderService.getQuotes({ |
|
|
user, |
|
|
user, |
|
|
items: [{ dataSource: DataSource.YAHOO, symbol: aSymbol }] |
|
|
items: [{ symbol, dataSource: DataSource.YAHOO }] |
|
|
}); |
|
|
}); |
|
|
const marketPrice = currentData[aSymbol]?.marketPrice; |
|
|
const marketPrice = currentData[symbol]?.marketPrice; |
|
|
|
|
|
|
|
|
let historicalData = await this.dataProviderService.getHistorical( |
|
|
let historicalData = await this.dataProviderService.getHistorical( |
|
|
[{ dataSource: DataSource.YAHOO, symbol: aSymbol }], |
|
|
[{ symbol, dataSource: DataSource.YAHOO }], |
|
|
'day', |
|
|
'day', |
|
|
portfolioStart, |
|
|
portfolioStart, |
|
|
new Date() |
|
|
new Date() |
|
@ -936,15 +948,13 @@ export class PortfolioService { |
|
|
if (isEmpty(historicalData)) { |
|
|
if (isEmpty(historicalData)) { |
|
|
try { |
|
|
try { |
|
|
historicalData = await this.dataProviderService.getHistoricalRaw({ |
|
|
historicalData = await this.dataProviderService.getHistoricalRaw({ |
|
|
assetProfileIdentifiers: [ |
|
|
assetProfileIdentifiers: [{ symbol, dataSource: DataSource.YAHOO }], |
|
|
{ dataSource: DataSource.YAHOO, symbol: aSymbol } |
|
|
|
|
|
], |
|
|
|
|
|
from: portfolioStart, |
|
|
from: portfolioStart, |
|
|
to: new Date() |
|
|
to: new Date() |
|
|
}); |
|
|
}); |
|
|
} catch { |
|
|
} catch { |
|
|
historicalData = { |
|
|
historicalData = { |
|
|
[aSymbol]: {} |
|
|
[symbol]: {} |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -955,7 +965,7 @@ export class PortfolioService { |
|
|
let marketPriceMin = marketPrice; |
|
|
let marketPriceMin = marketPrice; |
|
|
|
|
|
|
|
|
for (const [date, { marketPrice }] of Object.entries( |
|
|
for (const [date, { marketPrice }] of Object.entries( |
|
|
historicalData[aSymbol] |
|
|
historicalData[symbol] |
|
|
)) { |
|
|
)) { |
|
|
historicalDataArray.push({ |
|
|
historicalDataArray.push({ |
|
|
date, |
|
|
date, |
|
@ -1116,10 +1126,14 @@ export class PortfolioService { |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public async getReport( |
|
|
public async getReport({ |
|
|
impersonationId: string |
|
|
impersonationId, |
|
|
): Promise<PortfolioReportResponse> { |
|
|
userId |
|
|
const userId = await this.getUserId(impersonationId, this.request.user.id); |
|
|
}: { |
|
|
|
|
|
impersonationId: string; |
|
|
|
|
|
userId: string; |
|
|
|
|
|
}): Promise<PortfolioReportResponse> { |
|
|
|
|
|
userId = await this.getUserId(impersonationId, userId); |
|
|
const userSettings = this.request.user.Settings.settings as UserSettings; |
|
|
const userSettings = this.request.user.Settings.settings as UserSettings; |
|
|
|
|
|
|
|
|
const { accounts, holdings, markets, marketsAdvanced, summary } = |
|
|
const { accounts, holdings, markets, marketsAdvanced, summary } = |
|
|