Feature/expose max chart items as env variable (#3701)
* Expose MAX_CHART_ITEMS as env variable * Update changelog
This commit is contained in:
parent
4a8142b326
commit
d08e8b4fd8
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Reworked the portfolio calculator
|
- Reworked the portfolio calculator
|
||||||
|
- Exposed the maximum of chart data items as an environment variable (`MAX_CHART_ITEMS`)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.mo
|
|||||||
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
|
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
|
||||||
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
|
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
|
||||||
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
|
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
|
||||||
|
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
|
||||||
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
|
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
|
||||||
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
|
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
|
||||||
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
|
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
|
||||||
@ -18,6 +19,7 @@ import { BenchmarkService } from './benchmark.service';
|
|||||||
controllers: [BenchmarkController],
|
controllers: [BenchmarkController],
|
||||||
exports: [BenchmarkService],
|
exports: [BenchmarkService],
|
||||||
imports: [
|
imports: [
|
||||||
|
ConfigurationModule,
|
||||||
DataProviderModule,
|
DataProviderModule,
|
||||||
ExchangeRateDataModule,
|
ExchangeRateDataModule,
|
||||||
MarketDataModule,
|
MarketDataModule,
|
||||||
|
@ -12,6 +12,7 @@ describe('BenchmarkService', () => {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||||
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
|
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
|
||||||
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
|
||||||
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
|
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
|
||||||
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 { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
|
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
|
||||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||||
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
|
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
|
||||||
import {
|
import { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config';
|
||||||
MAX_CHART_ITEMS,
|
|
||||||
PROPERTY_BENCHMARKS
|
|
||||||
} from '@ghostfolio/common/config';
|
|
||||||
import {
|
import {
|
||||||
DATE_FORMAT,
|
DATE_FORMAT,
|
||||||
calculateBenchmarkTrend,
|
calculateBenchmarkTrend,
|
||||||
@ -47,6 +45,7 @@ export class BenchmarkService {
|
|||||||
private readonly CACHE_KEY_BENCHMARKS = 'BENCHMARKS';
|
private readonly CACHE_KEY_BENCHMARKS = 'BENCHMARKS';
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
private readonly configurationService: ConfigurationService,
|
||||||
private readonly dataProviderService: DataProviderService,
|
private readonly dataProviderService: DataProviderService,
|
||||||
private readonly exchangeRateDataService: ExchangeRateDataService,
|
private readonly exchangeRateDataService: ExchangeRateDataService,
|
||||||
private readonly marketDataService: MarketDataService,
|
private readonly marketDataService: MarketDataService,
|
||||||
@ -173,7 +172,12 @@ export class BenchmarkService {
|
|||||||
start: startDate,
|
start: startDate,
|
||||||
end: endDate
|
end: endDate
|
||||||
},
|
},
|
||||||
{ step: Math.round(days / Math.min(days, MAX_CHART_ITEMS)) }
|
{
|
||||||
|
step: Math.round(
|
||||||
|
days /
|
||||||
|
Math.min(days, this.configurationService.get('MAX_CHART_ITEMS'))
|
||||||
|
)
|
||||||
|
}
|
||||||
).map((date) => {
|
).map((date) => {
|
||||||
return resetHours(date);
|
return resetHours(date);
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,6 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
|
|||||||
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 { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
|
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
|
||||||
import { MAX_CHART_ITEMS } from '@ghostfolio/common/config';
|
|
||||||
import {
|
import {
|
||||||
DATE_FORMAT,
|
DATE_FORMAT,
|
||||||
getSum,
|
getSum,
|
||||||
@ -247,7 +246,13 @@ export abstract class PortfolioCalculator {
|
|||||||
let chartDateMap = this.getChartDateMap({
|
let chartDateMap = this.getChartDateMap({
|
||||||
endDate: this.endDate,
|
endDate: this.endDate,
|
||||||
startDate: this.startDate,
|
startDate: this.startDate,
|
||||||
step: Math.round(daysInMarket / Math.min(daysInMarket, MAX_CHART_ITEMS))
|
step: Math.round(
|
||||||
|
daysInMarket /
|
||||||
|
Math.min(
|
||||||
|
daysInMarket,
|
||||||
|
this.configurationService.get('MAX_CHART_ITEMS')
|
||||||
|
)
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
const chartDates = sortBy(Object.keys(chartDateMap), (chartDate) => {
|
const chartDates = sortBy(Object.keys(chartDateMap), (chartDate) => {
|
||||||
@ -659,12 +664,6 @@ export abstract class PortfolioCalculator {
|
|||||||
return this.snapshot.totalLiabilitiesWithCurrencyEffect;
|
return this.snapshot.totalLiabilitiesWithCurrencyEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSnapshot() {
|
|
||||||
await this.snapshotPromise;
|
|
||||||
|
|
||||||
return this.snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getPerformance({ end, start }) {
|
public async getPerformance({ end, start }) {
|
||||||
await this.snapshotPromise;
|
await this.snapshotPromise;
|
||||||
|
|
||||||
@ -733,6 +732,12 @@ export abstract class PortfolioCalculator {
|
|||||||
return { chart };
|
return { chart };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getSnapshot() {
|
||||||
|
await this.snapshotPromise;
|
||||||
|
|
||||||
|
return this.snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
public getStartDate() {
|
public getStartDate() {
|
||||||
let firstAccountBalanceDate: Date;
|
let firstAccountBalanceDate: Date;
|
||||||
let firstActivityDate: Date;
|
let firstActivityDate: Date;
|
||||||
@ -813,9 +818,17 @@ export abstract class PortfolioCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (step > 1) {
|
if (step > 1) {
|
||||||
// Reduce the step size of recent dates
|
// Reduce the step size of last 90 days
|
||||||
for (let date of eachDayOfInterval(
|
for (let date of eachDayOfInterval(
|
||||||
{ end: endDate, start: subDays(endDate, 90) },
|
{ end: endDate, start: subDays(endDate, 90) },
|
||||||
|
{ step: 3 }
|
||||||
|
)) {
|
||||||
|
chartDateMap[format(date, DATE_FORMAT)] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the step size of last 30 days
|
||||||
|
for (let date of eachDayOfInterval(
|
||||||
|
{ end: endDate, start: subDays(endDate, 30) },
|
||||||
{ step: 1 }
|
{ step: 1 }
|
||||||
)) {
|
)) {
|
||||||
chartDateMap[format(date, DATE_FORMAT)] = true;
|
chartDateMap[format(date, DATE_FORMAT)] = true;
|
||||||
|
@ -42,6 +42,7 @@ export class ConfigurationService {
|
|||||||
HOST: host({ default: '0.0.0.0' }),
|
HOST: host({ default: '0.0.0.0' }),
|
||||||
JWT_SECRET_KEY: str({}),
|
JWT_SECRET_KEY: str({}),
|
||||||
MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }),
|
MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }),
|
||||||
|
MAX_CHART_ITEMS: num({ default: 365 }),
|
||||||
MAX_ITEM_IN_CACHE: num({ default: 9999 }),
|
MAX_ITEM_IN_CACHE: num({ default: 9999 }),
|
||||||
PORT: port({ default: 3333 }),
|
PORT: port({ default: 3333 }),
|
||||||
REDIS_DB: num({ default: 0 }),
|
REDIS_DB: num({ default: 0 }),
|
||||||
|
@ -28,6 +28,7 @@ export interface Environment extends CleanedEnvAccessors {
|
|||||||
GOOGLE_SHEETS_PRIVATE_KEY: string;
|
GOOGLE_SHEETS_PRIVATE_KEY: string;
|
||||||
JWT_SECRET_KEY: string;
|
JWT_SECRET_KEY: string;
|
||||||
MAX_ACTIVITIES_TO_IMPORT: number;
|
MAX_ACTIVITIES_TO_IMPORT: number;
|
||||||
|
MAX_CHART_ITEMS: number;
|
||||||
MAX_ITEM_IN_CACHE: number;
|
MAX_ITEM_IN_CACHE: number;
|
||||||
PORT: number;
|
PORT: number;
|
||||||
REDIS_DB: number;
|
REDIS_DB: number;
|
||||||
|
@ -88,7 +88,6 @@ export const HEADER_KEY_IMPERSONATION = 'Impersonation-Id';
|
|||||||
export const HEADER_KEY_TIMEZONE = 'Timezone';
|
export const HEADER_KEY_TIMEZONE = 'Timezone';
|
||||||
export const HEADER_KEY_TOKEN = 'Authorization';
|
export const HEADER_KEY_TOKEN = 'Authorization';
|
||||||
|
|
||||||
export const MAX_CHART_ITEMS = 365;
|
|
||||||
export const MAX_TOP_HOLDINGS = 50;
|
export const MAX_TOP_HOLDINGS = 50;
|
||||||
|
|
||||||
export const NUMERICAL_PRECISION_THRESHOLD = 100000;
|
export const NUMERICAL_PRECISION_THRESHOLD = 100000;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user