Feature/add performance calculation type to user settings (#4567)
* Add performance calculation type to user settings * Update changelog
This commit is contained in:
parent
26b705cfea
commit
71fc3906c7
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
- Extended the benchmark detail dialog by the current market price
|
||||
- Added the performance calculation type to the user settings (experimental)
|
||||
- Added `watchlist` to the `User` database schema as a preparation for watching assets
|
||||
|
||||
### Changed
|
||||
|
@ -4,12 +4,17 @@ import {
|
||||
SymbolMetrics
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { PortfolioSnapshot } from '@ghostfolio/common/models';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
export class MwrPortfolioCalculator extends PortfolioCalculator {
|
||||
protected calculateOverallPerformance(): PortfolioSnapshot {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getPerformanceCalculationType() {
|
||||
return PerformanceCalculationType.MWR;
|
||||
}
|
||||
|
||||
protected getSymbolMetrics({}: {
|
||||
end: Date;
|
||||
exchangeRates: { [dateString: string]: number };
|
||||
|
@ -5,20 +5,16 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { Filter, HistoricalDataItem } from '@ghostfolio/common/interfaces';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { MwrPortfolioCalculator } from './mwr/portfolio-calculator';
|
||||
import { PortfolioCalculator } from './portfolio-calculator';
|
||||
import { RoaiPortfolioCalculator } from './roai/portfolio-calculator';
|
||||
import { RoiPortfolioCalculator } from './roi/portfolio-calculator';
|
||||
import { TwrPortfolioCalculator } from './twr/portfolio-calculator';
|
||||
|
||||
export enum PerformanceCalculationType {
|
||||
MWR = 'MWR', // Money-Weighted Rate of Return
|
||||
ROAI = 'ROAI', // Return on Average Investment
|
||||
TWR = 'TWR' // Time-Weighted Rate of Return
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class PortfolioCalculatorFactory {
|
||||
public constructor(
|
||||
@ -58,6 +54,7 @@ export class PortfolioCalculatorFactory {
|
||||
portfolioSnapshotService: this.portfolioSnapshotService,
|
||||
redisCacheService: this.redisCacheService
|
||||
});
|
||||
|
||||
case PerformanceCalculationType.ROAI:
|
||||
return new RoaiPortfolioCalculator({
|
||||
accountBalanceItems,
|
||||
@ -71,6 +68,21 @@ export class PortfolioCalculatorFactory {
|
||||
portfolioSnapshotService: this.portfolioSnapshotService,
|
||||
redisCacheService: this.redisCacheService
|
||||
});
|
||||
|
||||
case PerformanceCalculationType.ROI:
|
||||
return new RoiPortfolioCalculator({
|
||||
accountBalanceItems,
|
||||
activities,
|
||||
currency,
|
||||
filters,
|
||||
userId,
|
||||
configurationService: this.configurationService,
|
||||
currentRateService: this.currentRateService,
|
||||
exchangeRateDataService: this.exchangeRateDataService,
|
||||
portfolioSnapshotService: this.portfolioSnapshotService,
|
||||
redisCacheService: this.redisCacheService
|
||||
});
|
||||
|
||||
case PerformanceCalculationType.TWR:
|
||||
return new TwrPortfolioCalculator({
|
||||
accountBalanceItems,
|
||||
@ -84,6 +96,7 @@ export class PortfolioCalculatorFactory {
|
||||
portfolioSnapshotService: this.portfolioSnapshotService,
|
||||
redisCacheService: this.redisCacheService
|
||||
});
|
||||
|
||||
default:
|
||||
throw new Error('Invalid calculation type');
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import {
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { PortfolioSnapshot, TimelinePosition } from '@ghostfolio/common/models';
|
||||
import { GroupBy } from '@ghostfolio/common/types';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Big } from 'big.js';
|
||||
@ -623,6 +624,8 @@ export abstract class PortfolioCalculator {
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract getPerformanceCalculationType(): PerformanceCalculationType;
|
||||
|
||||
public getDataProviderInfos() {
|
||||
return this.dataProviderInfos;
|
||||
}
|
||||
@ -1073,6 +1076,7 @@ export abstract class PortfolioCalculator {
|
||||
// Compute in the background
|
||||
this.portfolioSnapshotService.addJobToQueue({
|
||||
data: {
|
||||
calculationType: this.getPerformanceCalculationType(),
|
||||
filters: this.filters,
|
||||
userCurrency: this.currency,
|
||||
userId: this.userId
|
||||
@ -1089,6 +1093,7 @@ export abstract class PortfolioCalculator {
|
||||
// Wait for computation
|
||||
await this.portfolioSnapshotService.addJobToQueue({
|
||||
data: {
|
||||
calculationType: this.getPerformanceCalculationType(),
|
||||
filters: this.filters,
|
||||
userCurrency: this.currency,
|
||||
userId: this.userId
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -17,6 +14,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -17,6 +14,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -17,6 +14,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -18,6 +15,7 @@ import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-r
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -17,6 +14,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -18,6 +15,7 @@ import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-r
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -17,6 +14,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PortfolioCalculatorFactory,
|
||||
PerformanceCalculationType
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -17,6 +14,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -18,6 +15,7 @@ import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-r
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -12,6 +9,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
|
||||
|
@ -6,10 +6,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -19,6 +16,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
import { join } from 'path';
|
||||
|
@ -6,10 +6,7 @@ import {
|
||||
symbolProfileDummyData,
|
||||
userDummyData
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -19,6 +16,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
|
||||
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
|
||||
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
|
||||
import { parseDate } from '@ghostfolio/common/helper';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Big } from 'big.js';
|
||||
import { join } from 'path';
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { PortfolioSnapshot, TimelinePosition } from '@ghostfolio/common/models';
|
||||
import { DateRange } from '@ghostfolio/common/types';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Big } from 'big.js';
|
||||
@ -112,6 +113,10 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
};
|
||||
}
|
||||
|
||||
protected getPerformanceCalculationType() {
|
||||
return PerformanceCalculationType.ROAI;
|
||||
}
|
||||
|
||||
protected getSymbolMetrics({
|
||||
chartDateMap,
|
||||
dataSource,
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator';
|
||||
import {
|
||||
AssetProfileIdentifier,
|
||||
SymbolMetrics
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { PortfolioSnapshot } from '@ghostfolio/common/models';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
export class RoiPortfolioCalculator extends PortfolioCalculator {
|
||||
protected calculateOverallPerformance(): PortfolioSnapshot {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getPerformanceCalculationType() {
|
||||
return PerformanceCalculationType.ROI;
|
||||
}
|
||||
|
||||
protected getSymbolMetrics({}: {
|
||||
end: Date;
|
||||
exchangeRates: { [dateString: string]: number };
|
||||
marketSymbolMap: {
|
||||
[date: string]: { [symbol: string]: Big };
|
||||
};
|
||||
start: Date;
|
||||
step?: number;
|
||||
} & AssetProfileIdentifier): SymbolMetrics {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
@ -4,12 +4,17 @@ import {
|
||||
SymbolMetrics
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { PortfolioSnapshot } from '@ghostfolio/common/models';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
export class TwrPortfolioCalculator extends PortfolioCalculator {
|
||||
protected calculateOverallPerformance(): PortfolioSnapshot {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getPerformanceCalculationType() {
|
||||
return PerformanceCalculationType.TWR;
|
||||
}
|
||||
|
||||
protected getSymbolMetrics({}: {
|
||||
end: Date;
|
||||
exchangeRates: { [dateString: string]: number };
|
||||
|
@ -50,13 +50,14 @@ import {
|
||||
UserSettings
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { TimelinePosition } from '@ghostfolio/common/models';
|
||||
import type {
|
||||
import {
|
||||
AccountWithValue,
|
||||
DateRange,
|
||||
GroupBy,
|
||||
RequestWithUser,
|
||||
UserWithSettings
|
||||
} from '@ghostfolio/common/types';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
@ -85,10 +86,7 @@ import {
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { PortfolioCalculator } from './calculator/portfolio-calculator';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from './calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from './calculator/portfolio-calculator.factory';
|
||||
import { PortfolioHoldingDetail } from './interfaces/portfolio-holding-detail.interface';
|
||||
import { RulesService } from './rules.service';
|
||||
|
||||
@ -278,14 +276,16 @@ export class PortfolioService {
|
||||
savingsRate: number;
|
||||
}): Promise<PortfolioInvestments> {
|
||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
||||
const user = await this.userService.user({ id: userId });
|
||||
const userCurrency = this.getUserCurrency(user);
|
||||
|
||||
const { endDate, startDate } = getIntervalFromDateRange(dateRange);
|
||||
|
||||
const { activities } =
|
||||
await this.orderService.getOrdersForPortfolioCalculator({
|
||||
filters,
|
||||
userId,
|
||||
userCurrency: this.getUserCurrency()
|
||||
userCurrency,
|
||||
userId
|
||||
});
|
||||
|
||||
if (activities.length === 0) {
|
||||
@ -299,8 +299,8 @@ export class PortfolioService {
|
||||
activities,
|
||||
filters,
|
||||
userId,
|
||||
calculationType: PerformanceCalculationType.ROAI,
|
||||
currency: this.request.user.Settings.settings.baseCurrency
|
||||
calculationType: this.getUserPerformanceCalculationType(user),
|
||||
currency: userCurrency
|
||||
});
|
||||
|
||||
const { historicalData } = await portfolioCalculator.getSnapshot();
|
||||
@ -376,7 +376,7 @@ export class PortfolioService {
|
||||
activities,
|
||||
filters,
|
||||
userId,
|
||||
calculationType: PerformanceCalculationType.ROAI,
|
||||
calculationType: this.getUserPerformanceCalculationType(user),
|
||||
currency: userCurrency
|
||||
});
|
||||
|
||||
@ -684,7 +684,7 @@ export class PortfolioService {
|
||||
const portfolioCalculator = this.calculatorFactory.createCalculator({
|
||||
activities,
|
||||
userId,
|
||||
calculationType: PerformanceCalculationType.ROAI,
|
||||
calculationType: this.getUserPerformanceCalculationType(user),
|
||||
currency: userCurrency
|
||||
});
|
||||
|
||||
@ -935,12 +935,13 @@ export class PortfolioService {
|
||||
})?.id;
|
||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
||||
const user = await this.userService.user({ id: userId });
|
||||
const userCurrency = this.getUserCurrency(user);
|
||||
|
||||
const { activities } =
|
||||
await this.orderService.getOrdersForPortfolioCalculator({
|
||||
filters,
|
||||
userId,
|
||||
userCurrency: this.getUserCurrency()
|
||||
userCurrency,
|
||||
userId
|
||||
});
|
||||
|
||||
if (activities.length === 0) {
|
||||
@ -954,8 +955,8 @@ export class PortfolioService {
|
||||
activities,
|
||||
filters,
|
||||
userId,
|
||||
calculationType: PerformanceCalculationType.ROAI,
|
||||
currency: this.request.user.Settings.settings.baseCurrency
|
||||
calculationType: this.getUserPerformanceCalculationType(user),
|
||||
currency: userCurrency
|
||||
});
|
||||
|
||||
const portfolioSnapshot = await portfolioCalculator.getSnapshot();
|
||||
@ -1120,7 +1121,7 @@ export class PortfolioService {
|
||||
activities,
|
||||
filters,
|
||||
userId,
|
||||
calculationType: PerformanceCalculationType.ROAI,
|
||||
calculationType: this.getUserPerformanceCalculationType(user),
|
||||
currency: userCurrency
|
||||
});
|
||||
|
||||
@ -2021,6 +2022,12 @@ export class PortfolioService {
|
||||
return impersonationUserId || aUserId;
|
||||
}
|
||||
|
||||
private getUserPerformanceCalculationType(
|
||||
aUser: UserWithSettings
|
||||
): PerformanceCalculationType {
|
||||
return aUser?.Settings?.settings.performanceCalculationType;
|
||||
}
|
||||
|
||||
private async getValueOfAccountsAndPlatforms({
|
||||
activities,
|
||||
filters = [],
|
||||
|
@ -41,6 +41,7 @@ import {
|
||||
permissions
|
||||
} from '@ghostfolio/common/permissions';
|
||||
import { UserWithSettings } from '@ghostfolio/common/types';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
@ -246,6 +247,12 @@ export class UserService {
|
||||
? 'max'
|
||||
: ((user.Settings.settings as UserSettings)?.dateRange ?? 'max');
|
||||
|
||||
// Set default value for performance calculation type
|
||||
if (!(user.Settings.settings as UserSettings)?.performanceCalculationType) {
|
||||
(user.Settings.settings as UserSettings).performanceCalculationType =
|
||||
PerformanceCalculationType.ROAI;
|
||||
}
|
||||
|
||||
// Set default value for view mode
|
||||
if (!(user.Settings.settings as UserSettings).viewMode) {
|
||||
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Filter } from '@ghostfolio/common/interfaces';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
export interface IPortfolioSnapshotQueueJob {
|
||||
calculationType: PerformanceCalculationType;
|
||||
filters: Filter[];
|
||||
userCurrency: string;
|
||||
userId: string;
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
|
||||
import { OrderService } from '@ghostfolio/api/app/order/order.service';
|
||||
import {
|
||||
PerformanceCalculationType,
|
||||
PortfolioCalculatorFactory
|
||||
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
|
||||
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
|
||||
@ -68,7 +65,7 @@ export class PortfolioSnapshotProcessor {
|
||||
const portfolioCalculator = this.calculatorFactory.createCalculator({
|
||||
accountBalanceItems,
|
||||
activities,
|
||||
calculationType: PerformanceCalculationType.ROAI,
|
||||
calculationType: job.data.calculationType,
|
||||
currency: job.data.userCurrency,
|
||||
filters: job.data.filters,
|
||||
userId: job.data.userId
|
||||
|
@ -2,25 +2,7 @@
|
||||
<h1 class="d-none d-sm-block h3 mb-3 text-center" i18n>Settings</h1>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="align-items-center d-flex py-1">
|
||||
<div class="pr-1 w-50">
|
||||
<div i18n>Presenter View</div>
|
||||
<div class="hint-text text-muted" i18n>
|
||||
Protection for sensitive information like absolute performances and
|
||||
quantity values
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-1 w-50">
|
||||
<mat-slide-toggle
|
||||
color="primary"
|
||||
hideIcon="true"
|
||||
[checked]="user.settings.isRestrictedView"
|
||||
[disabled]="!hasPermissionToUpdateUserSettings"
|
||||
(change)="onRestrictedViewChange($event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex mt-4 py-1">
|
||||
<div class="d-flex py-1">
|
||||
<form #changeUserSettingsForm="ngForm" class="w-100">
|
||||
<div class="d-flex mb-2">
|
||||
<div class="align-items-center d-flex pt-1 pt-1 w-50">
|
||||
@ -43,6 +25,32 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
@if (user?.settings?.isExperimentalFeatures && !user?.subscription) {
|
||||
<div class="d-flex mb-2">
|
||||
<div class="align-items-center d-flex pt-1 pt-1 w-50">
|
||||
<ng-container i18n>Performance Calculation</ng-container>
|
||||
</div>
|
||||
<div class="pl-1 w-50">
|
||||
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||
<mat-select
|
||||
name="performanceCalculationType"
|
||||
[disabled]="true"
|
||||
[value]="user.settings.performanceCalculationType"
|
||||
(selectionChange)="
|
||||
onChangeUserSetting(
|
||||
'performanceCalculationType',
|
||||
$event.value
|
||||
)
|
||||
"
|
||||
>
|
||||
<mat-option value="ROAI"
|
||||
>Return on Average Investment (ROAI)</mat-option
|
||||
>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="align-items-center d-flex mb-2">
|
||||
<div class="pr-1 w-50">
|
||||
<div i18n>Language</div>
|
||||
@ -172,6 +180,24 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="align-items-center d-flex mt-4 py-1">
|
||||
<div class="pr-1 w-50">
|
||||
<div i18n>Presenter View</div>
|
||||
<div class="hint-text text-muted" i18n>
|
||||
Protection for sensitive information like absolute performances and
|
||||
quantity values
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-1 w-50">
|
||||
<mat-slide-toggle
|
||||
color="primary"
|
||||
hideIcon="true"
|
||||
[checked]="user.settings.isRestrictedView"
|
||||
[disabled]="!hasPermissionToUpdateUserSettings"
|
||||
(change)="onRestrictedViewChange($event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex mt-4 py-1">
|
||||
<div class="pr-1 w-50">
|
||||
<div i18n>Zen Mode</div>
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
HoldingsViewMode,
|
||||
ViewMode
|
||||
} from '@ghostfolio/common/types';
|
||||
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
|
||||
|
||||
export interface UserSettings {
|
||||
annualInterestRate?: number;
|
||||
@ -22,6 +23,7 @@ export interface UserSettings {
|
||||
isRestrictedView?: boolean;
|
||||
language?: string;
|
||||
locale?: string;
|
||||
performanceCalculationType?: PerformanceCalculationType;
|
||||
projectedTotalAmount?: number;
|
||||
retirementDate?: string;
|
||||
savingsRate?: number;
|
||||
|
@ -0,0 +1,6 @@
|
||||
export enum PerformanceCalculationType {
|
||||
MWR = 'MWR', // Money-Weighted Rate of Return
|
||||
ROAI = 'ROAI', // Return on Average Investment
|
||||
ROI = 'ROI', // Return on Investment
|
||||
TWR = 'TWR' // Time-Weighted Rate of Return
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user