add timeline time point calculation

pull/239/head
Valentin Zickner 3 years ago committed by Thomas
parent 88f0cb095d
commit 4f7628921d

@ -1,6 +1,8 @@
import { import {
PortfolioCalculator, PortfolioCalculator,
PortfolioOrder PortfolioOrder,
TimelinePeriod,
TimelineSpecification
} from '@ghostfolio/api/app/core/portfolio-calculator'; } from '@ghostfolio/api/app/core/portfolio-calculator';
import { import {
CurrentRateService, CurrentRateService,
@ -535,6 +537,690 @@ describe('PortfolioCalculator', () => {
}); });
}); });
}); });
describe('calculate timeline', () => {
it('with yearly', async () => {
const portfolioCalculator = new PortfolioCalculator(
currentRateService,
Currency.USD
);
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
const timelineSpecification: TimelineSpecification[] = [
{
start: '2019-01-01',
accuracy: 'year'
}
];
const timeline: TimelinePeriod[] =
await portfolioCalculator.calculateTimeline(
timelineSpecification,
'2021-12-31'
);
expect(timeline).toEqual([
{
date: '2019-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-01-01',
grossPerformance: 0,
investment: 0,
value: 0
}
]);
});
it('with monthly', async () => {
const portfolioCalculator = new PortfolioCalculator(
currentRateService,
Currency.USD
);
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
const timelineSpecification: TimelineSpecification[] = [
{
start: '2019-01-01',
accuracy: 'month'
}
];
const timeline: TimelinePeriod[] =
await portfolioCalculator.calculateTimeline(
timelineSpecification,
'2021-12-31'
);
expect(timeline).toEqual([
{
date: '2019-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-02-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-03-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-04-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-05-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-06-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-07-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-08-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-09-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-10-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-11-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2019-12-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-02-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-03-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-04-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-05-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-06-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-07-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-08-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-09-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-10-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-11-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-12-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-02-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-03-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-04-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-05-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-06-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-07-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-08-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-09-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-10-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-11-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-01',
grossPerformance: 0,
investment: 0,
value: 0
}
]);
});
it('with yearly and monthly mixed', async () => {
const portfolioCalculator = new PortfolioCalculator(
currentRateService,
Currency.USD
);
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
const timelineSpecification: TimelineSpecification[] = [
{
start: '2019-01-01',
accuracy: 'year'
},
{
start: '2021-01-01',
accuracy: 'month'
}
];
const timeline: TimelinePeriod[] =
await portfolioCalculator.calculateTimeline(
timelineSpecification,
'2021-12-31'
);
expect(timeline).toEqual([
{
date: '2019-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-02-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-03-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-04-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-05-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-06-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-07-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-08-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-09-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-10-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-11-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-01',
grossPerformance: 0,
investment: 0,
value: 0
}
]);
});
it('with all mixed', async () => {
const portfolioCalculator = new PortfolioCalculator(
currentRateService,
Currency.USD
);
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
const timelineSpecification: TimelineSpecification[] = [
{
start: '2019-01-01',
accuracy: 'year'
},
{
start: '2021-01-01',
accuracy: 'month'
},
{
start: '2021-12-01',
accuracy: 'day'
}
];
const timeline: TimelinePeriod[] =
await portfolioCalculator.calculateTimeline(
timelineSpecification,
'2021-12-31'
);
expect(timeline).toEqual([
{
date: '2019-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2020-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-01-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-02-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-03-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-04-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-05-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-06-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-07-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-08-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-09-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-10-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-11-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-01',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-02',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-03',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-04',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-05',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-06',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-07',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-08',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-09',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-10',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-11',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-12',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-13',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-14',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-15',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-16',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-17',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-18',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-19',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-20',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-21',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-22',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-23',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-24',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-25',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-26',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-27',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-28',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-29',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-30',
grossPerformance: 0,
investment: 0,
value: 0
},
{
date: '2021-12-31',
grossPerformance: 0,
investment: 0,
value: 0
}
]);
});
});
}); });
const ordersMixedSymbols: PortfolioOrder[] = [ const ordersMixedSymbols: PortfolioOrder[] = [
{ {

@ -2,6 +2,17 @@ import { Currency } from '@prisma/client';
import { CurrentRateService } from '@ghostfolio/api/app/core/current-rate.service'; import { CurrentRateService } from '@ghostfolio/api/app/core/current-rate.service';
import { OrderType } from '@ghostfolio/api/models/order-type'; import { OrderType } from '@ghostfolio/api/models/order-type';
import Big from 'big.js'; import Big from 'big.js';
import {
addDays,
addMonths,
addYears,
format,
isAfter,
isBefore,
parse
} from 'date-fns';
const DATE_FORMAT = 'yyyy-MM-dd';
export class PortfolioCalculator { export class PortfolioCalculator {
private transactionPoints: TransactionPoint[]; private transactionPoints: TransactionPoint[];
@ -11,10 +22,6 @@ export class PortfolioCalculator {
private currency: Currency private currency: Currency
) {} ) {}
addOrder(order: PortfolioOrder): void {}
deleteOrder(order: PortfolioOrder): void {}
computeTransactionPoints(orders: PortfolioOrder[]) { computeTransactionPoints(orders: PortfolioOrder[]) {
orders.sort((a, b) => a.date.localeCompare(b.date)); orders.sort((a, b) => a.date.localeCompare(b.date));
@ -121,9 +128,38 @@ export class PortfolioCalculator {
calculateTimeline( calculateTimeline(
timelineSpecification: TimelineSpecification[], timelineSpecification: TimelineSpecification[],
endDate: Date endDate: string
): TimelinePeriod[] { ): TimelinePeriod[] {
return null; if (timelineSpecification.length === 0) {
return [];
}
const startDate = timelineSpecification[0].start;
const start = parse(startDate, DATE_FORMAT, new Date());
const end = parse(endDate, DATE_FORMAT, new Date());
const timelinePeriod: TimelinePeriod[] = [];
let i = 0;
for (
let currentDate = start;
!isAfter(currentDate, end);
currentDate = this.addToDate(
currentDate,
timelineSpecification[i].accuracy
)
) {
if (this.isNextItemActive(timelineSpecification, currentDate, i)) {
i++;
}
timelinePeriod.push({
date: format(currentDate, DATE_FORMAT),
grossPerformance: 0,
investment: 0,
value: 0
});
}
return timelinePeriod;
} }
private getFactor(type: OrderType) { private getFactor(type: OrderType) {
@ -141,6 +177,31 @@ export class PortfolioCalculator {
} }
return factor; return factor;
} }
private addToDate(date: Date, accurany: Accuracy): Date {
switch (accurany) {
case 'day':
return addDays(date, 1);
case 'month':
return addMonths(date, 1);
case 'year':
return addYears(date, 1);
}
}
private isNextItemActive(
timelineSpecification: TimelineSpecification[],
currentDate: Date,
i: number
) {
return (
i + 1 < timelineSpecification.length &&
!isBefore(
currentDate,
parse(timelineSpecification[i + 1].start, DATE_FORMAT, new Date())
)
);
}
} }
interface TransactionPoint { interface TransactionPoint {
@ -169,13 +230,13 @@ interface TimelinePosition {
type Accuracy = 'year' | 'month' | 'day'; type Accuracy = 'year' | 'month' | 'day';
interface TimelineSpecification { export interface TimelineSpecification {
start: Date; start: string;
accuracy: Accuracy; accuracy: Accuracy;
} }
interface TimelinePeriod { export interface TimelinePeriod {
date: Date; date: string;
grossPerformance: number; grossPerformance: number;
investment: number; investment: number;
value: number; value: number;

Loading…
Cancel
Save