pull/239/head
Thomas 3 years ago
parent e0435e5cad
commit ee89822bfe

@ -7,7 +7,8 @@ import {
PortfolioCalculator,
PortfolioOrder,
TimelinePeriod,
TimelineSpecification
TimelineSpecification,
TransactionPoint
} from '@ghostfolio/api/app/core/portfolio-calculator';
import { OrderType } from '@ghostfolio/api/models/order-type';
import { resetHours } from '@ghostfolio/common/helper';
@ -129,6 +130,7 @@ describe('PortfolioCalculator', () => {
...ordersVTI,
{
date: '2021-02-01',
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
type: OrderType.Buy,
@ -149,6 +151,7 @@ describe('PortfolioCalculator', () => {
date: '2019-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
investment: new Big('1443.8'),
@ -162,6 +165,7 @@ describe('PortfolioCalculator', () => {
date: '2019-08-03',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
investment: new Big('2923.7'),
@ -175,6 +179,7 @@ describe('PortfolioCalculator', () => {
date: '2020-02-02',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('5'),
symbol: 'VTI',
investment: new Big('652.55'),
@ -188,6 +193,7 @@ describe('PortfolioCalculator', () => {
date: '2021-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('35'),
symbol: 'VTI',
investment: new Big('6627.05'),
@ -201,6 +207,7 @@ describe('PortfolioCalculator', () => {
date: '2021-08-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('45'),
symbol: 'VTI',
investment: new Big('8403.95'),
@ -218,6 +225,7 @@ describe('PortfolioCalculator', () => {
...ordersVTI,
{
date: '2019-09-01',
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
type: OrderType.Buy,
@ -238,6 +246,7 @@ describe('PortfolioCalculator', () => {
date: '2019-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
investment: new Big('1443.8'),
@ -251,6 +260,7 @@ describe('PortfolioCalculator', () => {
date: '2019-08-03',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
investment: new Big('2923.7'),
@ -264,6 +274,7 @@ describe('PortfolioCalculator', () => {
date: '2019-09-01',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -272,6 +283,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
investment: new Big('2923.7'),
@ -285,6 +297,7 @@ describe('PortfolioCalculator', () => {
date: '2020-02-02',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -293,6 +306,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('5'),
symbol: 'VTI',
investment: new Big('652.55'),
@ -306,6 +320,7 @@ describe('PortfolioCalculator', () => {
date: '2021-02-01',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -314,6 +329,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('15'),
symbol: 'VTI',
investment: new Big('2684.05'),
@ -327,6 +343,7 @@ describe('PortfolioCalculator', () => {
date: '2021-08-01',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -335,6 +352,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('25'),
symbol: 'VTI',
investment: new Big('4460.95'),
@ -352,6 +370,7 @@ describe('PortfolioCalculator', () => {
...ordersVTI,
{
date: '2019-09-01',
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
type: OrderType.Buy,
@ -360,6 +379,7 @@ describe('PortfolioCalculator', () => {
},
{
date: '2020-08-02',
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
type: OrderType.Sell,
@ -380,6 +400,7 @@ describe('PortfolioCalculator', () => {
date: '2019-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
investment: new Big('1443.8'),
@ -393,6 +414,7 @@ describe('PortfolioCalculator', () => {
date: '2019-08-03',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
investment: new Big('2923.7'),
@ -406,6 +428,7 @@ describe('PortfolioCalculator', () => {
date: '2019-09-01',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -414,6 +437,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
investment: new Big('2923.7'),
@ -427,6 +451,7 @@ describe('PortfolioCalculator', () => {
date: '2020-02-02',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -435,6 +460,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('5'),
symbol: 'VTI',
investment: new Big('652.55'),
@ -448,6 +474,7 @@ describe('PortfolioCalculator', () => {
date: '2020-08-02',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('5'),
symbol: 'VTI',
investment: new Big('652.55'),
@ -461,6 +488,7 @@ describe('PortfolioCalculator', () => {
date: '2021-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('15'),
symbol: 'VTI',
investment: new Big('2684.05'),
@ -474,6 +502,7 @@ describe('PortfolioCalculator', () => {
date: '2021-08-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('25'),
symbol: 'VTI',
investment: new Big('4460.95'),
@ -500,6 +529,7 @@ describe('PortfolioCalculator', () => {
date: '2017-01-03',
items: [
{
name: 'Tesla, Inc.',
quantity: new Big('50'),
symbol: 'TSLA',
investment: new Big('2148.5'),
@ -513,6 +543,7 @@ describe('PortfolioCalculator', () => {
date: '2017-07-01',
items: [
{
name: 'Bitcoin USD',
quantity: new Big('0.5614682'),
symbol: 'BTCUSD',
investment: new Big('1999.9999999999998659756'),
@ -521,6 +552,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Tesla, Inc.',
quantity: new Big('50'),
symbol: 'TSLA',
investment: new Big('2148.5'),
@ -534,6 +566,7 @@ describe('PortfolioCalculator', () => {
date: '2018-09-01',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -542,6 +575,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Bitcoin USD',
quantity: new Big('0.5614682'),
symbol: 'BTCUSD',
investment: new Big('1999.9999999999998659756'),
@ -550,6 +584,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Tesla, Inc.',
quantity: new Big('50'),
symbol: 'TSLA',
investment: new Big('2148.5'),
@ -582,6 +617,7 @@ describe('PortfolioCalculator', () => {
grossPerformancePercentage: new Big('0.19548526659119694236'), // 872.05/4460.95
investment: new Big('4460.95'),
marketPrice: 213.32,
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('25'),
symbol: 'VTI',
transactionCount: 5
@ -1171,6 +1207,7 @@ describe('PortfolioCalculator', () => {
date: '2019-02-01',
items: [
{
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
investment: new Big('10109.95'),
@ -1179,6 +1216,7 @@ describe('PortfolioCalculator', () => {
transactionCount: 1
},
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
investment: new Big('1443.8'),
@ -1221,6 +1259,7 @@ describe('PortfolioCalculator', () => {
const ordersMixedSymbols: PortfolioOrder[] = [
{
date: '2017-01-03',
name: 'Tesla, Inc.',
quantity: new Big('50'),
symbol: 'TSLA',
type: OrderType.Buy,
@ -1229,6 +1268,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [
},
{
date: '2017-07-01',
name: 'Bitcoin USD',
quantity: new Big('0.5614682'),
symbol: 'BTCUSD',
type: OrderType.Buy,
@ -1237,6 +1277,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [
},
{
date: '2018-09-01',
name: 'Amazon.com, Inc.',
quantity: new Big('5'),
symbol: 'AMZN',
type: OrderType.Buy,
@ -1248,6 +1289,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [
const ordersVTI: PortfolioOrder[] = [
{
date: '2019-02-01',
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
type: OrderType.Buy,
@ -1256,6 +1298,7 @@ const ordersVTI: PortfolioOrder[] = [
},
{
date: '2019-08-03',
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
type: OrderType.Buy,
@ -1264,6 +1307,7 @@ const ordersVTI: PortfolioOrder[] = [
},
{
date: '2020-02-02',
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('15'),
symbol: 'VTI',
type: OrderType.Sell,
@ -1272,6 +1316,7 @@ const ordersVTI: PortfolioOrder[] = [
},
{
date: '2021-08-01',
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
type: OrderType.Buy,
@ -1280,6 +1325,7 @@ const ordersVTI: PortfolioOrder[] = [
},
{
date: '2021-02-01',
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
type: OrderType.Buy,
@ -1288,11 +1334,12 @@ const ordersVTI: PortfolioOrder[] = [
}
];
const ordersVTITransactionPoints = [
const ordersVTITransactionPoints: TransactionPoint[] = [
{
date: '2019-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('10'),
symbol: 'VTI',
investment: new Big('1443.8'),
@ -1306,6 +1353,7 @@ const ordersVTITransactionPoints = [
date: '2019-08-03',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('20'),
symbol: 'VTI',
investment: new Big('2923.7'),
@ -1319,6 +1367,7 @@ const ordersVTITransactionPoints = [
date: '2020-02-02',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('5'),
symbol: 'VTI',
investment: new Big('652.55'),
@ -1332,6 +1381,7 @@ const ordersVTITransactionPoints = [
date: '2021-02-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('15'),
symbol: 'VTI',
investment: new Big('2684.05'),
@ -1345,6 +1395,7 @@ const ordersVTITransactionPoints = [
date: '2021-08-01',
items: [
{
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
quantity: new Big('25'),
symbol: 'VTI',
investment: new Big('4460.95'),

@ -381,7 +381,7 @@ export class PortfolioCalculator {
}
}
interface TransactionPoint {
export interface TransactionPoint {
date: string;
items: TransactionPointSymbol[];
}

@ -14,10 +14,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider.serv
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service';
import { IOrder } from '@ghostfolio/api/services/interfaces/interfaces';
import {
MarketState,
Type
} from '@ghostfolio/api/services/interfaces/interfaces';
import { Type } from '@ghostfolio/api/services/interfaces/interfaces';
import { RulesService } from '@ghostfolio/api/services/rules.service';
import {
PortfolioItem,
@ -197,93 +194,6 @@ export class PortfolioService {
}));
}
public async getPositions(
aImpersonationId: string,
aDateRange: DateRange = 'max'
): Promise<Position[]> {
const impersonationUserId =
await this.impersonationService.validateImpersonationId(
aImpersonationId,
this.request.user.id
);
const userId = impersonationUserId || this.request.user.id;
const portfolioCalculator = new PortfolioCalculator(
this.currentRateService,
this.request.user.Settings.currency
);
const transactionPoints = await this.getTransactionPoints(userId);
portfolioCalculator.setTransactionPoints(transactionPoints);
// TODO: get positions for date range
console.log('Date range:', aDateRange);
const positions = await portfolioCalculator.getCurrentPositions();
return Object.values(positions).map((position) => {
return {
...position,
averagePrice: new Big(position.averagePrice).toNumber(),
grossPerformance: new Big(position.grossPerformance).toNumber(),
grossPerformancePercentage: new Big(
position.grossPerformancePercentage
).toNumber(),
investment: new Big(position.investment).toNumber(),
name: position.name,
quantity: new Big(position.quantity).toNumber(),
type: Type.Unknown, // TODO
url: '' // TODO
};
});
}
private getStartDate(aDateRange: DateRange, portfolioStart: Date) {
switch (aDateRange) {
case '1d':
portfolioStart = max([portfolioStart, subDays(new Date(), 1)]);
break;
case 'ytd':
portfolioStart = max([portfolioStart, setDayOfYear(new Date(), 1)]);
break;
case '1y':
portfolioStart = max([portfolioStart, subYears(new Date(), 1)]);
break;
case '5y':
portfolioStart = max([portfolioStart, subYears(new Date(), 5)]);
break;
}
return portfolioStart;
}
private async getTransactionPoints(userId: string) {
console.time('create-portfolio');
const orders = await this.getOrders(userId);
console.timeEnd('create-portfolio');
if (orders.length <= 0) {
return [];
}
const portfolioOrders: PortfolioOrder[] = orders.map((order) => ({
currency: order.currency,
date: format(order.date, 'yyyy-MM-dd'),
name: order.SymbolProfile?.name,
quantity: new Big(order.quantity),
symbol: order.symbol,
type: <OrderType>order.type,
unitPrice: new Big(order.unitPrice)
}));
const portfolioCalculator = new PortfolioCalculator(
this.currentRateService,
this.request.user.Settings.currency
);
portfolioCalculator.computeTransactionPoints(portfolioOrders);
return portfolioCalculator.getTransactionPoints();
}
public async getOverview(
aImpersonationId: string
): Promise<PortfolioOverview> {
@ -485,6 +395,93 @@ export class PortfolioService {
};
}
public async getPositions(
aImpersonationId: string,
aDateRange: DateRange = 'max'
): Promise<Position[]> {
const impersonationUserId =
await this.impersonationService.validateImpersonationId(
aImpersonationId,
this.request.user.id
);
const userId = impersonationUserId || this.request.user.id;
const portfolioCalculator = new PortfolioCalculator(
this.currentRateService,
this.request.user.Settings.currency
);
const transactionPoints = await this.getTransactionPoints(userId);
portfolioCalculator.setTransactionPoints(transactionPoints);
// TODO: get positions for date range
console.log('Date range:', aDateRange);
const positions = await portfolioCalculator.getCurrentPositions();
return Object.values(positions).map((position) => {
return {
...position,
averagePrice: new Big(position.averagePrice).toNumber(),
grossPerformance: new Big(position.grossPerformance).toNumber(),
grossPerformancePercentage: new Big(
position.grossPerformancePercentage
).toNumber(),
investment: new Big(position.investment).toNumber(),
name: position.name,
quantity: new Big(position.quantity).toNumber(),
type: Type.Unknown, // TODO
url: '' // TODO
};
});
}
private getStartDate(aDateRange: DateRange, portfolioStart: Date) {
switch (aDateRange) {
case '1d':
portfolioStart = max([portfolioStart, subDays(new Date(), 1)]);
break;
case 'ytd':
portfolioStart = max([portfolioStart, setDayOfYear(new Date(), 1)]);
break;
case '1y':
portfolioStart = max([portfolioStart, subYears(new Date(), 1)]);
break;
case '5y':
portfolioStart = max([portfolioStart, subYears(new Date(), 5)]);
break;
}
return portfolioStart;
}
private async getTransactionPoints(userId: string) {
console.time('create-portfolio');
const orders = await this.getOrders(userId);
console.timeEnd('create-portfolio');
if (orders.length <= 0) {
return [];
}
const portfolioOrders: PortfolioOrder[] = orders.map((order) => ({
currency: order.currency,
date: format(order.date, 'yyyy-MM-dd'),
name: order.SymbolProfile?.name,
quantity: new Big(order.quantity),
symbol: order.symbol,
type: <OrderType>order.type,
unitPrice: new Big(order.unitPrice)
}));
const portfolioCalculator = new PortfolioCalculator(
this.currentRateService,
this.request.user.Settings.currency
);
portfolioCalculator.computeTransactionPoints(portfolioOrders);
return portfolioCalculator.getTransactionPoints();
}
private convertDateRangeToDate(aDateRange: DateRange, aMinDate: Date) {
let currentDate = new Date();

Loading…
Cancel
Save