mirror of https://github.com/ghostfolio/ghostfolio
84 changed files with 5971 additions and 2193 deletions
@ -1,6 +1,6 @@ |
|||
import { UniqueAsset } from '@ghostfolio/common/interfaces'; |
|||
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; |
|||
|
|||
export interface GetValueObject extends UniqueAsset { |
|||
export interface GetValueObject extends AssetProfileIdentifier { |
|||
date: Date; |
|||
marketPrice: number; |
|||
} |
|||
|
@ -1,78 +0,0 @@ |
|||
import { Big } from 'big.js'; |
|||
|
|||
import { PortfolioService } from './portfolio.service'; |
|||
|
|||
describe('PortfolioService', () => { |
|||
let portfolioService: PortfolioService; |
|||
|
|||
beforeAll(async () => { |
|||
portfolioService = new PortfolioService( |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null |
|||
); |
|||
}); |
|||
|
|||
describe('annualized performance percentage', () => { |
|||
it('Get annualized performance', async () => { |
|||
expect( |
|||
portfolioService |
|||
.getAnnualizedPerformancePercent({ |
|||
daysInMarket: NaN, // differenceInDays of date-fns returns NaN for the same day
|
|||
netPerformancePercentage: new Big(0) |
|||
}) |
|||
.toNumber() |
|||
).toEqual(0); |
|||
|
|||
expect( |
|||
portfolioService |
|||
.getAnnualizedPerformancePercent({ |
|||
daysInMarket: 0, |
|||
netPerformancePercentage: new Big(0) |
|||
}) |
|||
.toNumber() |
|||
).toEqual(0); |
|||
|
|||
/** |
|||
* Source: https://www.readyratios.com/reference/analysis/annualized_rate.html
|
|||
*/ |
|||
expect( |
|||
portfolioService |
|||
.getAnnualizedPerformancePercent({ |
|||
daysInMarket: 65, // < 1 year
|
|||
netPerformancePercentage: new Big(0.1025) |
|||
}) |
|||
.toNumber() |
|||
).toBeCloseTo(0.729705); |
|||
|
|||
expect( |
|||
portfolioService |
|||
.getAnnualizedPerformancePercent({ |
|||
daysInMarket: 365, // 1 year
|
|||
netPerformancePercentage: new Big(0.05) |
|||
}) |
|||
.toNumber() |
|||
).toBeCloseTo(0.05); |
|||
|
|||
/** |
|||
* Source: https://www.investopedia.com/terms/a/annualized-total-return.asp#annualized-return-formula-and-calculation
|
|||
*/ |
|||
expect( |
|||
portfolioService |
|||
.getAnnualizedPerformancePercent({ |
|||
daysInMarket: 575, // > 1 year
|
|||
netPerformancePercentage: new Big(0.2374) |
|||
}) |
|||
.toNumber() |
|||
).toBeCloseTo(0.145); |
|||
}); |
|||
}); |
|||
}); |
@ -0,0 +1,7 @@ |
|||
import { Tag } from '@prisma/client'; |
|||
import { IsArray } from 'class-validator'; |
|||
|
|||
export class UpdateHoldingTagsDto { |
|||
@IsArray() |
|||
tags: Tag[]; |
|||
} |
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,50 @@ |
|||
import { Big } from 'big.js'; |
|||
|
|||
import { getAnnualizedPerformancePercent } from './calculation-helper'; |
|||
|
|||
describe('CalculationHelper', () => { |
|||
describe('annualized performance percentage', () => { |
|||
it('Get annualized performance', async () => { |
|||
expect( |
|||
getAnnualizedPerformancePercent({ |
|||
daysInMarket: NaN, // differenceInDays of date-fns returns NaN for the same day
|
|||
netPerformancePercentage: new Big(0) |
|||
}).toNumber() |
|||
).toEqual(0); |
|||
|
|||
expect( |
|||
getAnnualizedPerformancePercent({ |
|||
daysInMarket: 0, |
|||
netPerformancePercentage: new Big(0) |
|||
}).toNumber() |
|||
).toEqual(0); |
|||
|
|||
/** |
|||
* Source: https://www.readyratios.com/reference/analysis/annualized_rate.html
|
|||
*/ |
|||
expect( |
|||
getAnnualizedPerformancePercent({ |
|||
daysInMarket: 65, // < 1 year
|
|||
netPerformancePercentage: new Big(0.1025) |
|||
}).toNumber() |
|||
).toBeCloseTo(0.729705); |
|||
|
|||
expect( |
|||
getAnnualizedPerformancePercent({ |
|||
daysInMarket: 365, // 1 year
|
|||
netPerformancePercentage: new Big(0.05) |
|||
}).toNumber() |
|||
).toBeCloseTo(0.05); |
|||
|
|||
/** |
|||
* Source: https://www.investopedia.com/terms/a/annualized-total-return.asp#annualized-return-formula-and-calculation
|
|||
*/ |
|||
expect( |
|||
getAnnualizedPerformancePercent({ |
|||
daysInMarket: 575, // > 1 year
|
|||
netPerformancePercentage: new Big(0.2374) |
|||
}).toNumber() |
|||
).toBeCloseTo(0.145); |
|||
}); |
|||
}); |
|||
}); |
@ -0,0 +1,20 @@ |
|||
import { Big } from 'big.js'; |
|||
import { isNumber } from 'lodash'; |
|||
|
|||
export function getAnnualizedPerformancePercent({ |
|||
daysInMarket, |
|||
netPerformancePercentage |
|||
}: { |
|||
daysInMarket: number; |
|||
netPerformancePercentage: Big; |
|||
}): Big { |
|||
if (isNumber(daysInMarket) && daysInMarket > 0) { |
|||
const exponent = new Big(365).div(daysInMarket).toNumber(); |
|||
|
|||
return new Big( |
|||
Math.pow(netPerformancePercentage.plus(1).toNumber(), exponent) |
|||
).minus(1); |
|||
} |
|||
|
|||
return new Big(0); |
|||
} |
@ -1,6 +1,6 @@ |
|||
import { DataSource } from '@prisma/client'; |
|||
|
|||
export interface UniqueAsset { |
|||
export interface AssetProfileIdentifier { |
|||
dataSource: DataSource; |
|||
symbol: string; |
|||
} |
@ -1,6 +1,6 @@ |
|||
import { UniqueAsset } from '../unique-asset.interface'; |
|||
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; |
|||
|
|||
export interface ResponseError { |
|||
errors?: UniqueAsset[]; |
|||
errors?: AssetProfileIdentifier[]; |
|||
hasErrors: boolean; |
|||
} |
|||
|
@ -1 +0,0 @@ |
|||
export type HoldingViewMode = 'CHART' | 'TABLE'; |
@ -0,0 +1 @@ |
|||
export type HoldingsViewMode = 'CHART' | 'TABLE'; |
File diff suppressed because it is too large
Loading…
Reference in new issue