Browse Source

Refactoring

pull/3167/head
Thomas Kaul 1 year ago
parent
commit
e80b8669df
  1. 33
      apps/api/src/app/benchmark/benchmark.service.ts
  2. 4
      apps/api/src/app/portfolio/current-rate.service.ts
  3. 33
      apps/api/src/app/portfolio/portfolio-calculator.ts
  4. 76
      libs/common/src/lib/helper.spec.ts
  5. 29
      libs/common/src/lib/helper.ts

33
apps/api/src/app/benchmark/benchmark.service.ts

@ -13,7 +13,6 @@ import {
import { import {
DATE_FORMAT, DATE_FORMAT,
calculateBenchmarkTrend, calculateBenchmarkTrend,
eachDayOfInterval,
parseDate, parseDate,
resetHours resetHours
} from '@ghostfolio/common/helper'; } from '@ghostfolio/common/helper';
@ -29,7 +28,13 @@ import { BenchmarkTrend } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { SymbolProfile } from '@prisma/client'; import { SymbolProfile } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { differenceInDays, format, isSameDay, subDays } from 'date-fns'; import {
differenceInDays,
eachDayOfInterval,
format,
isSameDay,
subDays
} from 'date-fns';
import { isNumber, last, uniqBy } from 'lodash'; import { isNumber, last, uniqBy } from 'lodash';
import ms from 'ms'; import ms from 'ms';
@ -210,23 +215,26 @@ export class BenchmarkService {
public async getMarketDataBySymbol({ public async getMarketDataBySymbol({
dataSource, dataSource,
startDate,
endDate = new Date(), endDate = new Date(),
startDate,
symbol, symbol,
userCurrency userCurrency
}: { }: {
startDate: Date;
endDate?: Date; endDate?: Date;
startDate: Date;
userCurrency: string; userCurrency: string;
} & UniqueAsset): Promise<BenchmarkMarketDataDetails> { } & UniqueAsset): Promise<BenchmarkMarketDataDetails> {
const marketData: { date: string; value: number }[] = []; const marketData: { date: string; value: number }[] = [];
const days = differenceInDays(endDate, startDate) + 1; const days = differenceInDays(endDate, startDate) + 1;
const dates = eachDayOfInterval({ const dates = eachDayOfInterval(
start: startDate, {
end: endDate, start: startDate,
step: Math.round(days / Math.min(days, MAX_CHART_ITEMS)), end: endDate
includeEnd: true },
{ step: Math.round(days / Math.min(days, MAX_CHART_ITEMS)) }
).map((date) => {
return resetHours(date);
}); });
const [currentSymbolItem, marketDataItems] = await Promise.all([ const [currentSymbolItem, marketDataItems] = await Promise.all([
@ -301,9 +309,12 @@ export class BenchmarkService {
}); });
} }
const includesToday = isSameDay(parseDate(last(marketData).date), endDate); const includesEndDate = isSameDay(
parseDate(last(marketData).date),
endDate
);
if (currentSymbolItem?.marketPrice && !includesToday) { if (currentSymbolItem?.marketPrice && !includesEndDate) {
const exchangeRate = const exchangeRate =
exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[
format(endDate, DATE_FORMAT) format(endDate, DATE_FORMAT)

4
apps/api/src/app/portfolio/current-rate.service.ts

@ -34,7 +34,7 @@ export class CurrentRateService {
}: GetValuesParams): Promise<GetValuesObject> { }: GetValuesParams): Promise<GetValuesObject> {
const dataProviderInfos: DataProviderInfo[] = []; const dataProviderInfos: DataProviderInfo[] = [];
const includeToday = const includesToday =
(!dateQuery.lt || isBefore(new Date(), dateQuery.lt)) && (!dateQuery.lt || isBefore(new Date(), dateQuery.lt)) &&
(!dateQuery.gte || isBefore(dateQuery.gte, new Date())) && (!dateQuery.gte || isBefore(dateQuery.gte, new Date())) &&
(!dateQuery.in || this.containsToday(dateQuery.in)); (!dateQuery.in || this.containsToday(dateQuery.in));
@ -43,7 +43,7 @@ export class CurrentRateService {
const quoteErrors: ResponseError['errors'] = []; const quoteErrors: ResponseError['errors'] = [];
const today = resetHours(new Date()); const today = resetHours(new Date());
if (includeToday) { if (includesToday) {
promises.push( promises.push(
this.dataProviderService this.dataProviderService
.getQuotes({ items: dataGatheringItems, user: this.request?.user }) .getQuotes({ items: dataGatheringItems, user: this.request?.user })

33
apps/api/src/app/portfolio/portfolio-calculator.ts

@ -1,12 +1,7 @@
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper'; import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
import { import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
DATE_FORMAT,
eachDayOfInterval,
parseDate,
resetHours
} from '@ghostfolio/common/helper';
import { import {
DataProviderInfo, DataProviderInfo,
HistoricalDataItem, HistoricalDataItem,
@ -23,10 +18,12 @@ import {
addDays, addDays,
addMilliseconds, addMilliseconds,
differenceInDays, differenceInDays,
eachDayOfInterval,
endOfDay, endOfDay,
format, format,
isBefore, isBefore,
isSameDay, isSameDay,
isToday,
max, max,
subDays subDays
} from 'date-fns'; } from 'date-fns';
@ -207,16 +204,28 @@ export class PortfolioCalculator {
const dataGatheringItems: IDataGatheringItem[] = []; const dataGatheringItems: IDataGatheringItem[] = [];
const firstIndex = transactionPointsBeforeEndDate.length; const firstIndex = transactionPointsBeforeEndDate.length;
const dates = eachDayOfInterval({ start, end, step, includeEnd: true }); let dates = eachDayOfInterval({ start, end }, { step }).map((date) => {
return resetHours(date);
});
const includesEndDate = isSameDay(last(dates), end);
if (!includesEndDate) {
dates.push(resetHours(end));
}
if (transactionPointsBeforeEndDate.length > 0) { if (transactionPointsBeforeEndDate.length > 0) {
for (const item of transactionPointsBeforeEndDate[firstIndex - 1].items) { for (const {
currency,
dataSource,
symbol
} of transactionPointsBeforeEndDate[firstIndex - 1].items) {
dataGatheringItems.push({ dataGatheringItems.push({
dataSource: item.dataSource, dataSource,
symbol: item.symbol symbol
}); });
currencies[item.symbol] = item.currency; currencies[symbol] = currency;
symbols[item.symbol] = true; symbols[symbol] = true;
} }
} }

76
libs/common/src/lib/helper.spec.ts

@ -1,7 +1,4 @@
import { import { extractNumberFromString } from '@ghostfolio/common/helper';
eachDayOfInterval,
extractNumberFromString
} from '@ghostfolio/common/helper';
describe('Helper', () => { describe('Helper', () => {
describe('Extract number from string', () => { describe('Extract number from string', () => {
@ -39,75 +36,4 @@ describe('Helper', () => {
expect(extractNumberFromString({ value: 'X' })).toEqual(NaN); expect(extractNumberFromString({ value: 'X' })).toEqual(NaN);
}); });
}); });
describe('eachDayOfInterval', () => {
describe('start and end', () => {
const expected = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 2)),
new Date(Date.UTC(2021, 0, 3))
];
it('as strings', () => {
const [start, end] = ['2021-01-01', '2021-01-03'];
expect(eachDayOfInterval({ start, end })).toEqual(expected);
});
it('as numbers', () => {
const [start, end] = [Date.UTC(2021, 0, 1), Date.UTC(2021, 0, 3)];
expect(eachDayOfInterval({ start, end })).toEqual(expected);
});
it('as dates', () => {
const [start, end] = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 3))
];
expect(eachDayOfInterval({ start, end })).toEqual(expected);
});
});
describe('step', () => {
const [start, end] = ['2021-01-01', '2021-01-06'];
it('step size of 2', () => {
const expected = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 3)),
new Date(Date.UTC(2021, 0, 5))
];
expect(eachDayOfInterval({ start, end, step: 2 })).toEqual(expected);
});
it('step size of 4', () => {
const expected = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 5))
];
expect(eachDayOfInterval({ start, end, step: 4 })).toEqual(expected);
});
it('step size of 5', () => {
const expected = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 6))
];
expect(eachDayOfInterval({ start, end, step: 5 })).toEqual(expected);
});
});
describe('includeEnd', () => {
const [start, end] = ['2021-01-01', '2021-01-06'];
it('end is added', () => {
const expected = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 5)),
new Date(Date.UTC(2021, 0, 6))
];
expect(
eachDayOfInterval({ start, end, step: 4, includeEnd: true })
).toEqual(expected);
});
it('end is not duplicated', () => {
const expected = [
new Date(Date.UTC(2021, 0, 1)),
new Date(Date.UTC(2021, 0, 6))
];
expect(
eachDayOfInterval({ start, end, step: 5, includeEnd: true })
).toEqual(expected);
});
});
});
}); });

