fix performance of combination of investments
This commit is contained in:
parent
f9b9dc32cb
commit
9c51a257ae
@ -623,6 +623,9 @@ describe('PortfolioCalculator', () => {
|
||||
|
||||
expect(currentPositions).toEqual({
|
||||
hasErrors: false,
|
||||
currentValue: new Big('657.62'),
|
||||
grossPerformance: new Big('-61.84'),
|
||||
grossPerformancePercentage: new Big('-0.08456342256692519389'),
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('719.46'),
|
||||
@ -658,6 +661,9 @@ describe('PortfolioCalculator', () => {
|
||||
|
||||
expect(currentPositions).toEqual({
|
||||
hasErrors: false,
|
||||
currentValue: new Big('657.62'),
|
||||
grossPerformance: new Big('-61.84'),
|
||||
grossPerformancePercentage: new Big('-0.08456342256692519389'),
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('719.46'),
|
||||
@ -693,6 +699,9 @@ describe('PortfolioCalculator', () => {
|
||||
|
||||
expect(currentPositions).toEqual({
|
||||
hasErrors: false,
|
||||
currentValue: new Big('657.62'),
|
||||
grossPerformance: new Big('-9.04'),
|
||||
grossPerformancePercentage: new Big('-0.01206012060120601206'),
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('719.46'),
|
||||
@ -728,6 +737,9 @@ describe('PortfolioCalculator', () => {
|
||||
|
||||
expect(currentPositions).toEqual({
|
||||
hasErrors: false,
|
||||
currentValue: new Big('4871.5'),
|
||||
grossPerformance: new Big('240.4'),
|
||||
grossPerformancePercentage: new Big('0.08908669575467971768'),
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('178.438'),
|
||||
@ -805,6 +817,9 @@ describe('PortfolioCalculator', () => {
|
||||
spy.mockRestore();
|
||||
expect(currentPositions).toEqual({
|
||||
hasErrors: false,
|
||||
currentValue: new Big('3897.2'),
|
||||
grossPerformance: new Big('303.2'),
|
||||
grossPerformancePercentage: new Big('0.2759628350186678759'),
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('146.185'),
|
||||
@ -875,6 +890,9 @@ describe('PortfolioCalculator', () => {
|
||||
|
||||
expect(currentPositions).toEqual({
|
||||
hasErrors: false,
|
||||
currentValue: new Big('1192327.999656600298238721'),
|
||||
grossPerformance: new Big('92327.999656600898394721'),
|
||||
grossPerformancePercentage: new Big('0.09788598099999947809'),
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('1.01287018290924923237'), // 1'100'000 / 1'086'022.689344542
|
||||
|
@ -114,11 +114,17 @@ export class PortfolioCalculator {
|
||||
public async getCurrentPositions(start: Date): Promise<{
|
||||
hasErrors: boolean;
|
||||
positions: TimelinePosition[];
|
||||
grossPerformance: Big;
|
||||
grossPerformancePercentage: Big;
|
||||
currentValue: Big;
|
||||
}> {
|
||||
if (!this.transactionPoints?.length) {
|
||||
return {
|
||||
hasErrors: false,
|
||||
positions: []
|
||||
positions: [],
|
||||
grossPerformance: new Big(0),
|
||||
grossPerformancePercentage: new Big(0),
|
||||
currentValue: new Big(0)
|
||||
};
|
||||
}
|
||||
|
||||
@ -197,6 +203,8 @@ export class PortfolioCalculator {
|
||||
const invalidSymbols = [];
|
||||
const lastInvestments: { [symbol: string]: Big } = {};
|
||||
const lastQuantities: { [symbol: string]: Big } = {};
|
||||
const initialValues: { [symbol: string]: Big } = {};
|
||||
|
||||
for (let i = firstIndex; i < this.transactionPoints.length; i++) {
|
||||
const currentDate =
|
||||
i === firstIndex ? startString : this.transactionPoints[i].date;
|
||||
@ -233,6 +241,9 @@ export class PortfolioCalculator {
|
||||
initialValue = item.investment;
|
||||
investedValue = item.investment;
|
||||
}
|
||||
if (i === firstIndex || !initialValues[item.symbol]) {
|
||||
initialValues[item.symbol] = initialValue;
|
||||
}
|
||||
if (!initialValue) {
|
||||
invalidSymbols.push(item.symbol);
|
||||
hasErrors = true;
|
||||
@ -287,7 +298,48 @@ export class PortfolioCalculator {
|
||||
});
|
||||
}
|
||||
|
||||
return { hasErrors, positions };
|
||||
let currentValue = new Big(0);
|
||||
let overallGrossPerformance = new Big(0);
|
||||
let grossPerformancePercentage = new Big(1);
|
||||
let completeInitialValue = new Big(0);
|
||||
for (const currentPosition of positions) {
|
||||
currentValue = currentValue.add(
|
||||
new Big(currentPosition.marketPrice).mul(currentPosition.quantity)
|
||||
);
|
||||
if (currentPosition.grossPerformance) {
|
||||
overallGrossPerformance = overallGrossPerformance.plus(
|
||||
currentPosition.grossPerformance
|
||||
);
|
||||
} else {
|
||||
hasErrors = true;
|
||||
}
|
||||
if (
|
||||
currentPosition.grossPerformancePercentage &&
|
||||
initialValues[currentPosition.symbol]
|
||||
) {
|
||||
const currentInitialValue = initialValues[currentPosition.symbol];
|
||||
completeInitialValue = completeInitialValue.plus(currentInitialValue);
|
||||
grossPerformancePercentage = grossPerformancePercentage.plus(
|
||||
currentPosition.grossPerformancePercentage.mul(currentInitialValue)
|
||||
);
|
||||
} else {
|
||||
console.log(initialValues);
|
||||
console.error(
|
||||
'initial value is missing for symbol',
|
||||
currentPosition.symbol
|
||||
);
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hasErrors,
|
||||
positions,
|
||||
grossPerformance: overallGrossPerformance,
|
||||
grossPerformancePercentage:
|
||||
grossPerformancePercentage.div(completeInitialValue),
|
||||
currentValue
|
||||
};
|
||||
}
|
||||
|
||||
public async calculateTimeline(
|
||||
|
@ -484,34 +484,12 @@ export class PortfolioService {
|
||||
startDate
|
||||
);
|
||||
|
||||
let currentValue = new Big(0);
|
||||
let grossPerformance = new Big(0);
|
||||
let grossPerformancePercentage = new Big(1);
|
||||
let hasErrors = false;
|
||||
for (const currentPosition of currentPositions.positions) {
|
||||
currentValue = currentValue.add(
|
||||
new Big(currentPosition.marketPrice).mul(currentPosition.quantity)
|
||||
);
|
||||
if (currentPosition.grossPerformance) {
|
||||
grossPerformance = grossPerformance.plus(
|
||||
currentPosition.grossPerformance
|
||||
);
|
||||
} else {
|
||||
hasErrors = true;
|
||||
}
|
||||
if (currentPosition.grossPerformancePercentage) {
|
||||
grossPerformancePercentage = grossPerformancePercentage.mul(
|
||||
currentPosition.grossPerformancePercentage.plus(1)
|
||||
);
|
||||
} else {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
const currentGrossPerformance = grossPerformance.toNumber();
|
||||
const currentGrossPerformancePercent = grossPerformancePercentage
|
||||
.minus(1)
|
||||
.toNumber();
|
||||
const hasErrors = currentPositions.hasErrors;
|
||||
const currentValue = currentPositions.currentValue.toNumber();
|
||||
const currentGrossPerformance =
|
||||
currentPositions.grossPerformance.toNumber();
|
||||
const currentGrossPerformancePercent =
|
||||
currentPositions.grossPerformancePercentage.toNumber();
|
||||
return {
|
||||
hasErrors: currentPositions.hasErrors || hasErrors,
|
||||
performance: {
|
||||
@ -520,7 +498,7 @@ export class PortfolioService {
|
||||
// TODO: the next two should include fees
|
||||
currentNetPerformance: currentGrossPerformance,
|
||||
currentNetPerformancePercent: currentGrossPerformancePercent,
|
||||
currentValue: currentValue.toNumber()
|
||||
currentValue: currentValue
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user