|
@ -7,7 +7,6 @@ import { |
|
|
MarketState, |
|
|
MarketState, |
|
|
Type |
|
|
Type |
|
|
} from '@ghostfolio/api/services/interfaces/interfaces'; |
|
|
} from '@ghostfolio/api/services/interfaces/interfaces'; |
|
|
import { resetHours } from '@ghostfolio/common/helper'; |
|
|
|
|
|
import { TimelinePosition } from '@ghostfolio/common/interfaces'; |
|
|
import { TimelinePosition } from '@ghostfolio/common/interfaces'; |
|
|
import { Currency } from '@prisma/client'; |
|
|
import { Currency } from '@prisma/client'; |
|
|
import Big from 'big.js'; |
|
|
import Big from 'big.js'; |
|
@ -21,9 +20,11 @@ import { |
|
|
isBefore, |
|
|
isBefore, |
|
|
max, |
|
|
max, |
|
|
min, |
|
|
min, |
|
|
parse |
|
|
parse, |
|
|
|
|
|
subDays |
|
|
} from 'date-fns'; |
|
|
} from 'date-fns'; |
|
|
import { flatten } from 'lodash'; |
|
|
import { flatten } from 'lodash'; |
|
|
|
|
|
import { resetHours } from '@ghostfolio/common/helper'; |
|
|
|
|
|
|
|
|
const DATE_FORMAT = 'yyyy-MM-dd'; |
|
|
const DATE_FORMAT = 'yyyy-MM-dd'; |
|
|
|
|
|
|
|
@ -127,16 +128,19 @@ export class PortfolioCalculator { |
|
|
this.transactionPoints[this.transactionPoints.length - 1]; |
|
|
this.transactionPoints[this.transactionPoints.length - 1]; |
|
|
|
|
|
|
|
|
const result: { [symbol: string]: TimelinePosition } = {}; |
|
|
const result: { [symbol: string]: TimelinePosition } = {}; |
|
|
|
|
|
const marketValues = await this.getMarketValues( |
|
|
|
|
|
lastTransactionPoint, |
|
|
|
|
|
resetHours(subDays(new Date(), 3)), |
|
|
|
|
|
endOfDay(new Date()) |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
for (const item of lastTransactionPoint.items) { |
|
|
for (const item of lastTransactionPoint.items) { |
|
|
const marketValue = await this.currentRateService.getValue({ |
|
|
const marketValue = marketValues[item.symbol]; |
|
|
date: new Date(), |
|
|
const grossPerformance = marketValue |
|
|
symbol: item.symbol, |
|
|
? new Big(marketValue.marketPrice) |
|
|
currency: item.currency, |
|
|
.mul(item.quantity) |
|
|
userCurrency: this.currency |
|
|
.minus(item.investment) |
|
|
}); |
|
|
: null; |
|
|
const grossPerformance = new Big(marketValue.marketPrice) |
|
|
|
|
|
.mul(item.quantity) |
|
|
|
|
|
.minus(item.investment); |
|
|
|
|
|
result[item.symbol] = { |
|
|
result[item.symbol] = { |
|
|
averagePrice: item.investment.div(item.quantity), |
|
|
averagePrice: item.investment.div(item.quantity), |
|
|
currency: item.currency, |
|
|
currency: item.currency, |
|
@ -145,10 +149,12 @@ export class PortfolioCalculator { |
|
|
quantity: item.quantity, |
|
|
quantity: item.quantity, |
|
|
symbol: item.symbol, |
|
|
symbol: item.symbol, |
|
|
investment: item.investment, |
|
|
investment: item.investment, |
|
|
marketPrice: marketValue.marketPrice, |
|
|
marketPrice: marketValue?.marketPrice, |
|
|
transactionCount: item.transactionCount, |
|
|
transactionCount: item.transactionCount, |
|
|
grossPerformance, |
|
|
grossPerformance, |
|
|
grossPerformancePercentage: grossPerformance.div(item.investment), |
|
|
grossPerformancePercentage: marketValue |
|
|
|
|
|
? grossPerformance.div(item.investment) |
|
|
|
|
|
: null, |
|
|
url: '', // TODO
|
|
|
url: '', // TODO
|
|
|
name: '', // TODO,
|
|
|
name: '', // TODO,
|
|
|
type: Type.Unknown // TODO
|
|
|
type: Type.Unknown // TODO
|
|
@ -228,6 +234,33 @@ export class PortfolioCalculator { |
|
|
return flatten(timelinePeriods); |
|
|
return flatten(timelinePeriods); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async getMarketValues( |
|
|
|
|
|
transactionPoint: TransactionPoint, |
|
|
|
|
|
dateRangeStart: Date, |
|
|
|
|
|
dateRangeEnd: Date |
|
|
|
|
|
) { |
|
|
|
|
|
const symbols: string[] = []; |
|
|
|
|
|
const currencies: { [symbol: string]: Currency } = {}; |
|
|
|
|
|
|
|
|
|
|
|
for (const item of transactionPoint.items) { |
|
|
|
|
|
symbols.push(item.symbol); |
|
|
|
|
|
currencies[item.symbol] = item.currency; |
|
|
|
|
|
} |
|
|
|
|
|
const values = await this.currentRateService.getValues({ |
|
|
|
|
|
dateRangeStart, |
|
|
|
|
|
dateRangeEnd, |
|
|
|
|
|
symbols, |
|
|
|
|
|
currencies, |
|
|
|
|
|
userCurrency: this.currency |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const marketValues: { [symbol: string]: GetValueObject } = {}; |
|
|
|
|
|
for (const value of values) { |
|
|
|
|
|
marketValues[value.symbol] = value; |
|
|
|
|
|
} |
|
|
|
|
|
return marketValues; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private async getTimePeriodForDate( |
|
|
private async getTimePeriodForDate( |
|
|
j: number, |
|
|
j: number, |
|
|
startDate: Date, |
|
|
startDate: Date, |
|
|