29
libs/common/src/lib/helper.ts

@ -375,35 +375,6 @@ export function resetHours(aDate: Date) {
return new Date(Date.UTC(year, month, day)); return new Date(Date.UTC(year, month, day));
} }
export function eachDayOfInterval({
start,
end,
step = 1,
includeEnd = false
}: {
start: Date | string | number;
end: Date | string | number;
step?: number;
includeEnd?: boolean;
}) {
[start, end] = [new Date(start), new Date(end)];
[start, end] = [resetHours(start), resetHours(end)];
[start, end] = [start.getTime(), end.getTime()];
const DAY_IN_MS = 1000 * 60 * 60 * 24;
const dates: number[] = [];
for (let date = start; date <= end; date += step * DAY_IN_MS) {
dates.push(date);
}
if (includeEnd && end !== dates?.[dates.length - 1]) {
dates.push(end);
}
return dates.map((date) => new Date(date));
}
export function resolveFearAndGreedIndex(aValue: number) { export function resolveFearAndGreedIndex(aValue: number) {
if (aValue <= 25) { if (aValue <= 25) {
return { emoji: '🥵', key: 'EXTREME_FEAR', text: 'Extreme Fear' }; return { emoji: '🥵', key: 'EXTREME_FEAR', text: 'Extreme Fear' };

Loading…
Cancel
Save