Browse Source

Rename new portfolio calculation engine

pull/816/head
Thomas 3 years ago
parent
commit
861738b05b
  1. 6
      apps/api/src/app/account/account.controller.ts
  2. 10
      apps/api/src/app/portfolio/portfolio-calculator-baln-buy-and-sell.spec.ts
  3. 10
      apps/api/src/app/portfolio/portfolio-calculator-baln-buy.spec.ts
  4. 10
      apps/api/src/app/portfolio/portfolio-calculator-no-orders.spec.ts
  5. 16
      apps/api/src/app/portfolio/portfolio-calculator.spec.ts
  6. 18
      apps/api/src/app/portfolio/portfolio-calculator.ts
  7. 26
      apps/api/src/app/portfolio/portfolio.controller.ts
  8. 6
      apps/api/src/app/portfolio/portfolio.module.ts
  9. 22
      apps/api/src/app/portfolio/portfolio.service.ts

6
apps/api/src/app/account/account.controller.ts

@ -1,4 +1,4 @@
import { PortfolioServiceNew } from '@ghostfolio/api/app/portfolio/portfolio.service-new';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import {
nullifyValuesInObject,
@ -35,7 +35,7 @@ export class AccountController {
public constructor(
private readonly accountService: AccountService,
private readonly impersonationService: ImpersonationService,
private readonly portfolioServiceNew: PortfolioServiceNew,
private readonly portfolioService: PortfolioService,
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly userService: UserService
) {}
@ -92,7 +92,7 @@ export class AccountController {
);
let accountsWithAggregations =
await this.portfolioServiceNew.getAccountsWithAggregations(
await this.portfolioService.getAccountsWithAggregations(
impersonationUserId || this.request.user.id
);

10
apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy-and-sell.spec.ts → apps/api/src/app/portfolio/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -3,7 +3,7 @@ import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
import { PortfolioCalculatorNew } from './portfolio-calculator-new';
import { PortfolioCalculator } from './portfolio-calculator';
jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
return {
@ -14,7 +14,7 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
};
});
describe('PortfolioCalculatorNew', () => {
describe('PortfolioCalculator', () => {
let currentRateService: CurrentRateService;
beforeEach(() => {
@ -23,7 +23,7 @@ describe('PortfolioCalculatorNew', () => {
describe('get current positions', () => {
it.only('with BALN.SW buy and sell', async () => {
const portfolioCalculatorNew = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currentRateService,
currency: 'CHF',
orders: [
@ -52,13 +52,13 @@ describe('PortfolioCalculatorNew', () => {
]
});
portfolioCalculatorNew.computeTransactionPoints();
portfolioCalculator.computeTransactionPoints();
const spy = jest
.spyOn(Date, 'now')
.mockImplementation(() => parseDate('2021-12-18').getTime());
const currentPositions = await portfolioCalculatorNew.getCurrentPositions(
const currentPositions = await portfolioCalculator.getCurrentPositions(
parseDate('2021-11-22')
);

10
apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy.spec.ts → apps/api/src/app/portfolio/portfolio-calculator-baln-buy.spec.ts

@ -3,7 +3,7 @@ import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
import { PortfolioCalculatorNew } from './portfolio-calculator-new';
import { PortfolioCalculator } from './portfolio-calculator';
jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
return {
@ -14,7 +14,7 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
};
});
describe('PortfolioCalculatorNew', () => {
describe('PortfolioCalculator', () => {
let currentRateService: CurrentRateService;
beforeEach(() => {
@ -23,7 +23,7 @@ describe('PortfolioCalculatorNew', () => {
describe('get current positions', () => {
it.only('with BALN.SW buy', async () => {
const portfolioCalculatorNew = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currentRateService,
currency: 'CHF',
orders: [
@ -41,13 +41,13 @@ describe('PortfolioCalculatorNew', () => {
]
});
portfolioCalculatorNew.computeTransactionPoints();
portfolioCalculator.computeTransactionPoints();
const spy = jest
.spyOn(Date, 'now')
.mockImplementation(() => parseDate('2021-12-18').getTime());
const currentPositions = await portfolioCalculatorNew.getCurrentPositions(
const currentPositions = await portfolioCalculator.getCurrentPositions(
parseDate('2021-11-30')
);

10
apps/api/src/app/portfolio/portfolio-calculator-new-no-orders.spec.ts → apps/api/src/app/portfolio/portfolio-calculator-no-orders.spec.ts

@ -3,7 +3,7 @@ import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
import { PortfolioCalculatorNew } from './portfolio-calculator-new';
import { PortfolioCalculator } from './portfolio-calculator';
jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
return {
@ -14,7 +14,7 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
};
});
describe('PortfolioCalculatorNew', () => {
describe('PortfolioCalculator', () => {
let currentRateService: CurrentRateService;
beforeEach(() => {
@ -23,19 +23,19 @@ describe('PortfolioCalculatorNew', () => {
describe('get current positions', () => {
it('with no orders', async () => {
const portfolioCalculatorNew = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currentRateService,
currency: 'CHF',
orders: []
});
portfolioCalculatorNew.computeTransactionPoints();
portfolioCalculator.computeTransactionPoints();
const spy = jest
.spyOn(Date, 'now')
.mockImplementation(() => parseDate('2021-12-18').getTime());
const currentPositions = await portfolioCalculatorNew.getCurrentPositions(
const currentPositions = await portfolioCalculator.getCurrentPositions(
new Date()
);

16
apps/api/src/app/portfolio/portfolio-calculator-new.spec.ts → apps/api/src/app/portfolio/portfolio-calculator.spec.ts

@ -1,9 +1,9 @@
import Big from 'big.js';
import { CurrentRateService } from './current-rate.service';
import { PortfolioCalculatorNew } from './portfolio-calculator-new';
import { PortfolioCalculator } from './portfolio-calculator';
describe('PortfolioCalculatorNew', () => {
describe('PortfolioCalculator', () => {
let currentRateService: CurrentRateService;
beforeEach(() => {
@ -11,7 +11,7 @@ describe('PortfolioCalculatorNew', () => {
});
describe('annualized performance percentage', () => {
const portfolioCalculatorNew = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currentRateService,
currency: 'USD',
orders: []
@ -19,7 +19,7 @@ describe('PortfolioCalculatorNew', () => {
it('Get annualized performance', async () => {
expect(
portfolioCalculatorNew
portfolioCalculator
.getAnnualizedPerformancePercent({
daysInMarket: NaN, // differenceInDays of date-fns returns NaN for the same day
netPerformancePercent: new Big(0)
@ -28,7 +28,7 @@ describe('PortfolioCalculatorNew', () => {
).toEqual(0);
expect(
portfolioCalculatorNew
portfolioCalculator
.getAnnualizedPerformancePercent({
daysInMarket: 0,
netPerformancePercent: new Big(0)
@ -40,7 +40,7 @@ describe('PortfolioCalculatorNew', () => {
* Source: https://www.readyratios.com/reference/analysis/annualized_rate.html
*/
expect(
portfolioCalculatorNew
portfolioCalculator
.getAnnualizedPerformancePercent({
daysInMarket: 65, // < 1 year
netPerformancePercent: new Big(0.1025)
@ -49,7 +49,7 @@ describe('PortfolioCalculatorNew', () => {
).toBeCloseTo(0.729705);
expect(
portfolioCalculatorNew
portfolioCalculator
.getAnnualizedPerformancePercent({
daysInMarket: 365, // 1 year
netPerformancePercent: new Big(0.05)
@ -61,7 +61,7 @@ describe('PortfolioCalculatorNew', () => {
* Source: https://www.investopedia.com/terms/a/annualized-total-return.asp#annualized-return-formula-and-calculation
*/
expect(
portfolioCalculatorNew
portfolioCalculator
.getAnnualizedPerformancePercent({
daysInMarket: 575, // > 1 year
netPerformancePercent: new Big(0.2374)

18
apps/api/src/app/portfolio/portfolio-calculator-new.ts → apps/api/src/app/portfolio/portfolio-calculator.ts

@ -1,11 +1,7 @@
import { TimelineInfoInterface } from '@ghostfolio/api/app/portfolio/interfaces/timeline-info.interface';
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
import {
ResponseError,
TimelinePosition,
UniqueAsset
} from '@ghostfolio/common/interfaces';
import { ResponseError, TimelinePosition } from '@ghostfolio/common/interfaces';
import { Logger } from '@nestjs/common';
import { Type as TypeOfOrder } from '@prisma/client';
import Big from 'big.js';
@ -36,7 +32,7 @@ import {
import { TransactionPointSymbol } from './interfaces/transaction-point-symbol.interface';
import { TransactionPoint } from './interfaces/transaction-point.interface';
export class PortfolioCalculatorNew {
export class PortfolioCalculator {
private static readonly CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT =
true;
@ -462,7 +458,7 @@ export class PortfolioCalculatorNew {
} else if (!currentPosition.quantity.eq(0)) {
Logger.warn(
`Missing initial value for symbol ${currentPosition.symbol} at ${currentPosition.firstBuyDate}`,
'PortfolioCalculatorNew'
'PortfolioCalculator'
);
hasErrors = true;
}
@ -528,7 +524,7 @@ export class PortfolioCalculatorNew {
Logger.error(
`Failed to fetch info for date ${startDate} with exception`,
error,
'PortfolioCalculatorNew'
'PortfolioCalculator'
);
return null;
}
@ -913,7 +909,7 @@ export class PortfolioCalculatorNew {
);
const grossPerformancePercentage =
PortfolioCalculatorNew.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT ||
PortfolioCalculator.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT ||
averagePriceAtStartDate.eq(0) ||
averagePriceAtEndDate.eq(0) ||
orders[indexOfStartOrder].unitPrice.eq(0)
@ -935,7 +931,7 @@ export class PortfolioCalculatorNew {
: new Big(0);
const netPerformancePercentage =
PortfolioCalculatorNew.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT ||
PortfolioCalculator.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT ||
averagePriceAtStartDate.eq(0) ||
averagePriceAtEndDate.eq(0) ||
orders[indexOfStartOrder].unitPrice.eq(0)
@ -953,7 +949,7 @@ export class PortfolioCalculatorNew {
)
.minus(1);
if (PortfolioCalculatorNew.ENABLE_LOGGING) {
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log(
`
${symbol}

26
apps/api/src/app/portfolio/portfolio.controller.ts

@ -38,7 +38,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { PortfolioPositionDetail } from './interfaces/portfolio-position-detail.interface';
import { PortfolioPositions } from './interfaces/portfolio-positions.interface';
import { PortfolioServiceNew } from './portfolio.service-new';
import { PortfolioService } from './portfolio.service';
@Controller('portfolio')
export class PortfolioController {
@ -46,7 +46,7 @@ export class PortfolioController {
private readonly accessService: AccessService,
private readonly configurationService: ConfigurationService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly portfolioServiceNew: PortfolioServiceNew,
private readonly portfolioService: PortfolioService,
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly userService: UserService
) {}
@ -57,7 +57,7 @@ export class PortfolioController {
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
): Promise<PortfolioChart> {
const historicalDataContainer = await this.portfolioServiceNew.getChart(
const historicalDataContainer = await this.portfolioService.getChart(
impersonationId,
range
);
@ -110,7 +110,7 @@ export class PortfolioController {
let hasError = false;
const { accounts, holdings, hasErrors } =
await this.portfolioServiceNew.getDetails(
await this.portfolioService.getDetails(
impersonationId,
this.request.user.id,
range
@ -177,7 +177,7 @@ export class PortfolioController {
);
}
let investments = await this.portfolioServiceNew.getInvestments(
let investments = await this.portfolioService.getInvestments(
impersonationId
);
@ -206,8 +206,10 @@ export class PortfolioController {
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
): Promise<PortfolioPerformanceResponse> {
const performanceInformation =
await this.portfolioServiceNew.getPerformance(impersonationId, range);
const performanceInformation = await this.portfolioService.getPerformance(
impersonationId,
range
);
if (
impersonationId ||
@ -230,7 +232,7 @@ export class PortfolioController {
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
): Promise<PortfolioPositions> {
const result = await this.portfolioServiceNew.getPositions(
const result = await this.portfolioService.getPositions(
impersonationId,
range
);
@ -273,7 +275,7 @@ export class PortfolioController {
hasDetails = user.subscription.type === 'Premium';
}
const { holdings } = await this.portfolioServiceNew.getDetails(
const { holdings } = await this.portfolioService.getDetails(
access.userId,
access.userId
);
@ -328,7 +330,7 @@ export class PortfolioController {
);
}
let summary = await this.portfolioServiceNew.getSummary(impersonationId);
let summary = await this.portfolioService.getSummary(impersonationId);
if (
impersonationId ||
@ -362,7 +364,7 @@ export class PortfolioController {
@Param('dataSource') dataSource,
@Param('symbol') symbol
): Promise<PortfolioPositionDetail> {
let position = await this.portfolioServiceNew.getPosition(
let position = await this.portfolioService.getPosition(
dataSource,
impersonationId,
symbol
@ -407,6 +409,6 @@ export class PortfolioController {
);
}
return await this.portfolioServiceNew.getReport(impersonationId);
return await this.portfolioService.getReport(impersonationId);
}
}

6
apps/api/src/app/portfolio/portfolio.module.ts

@ -14,12 +14,12 @@ import { Module } from '@nestjs/common';
import { CurrentRateService } from './current-rate.service';
import { PortfolioController } from './portfolio.controller';
import { PortfolioServiceNew } from './portfolio.service-new';
import { PortfolioService } from './portfolio.service';
import { RulesService } from './rules.service';
@Module({
controllers: [PortfolioController],
exports: [PortfolioServiceNew],
exports: [PortfolioService],
imports: [
AccessModule,
ConfigurationModule,
@ -36,7 +36,7 @@ import { RulesService } from './rules.service';
providers: [
AccountService,
CurrentRateService,
PortfolioServiceNew,
PortfolioService,
RulesService
]
})

22
apps/api/src/app/portfolio/portfolio.service-new.ts → apps/api/src/app/portfolio/portfolio.service.ts

@ -69,14 +69,14 @@ import {
HistoricalDataItem,
PortfolioPositionDetail
} from './interfaces/portfolio-position-detail.interface';
import { PortfolioCalculatorNew } from './portfolio-calculator-new';
import { PortfolioCalculator } from './portfolio-calculator';
import { RulesService } from './rules.service';
const developedMarkets = require('../../assets/countries/developed-markets.json');
const emergingMarkets = require('../../assets/countries/emerging-markets.json');
@Injectable()
export class PortfolioServiceNew {
export class PortfolioService {
public constructor(
private readonly accountService: AccountService,
private readonly currentRateService: CurrentRateService,
@ -170,7 +170,7 @@ export class PortfolioServiceNew {
includeDrafts: true
});
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -221,7 +221,7 @@ export class PortfolioServiceNew {
userId
});
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -321,7 +321,7 @@ export class PortfolioServiceNew {
userId
});
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: userCurrency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -514,7 +514,7 @@ export class PortfolioServiceNew {
unitPrice: new Big(order.unitPrice)
}));
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: positionCurrency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -704,7 +704,7 @@ export class PortfolioServiceNew {
userId
});
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -781,7 +781,7 @@ export class PortfolioServiceNew {
userId
});
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -856,7 +856,7 @@ export class PortfolioServiceNew {
};
}
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency,
currentRateService: this.currentRateService,
orders: portfolioOrders
@ -969,7 +969,7 @@ export class PortfolioServiceNew {
const daysInMarket = differenceInDays(new Date(), firstOrderDate);
const annualizedPerformancePercent = new PortfolioCalculatorNew({
const annualizedPerformancePercent = new PortfolioCalculator({
currency: userCurrency,
currentRateService: this.currentRateService,
orders: []
@ -1224,7 +1224,7 @@ export class PortfolioServiceNew {
)
}));
const portfolioCalculator = new PortfolioCalculatorNew({
const portfolioCalculator = new PortfolioCalculator({
currency: userCurrency,
currentRateService: this.currentRateService,
orders: portfolioOrders
Loading…
Cancel
Save