|
@ -390,13 +390,11 @@ export class PortfolioCalculator { |
|
|
? format(previousDate, DATE_FORMAT) |
|
|
? format(previousDate, DATE_FORMAT) |
|
|
: null; |
|
|
: null; |
|
|
let totalCurrentValue = new Big(0); |
|
|
let totalCurrentValue = new Big(0); |
|
|
let maxTotalInvestmentValue = new Big(0); |
|
|
|
|
|
let previousTotalInvestmentValue = new Big(0); |
|
|
let previousTotalInvestmentValue = new Big(0); |
|
|
let timeWeightedPerformance = new Big(0); |
|
|
|
|
|
|
|
|
|
|
|
if (calculateTimeWeightedPerformance && previousDateString) { |
|
|
if (calculateTimeWeightedPerformance && previousDateString) { |
|
|
previousTotalInvestmentValue = |
|
|
previousTotalInvestmentValue = |
|
|
accumulatedValuesByDate[previousDateString].totalInvestmentValue; |
|
|
accumulatedValuesByDate[previousDateString].totalCurrentValue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (const symbol of Object.keys(valuesBySymbol)) { |
|
|
for (const symbol of Object.keys(valuesBySymbol)) { |
|
@ -406,6 +404,8 @@ export class PortfolioCalculator { |
|
|
|
|
|
|
|
|
totalCurrentValue = totalCurrentValue.plus(symbolCurrentValues); |
|
|
totalCurrentValue = totalCurrentValue.plus(symbolCurrentValues); |
|
|
|
|
|
|
|
|
|
|
|
let timeWeightedPerformanceContribution = new Big(0); |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
previousTotalInvestmentValue.toNumber() && |
|
|
previousTotalInvestmentValue.toNumber() && |
|
|
symbolValues.netPerformanceValuesPercentage && |
|
|
symbolValues.netPerformanceValuesPercentage && |
|
@ -418,26 +418,16 @@ export class PortfolioCalculator { |
|
|
const netPerformance = |
|
|
const netPerformance = |
|
|
symbolValues.netPerformanceValuesPercentage?.[dateString] ?? |
|
|
symbolValues.netPerformanceValuesPercentage?.[dateString] ?? |
|
|
new Big(0); |
|
|
new Big(0); |
|
|
const timeWeightedPerformanceContribution = previousValue |
|
|
timeWeightedPerformanceContribution = previousValue |
|
|
.div(previousTotalInvestmentValue) |
|
|
.div(previousTotalInvestmentValue) |
|
|
.mul(netPerformance) |
|
|
.mul(netPerformance); |
|
|
.mul(100); |
|
|
|
|
|
timeWeightedPerformance = timeWeightedPerformance.plus( |
|
|
|
|
|
timeWeightedPerformanceContribution |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let totalTimeWeightedPerformance = timeWeightedPerformance.plus( |
|
|
|
|
|
accumulatedValuesByDate[previousDateString] |
|
|
|
|
|
?.totalTimeWeightedPerformance ?? new Big(0) |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
accumulatedValuesByDate = this.accumulatedValuesByDate( |
|
|
accumulatedValuesByDate = this.accumulatedValuesByDate( |
|
|
valuesBySymbol, |
|
|
valuesBySymbol, |
|
|
symbol, |
|
|
symbol, |
|
|
dateString, |
|
|
dateString, |
|
|
accumulatedValuesByDate, |
|
|
accumulatedValuesByDate, |
|
|
totalTimeWeightedPerformance |
|
|
timeWeightedPerformanceContribution |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -453,6 +443,19 @@ export class PortfolioCalculator { |
|
|
totalNetPerformanceValue |
|
|
totalNetPerformanceValue |
|
|
} = accumulatedValuesByDate[dateString]; |
|
|
} = accumulatedValuesByDate[dateString]; |
|
|
|
|
|
|
|
|
|
|
|
let totalNetTimeWeightedPerformance = new Big(0); |
|
|
|
|
|
|
|
|
|
|
|
if (previousDateString) { |
|
|
|
|
|
totalNetTimeWeightedPerformance = ( |
|
|
|
|
|
accumulatedValuesByDate[previousDateString] |
|
|
|
|
|
?.totalTimeWeightedPerformance ?? new Big(0) |
|
|
|
|
|
) |
|
|
|
|
|
.plus(1) |
|
|
|
|
|
.mul(totalTimeWeightedPerformance.plus(1)) |
|
|
|
|
|
.minus(1) |
|
|
|
|
|
.mul(100); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const netPerformanceInPercentage = totalTimeWeightedInvestmentValue.eq(0) |
|
|
const netPerformanceInPercentage = totalTimeWeightedInvestmentValue.eq(0) |
|
|
? 0 |
|
|
? 0 |
|
|
: totalNetPerformanceValue |
|
|
: totalNetPerformanceValue |
|
@ -476,7 +479,7 @@ export class PortfolioCalculator { |
|
|
totalInvestment: totalInvestmentValue.toNumber(), |
|
|
totalInvestment: totalInvestmentValue.toNumber(), |
|
|
value: totalCurrentValue.toNumber(), |
|
|
value: totalCurrentValue.toNumber(), |
|
|
valueWithCurrencyEffect: totalCurrentValueWithCurrencyEffect.toNumber(), |
|
|
valueWithCurrencyEffect: totalCurrentValueWithCurrencyEffect.toNumber(), |
|
|
timeWeightedPerformance: totalTimeWeightedPerformance.toNumber(), |
|
|
timeWeightedPerformance: totalNetTimeWeightedPerformance.toNumber(), |
|
|
investmentValueWithCurrencyEffect: |
|
|
investmentValueWithCurrencyEffect: |
|
|
investmentValueWithCurrencyEffect.toNumber(), |
|
|
investmentValueWithCurrencyEffect.toNumber(), |
|
|
netPerformanceWithCurrencyEffect: |
|
|
netPerformanceWithCurrencyEffect: |
|
@ -589,7 +592,10 @@ export class PortfolioCalculator { |
|
|
accumulatedValuesByDate[dateString] |
|
|
accumulatedValuesByDate[dateString] |
|
|
?.totalTimeWeightedInvestmentValueWithCurrencyEffect ?? new Big(0) |
|
|
?.totalTimeWeightedInvestmentValueWithCurrencyEffect ?? new Big(0) |
|
|
).add(timeWeightedInvestmentValueWithCurrencyEffect), |
|
|
).add(timeWeightedInvestmentValueWithCurrencyEffect), |
|
|
totalTimeWeightedPerformance: timeWeightedPerformance |
|
|
totalTimeWeightedPerformance: ( |
|
|
|
|
|
accumulatedValuesByDate[dateString]?.totalTimeWeightedPerformance ?? |
|
|
|
|
|
new Big(0) |
|
|
|
|
|
).add(timeWeightedPerformance) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
return accumulatedValuesByDate; |
|
|
return accumulatedValuesByDate; |
|
@ -1162,78 +1168,55 @@ export class PortfolioCalculator { |
|
|
symbol: string; |
|
|
symbol: string; |
|
|
calculatePerformance?: boolean; |
|
|
calculatePerformance?: boolean; |
|
|
}): SymbolMetrics { |
|
|
}): SymbolMetrics { |
|
|
const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; |
|
|
let { |
|
|
const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = { |
|
|
averagePriceAtStartDate, |
|
|
Value: {}, |
|
|
totalUnits, |
|
|
WithCurrencyEffect: {} |
|
|
totalInvestment, |
|
|
}; |
|
|
investmentAtStartDate, |
|
|
let fees: WithCurrencyEffect<Big> = { |
|
|
valueAtStartDate, |
|
|
Value: new Big(0), |
|
|
maxTotalInvestment, |
|
|
WithCurrencyEffect: new Big(0) |
|
|
averagePriceAtEndDate, |
|
|
}; |
|
|
initialValue, |
|
|
let feesAtStartDate: WithCurrencyEffect<Big> = { |
|
|
fees, |
|
|
Value: new Big(0), |
|
|
feesAtStartDate, |
|
|
WithCurrencyEffect: new Big(0) |
|
|
lastAveragePrice, |
|
|
}; |
|
|
grossPerformanceFromSells, |
|
|
let grossPerformance: WithCurrencyEffect<Big> = { |
|
|
totalInvestmentWithGrossPerformanceFromSell, |
|
|
Value: new Big(0), |
|
|
grossPerformance, |
|
|
WithCurrencyEffect: new Big(0) |
|
|
grossPerformanceAtStartDate, |
|
|
}; |
|
|
currentValues, |
|
|
let grossPerformanceAtStartDate: WithCurrencyEffect<Big> = { |
|
|
netPerformanceValues, |
|
|
Value: new Big(0), |
|
|
netPerformanceValuesPercentage, |
|
|
WithCurrencyEffect: new Big(0) |
|
|
investmentValues, |
|
|
}; |
|
|
investmentValuesAccumulated, |
|
|
let grossPerformanceFromSells: WithCurrencyEffect<Big> = { |
|
|
maxInvestmentValues, |
|
|
Value: new Big(0), |
|
|
timeWeightedInvestmentValues |
|
|
WithCurrencyEffect: new Big(0) |
|
|
}: { |
|
|
}; |
|
|
averagePriceAtStartDate: Big; |
|
|
let averagePriceAtEndDate = new Big(0); |
|
|
totalUnits: Big; |
|
|
let averagePriceAtStartDate = new Big(0); |
|
|
totalInvestment: WithCurrencyEffect<Big>; |
|
|
const investmentValues: WithCurrencyEffect<{ [date: string]: Big }> = { |
|
|
investmentAtStartDate: any; |
|
|
Value: {}, |
|
|
valueAtStartDate: WithCurrencyEffect<Big>; |
|
|
WithCurrencyEffect: {} |
|
|
maxTotalInvestment: Big; |
|
|
}; |
|
|
averagePriceAtEndDate: Big; |
|
|
const maxInvestmentValues: { [date: string]: Big } = {}; |
|
|
initialValue: any; |
|
|
let maxTotalInvestment = new Big(0); |
|
|
fees: WithCurrencyEffect<Big>; |
|
|
const netPerformanceValuesPercentage: { [date: string]: Big } = {}; |
|
|
feesAtStartDate: WithCurrencyEffect<Big>; |
|
|
let initialValue; |
|
|
lastAveragePrice: WithCurrencyEffect<Big>; |
|
|
let investmentAtStartDate; |
|
|
grossPerformanceFromSells: WithCurrencyEffect<Big>; |
|
|
const investmentValuesAccumulated: WithCurrencyEffect<{ |
|
|
totalInvestmentWithGrossPerformanceFromSell: WithCurrencyEffect<Big>; |
|
|
[date: string]: Big; |
|
|
grossPerformance: WithCurrencyEffect<Big>; |
|
|
}> = { |
|
|
grossPerformanceAtStartDate: WithCurrencyEffect<Big>; |
|
|
Value: {}, |
|
|
currentValues: WithCurrencyEffect<{ [date: string]: Big }>; |
|
|
WithCurrencyEffect: {} |
|
|
netPerformanceValues: WithCurrencyEffect<{ [date: string]: Big }>; |
|
|
}; |
|
|
netPerformanceValuesPercentage: { [date: string]: Big }; |
|
|
let lastAveragePrice: WithCurrencyEffect<Big> = { |
|
|
investmentValues: WithCurrencyEffect<{ [date: string]: Big }>; |
|
|
Value: new Big(0), |
|
|
investmentValuesAccumulated: WithCurrencyEffect<{ [date: string]: Big }>; |
|
|
WithCurrencyEffect: new Big(0) |
|
|
maxInvestmentValues: { [date: string]: Big }; |
|
|
}; |
|
|
timeWeightedInvestmentValues: WithCurrencyEffect<{ [date: string]: Big }>; |
|
|
const netPerformanceValues: WithCurrencyEffect<{ [date: string]: Big }> = { |
|
|
} = this.InitializeSymbolMetricValues(); |
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
const timeWeightedInvestmentValues: WithCurrencyEffect<{ |
|
|
|
|
|
[date: string]: Big; |
|
|
|
|
|
}> = { |
|
|
|
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let totalInvestment: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let totalInvestmentWithGrossPerformanceFromSell: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let totalUnits = new Big(0); |
|
|
const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; |
|
|
let valueAtStartDate: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Clone orders to keep the original values in this.orders
|
|
|
// Clone orders to keep the original values in this.orders
|
|
|
let orders: PortfolioOrderItem[] = cloneDeep(this.orders).filter( |
|
|
let orders: PortfolioOrderItem[] = cloneDeep(this.orders).filter( |
|
@ -1426,6 +1409,104 @@ export class PortfolioCalculator { |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private InitializeSymbolMetricValues() { |
|
|
|
|
|
const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = { |
|
|
|
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
let fees: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
let feesAtStartDate: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
let grossPerformance: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
let grossPerformanceAtStartDate: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
let grossPerformanceFromSells: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
let averagePriceAtEndDate = new Big(0); |
|
|
|
|
|
let averagePriceAtStartDate = new Big(0); |
|
|
|
|
|
const investmentValues: WithCurrencyEffect<{ [date: string]: Big }> = { |
|
|
|
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
const maxInvestmentValues: { [date: string]: Big } = {}; |
|
|
|
|
|
let maxTotalInvestment = new Big(0); |
|
|
|
|
|
const netPerformanceValuesPercentage: { [date: string]: Big } = {}; |
|
|
|
|
|
let initialValue; |
|
|
|
|
|
let investmentAtStartDate; |
|
|
|
|
|
const investmentValuesAccumulated: WithCurrencyEffect<{ |
|
|
|
|
|
[date: string]: Big; |
|
|
|
|
|
}> = { |
|
|
|
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
let lastAveragePrice: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
const netPerformanceValues: WithCurrencyEffect<{ [date: string]: Big }> = { |
|
|
|
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
const timeWeightedInvestmentValues: WithCurrencyEffect<{ |
|
|
|
|
|
[date: string]: Big; |
|
|
|
|
|
}> = { |
|
|
|
|
|
Value: {}, |
|
|
|
|
|
WithCurrencyEffect: {} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let totalInvestment: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let totalInvestmentWithGrossPerformanceFromSell: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let totalUnits = new Big(0); |
|
|
|
|
|
let valueAtStartDate: WithCurrencyEffect<Big> = { |
|
|
|
|
|
Value: new Big(0), |
|
|
|
|
|
WithCurrencyEffect: new Big(0) |
|
|
|
|
|
}; |
|
|
|
|
|
return { |
|
|
|
|
|
averagePriceAtStartDate, |
|
|
|
|
|
totalUnits, |
|
|
|
|
|
totalInvestment, |
|
|
|
|
|
investmentAtStartDate, |
|
|
|
|
|
valueAtStartDate, |
|
|
|
|
|
maxTotalInvestment, |
|
|
|
|
|
averagePriceAtEndDate, |
|
|
|
|
|
initialValue, |
|
|
|
|
|
fees, |
|
|
|
|
|
feesAtStartDate, |
|
|
|
|
|
lastAveragePrice, |
|
|
|
|
|
grossPerformanceFromSells, |
|
|
|
|
|
totalInvestmentWithGrossPerformanceFromSell, |
|
|
|
|
|
grossPerformance, |
|
|
|
|
|
grossPerformanceAtStartDate, |
|
|
|
|
|
currentValues, |
|
|
|
|
|
netPerformanceValues, |
|
|
|
|
|
netPerformanceValuesPercentage, |
|
|
|
|
|
investmentValues, |
|
|
|
|
|
investmentValuesAccumulated, |
|
|
|
|
|
maxInvestmentValues, |
|
|
|
|
|
timeWeightedInvestmentValues |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@LogPerformance |
|
|
@LogPerformance |
|
|
private calculatePerformanceOfSymbol( |
|
|
private calculatePerformanceOfSymbol( |
|
|
orders: PortfolioOrderItem[], |
|
|
orders: PortfolioOrderItem[], |
|
|