|
|
@ -321,9 +321,44 @@ export class PortfolioService { |
|
|
|
aSymbol: string |
|
|
|
): Promise<PortfolioPositionDetail> { |
|
|
|
const userId = await this.getUserId(aImpersonationId); |
|
|
|
const portfolio = await this.createPortfolio(userId); |
|
|
|
|
|
|
|
const position = portfolio.getPositions(new Date())[aSymbol]; |
|
|
|
const portfolioCalculator = new PortfolioCalculator( |
|
|
|
this.currentRateService, |
|
|
|
this.request.user.Settings.currency |
|
|
|
); |
|
|
|
|
|
|
|
const { transactionPoints, orders } = await this.getTransactionPoints( |
|
|
|
userId |
|
|
|
); |
|
|
|
|
|
|
|
if (transactionPoints?.length <= 0) { |
|
|
|
return { |
|
|
|
averagePrice: undefined, |
|
|
|
currency: undefined, |
|
|
|
firstBuyDate: undefined, |
|
|
|
grossPerformance: undefined, |
|
|
|
grossPerformancePercent: undefined, |
|
|
|
historicalData: [], |
|
|
|
investment: undefined, |
|
|
|
marketPrice: undefined, |
|
|
|
maxPrice: undefined, |
|
|
|
minPrice: undefined, |
|
|
|
quantity: undefined, |
|
|
|
symbol: aSymbol, |
|
|
|
transactionCount: undefined |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
portfolioCalculator.setTransactionPoints(transactionPoints); |
|
|
|
|
|
|
|
const portfolioStart = parseDate(transactionPoints[0].date); |
|
|
|
const currentPositions = await portfolioCalculator.getCurrentPositions( |
|
|
|
portfolioStart |
|
|
|
); |
|
|
|
|
|
|
|
const position = currentPositions.positions.find( |
|
|
|
(item) => item.symbol === aSymbol |
|
|
|
); |
|
|
|
|
|
|
|
if (position) { |
|
|
|
const { |
|
|
@ -331,11 +366,10 @@ export class PortfolioService { |
|
|
|
currency, |
|
|
|
firstBuyDate, |
|
|
|
investment, |
|
|
|
marketPrice, |
|
|
|
quantity, |
|
|
|
transactionCount |
|
|
|
} = position; |
|
|
|
let marketPrice = position.marketPrice; |
|
|
|
const orders = portfolio.getOrders(aSymbol); |
|
|
|
|
|
|
|
const historicalData = await this.dataProviderService.getHistorical( |
|
|
|
[aSymbol], |
|
|
@ -344,33 +378,29 @@ export class PortfolioService { |
|
|
|
new Date() |
|
|
|
); |
|
|
|
|
|
|
|
if (marketPrice === 0) { |
|
|
|
marketPrice = averagePrice; |
|
|
|
} |
|
|
|
|
|
|
|
const historicalDataArray: HistoricalDataItem[] = []; |
|
|
|
let currentAveragePrice: number; |
|
|
|
let maxPrice = marketPrice; |
|
|
|
let minPrice = marketPrice; |
|
|
|
|
|
|
|
if (historicalData[aSymbol]) { |
|
|
|
let j = -1; |
|
|
|
for (const [date, { marketPrice }] of Object.entries( |
|
|
|
historicalData[aSymbol] |
|
|
|
)) { |
|
|
|
const currentDate = parse(date, DATE_FORMAT, new Date()); |
|
|
|
if ( |
|
|
|
isSameDay(currentDate, parseISO(orders[0]?.getDate())) || |
|
|
|
isAfter(currentDate, parseISO(orders[0]?.getDate())) |
|
|
|
while ( |
|
|
|
j + 1 < transactionPoints.length && |
|
|
|
!isAfter(parseDate(transactionPoints[j + 1].date), parseDate(date)) |
|
|
|
) { |
|
|
|
// Get snapshot of first day of next month
|
|
|
|
const snapshot = portfolio.get( |
|
|
|
addMonths(setDate(currentDate, 1), 1) |
|
|
|
)?.[0]?.positions[aSymbol]; |
|
|
|
orders.shift(); |
|
|
|
|
|
|
|
if (snapshot?.averagePrice) { |
|
|
|
currentAveragePrice = snapshot.averagePrice; |
|
|
|
j++; |
|
|
|
} |
|
|
|
let currentAveragePrice = 0; |
|
|
|
const currentSymbol = transactionPoints[j].items.find( |
|
|
|
(item) => item.symbol === aSymbol |
|
|
|
); |
|
|
|
if (currentSymbol) { |
|
|
|
currentAveragePrice = currentSymbol.investment |
|
|
|
.div(currentSymbol.quantity) |
|
|
|
.toNumber(); |
|
|
|
} |
|
|
|
|
|
|
|
historicalDataArray.push({ |
|
|
@ -379,58 +409,40 @@ export class PortfolioService { |
|
|
|
value: marketPrice |
|
|
|
}); |
|
|
|
|
|
|
|
if ( |
|
|
|
marketPrice && |
|
|
|
(marketPrice > maxPrice || maxPrice === undefined) |
|
|
|
) { |
|
|
|
maxPrice = marketPrice; |
|
|
|
} |
|
|
|
|
|
|
|
if ( |
|
|
|
marketPrice && |
|
|
|
(marketPrice < minPrice || minPrice === undefined) |
|
|
|
) { |
|
|
|
minPrice = marketPrice; |
|
|
|
} |
|
|
|
maxPrice = Math.max(marketPrice ?? 0, maxPrice); |
|
|
|
minPrice = Math.min(marketPrice ?? Number.MAX_SAFE_INTEGER, minPrice); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
|
averagePrice, |
|
|
|
averagePrice: averagePrice.toNumber(), |
|
|
|
currency, |
|
|
|
firstBuyDate, |
|
|
|
investment, |
|
|
|
investment: investment.toNumber(), |
|
|
|
marketPrice, |
|
|
|
maxPrice, |
|
|
|
minPrice, |
|
|
|
quantity, |
|
|
|
quantity: quantity.toNumber(), |
|
|
|
transactionCount, |
|
|
|
grossPerformance: this.exchangeRateDataService.toCurrency( |
|
|
|
marketPrice - averagePrice, |
|
|
|
currency, |
|
|
|
this.request.user.Settings.currency |
|
|
|
), |
|
|
|
grossPerformancePercent: roundTo( |
|
|
|
(marketPrice - averagePrice) / averagePrice, |
|
|
|
4 |
|
|
|
), |
|
|
|
grossPerformance: position.grossPerformance.toNumber(), |
|
|
|
grossPerformancePercent: position.grossPerformancePercentage.toNumber(), |
|
|
|
historicalData: historicalDataArray, |
|
|
|
symbol: aSymbol |
|
|
|
}; |
|
|
|
} else if (portfolio.getMinDate()) { |
|
|
|
} else { |
|
|
|
const currentData = await this.dataProviderService.get([aSymbol]); |
|
|
|
|
|
|
|
let historicalData = await this.dataProviderService.getHistorical( |
|
|
|
[aSymbol], |
|
|
|
'day', |
|
|
|
portfolio.getMinDate(), |
|
|
|
portfolioStart, |
|
|
|
new Date() |
|
|
|
); |
|
|
|
|
|
|
|
if (isEmpty(historicalData)) { |
|
|
|
historicalData = await this.dataProviderService.getHistoricalRaw( |
|
|
|
[{ dataSource: DataSource.YAHOO, symbol: aSymbol }], |
|
|
|
portfolio.getMinDate(), |
|
|
|
portfolioStart, |
|
|
|
new Date() |
|
|
|
); |
|
|
|
} |
|
|
@ -462,22 +474,6 @@ export class PortfolioService { |
|
|
|
transactionCount: undefined |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
|
averagePrice: undefined, |
|
|
|
currency: undefined, |
|
|
|
firstBuyDate: undefined, |
|
|
|
grossPerformance: undefined, |
|
|
|
grossPerformancePercent: undefined, |
|
|
|
historicalData: [], |
|
|
|
investment: undefined, |
|
|
|
marketPrice: undefined, |
|
|
|
maxPrice: undefined, |
|
|
|
minPrice: undefined, |
|
|
|
quantity: undefined, |
|
|
|
symbol: aSymbol, |
|
|
|
transactionCount: undefined |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public async getPositions( |
|
|
|