Feature/extend holding endpoint by performances (#4660)
* Extend holding endpoint by performances * Update changelog
This commit is contained in:
parent
40d3eaa023
commit
c38dab5ab0
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Extended the endpoint to get a holding by the date of the last all time high and the current change to the all time high
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improved the language localization for Turkish (`tr`)
|
- Improved the language localization for Turkish (`tr`)
|
||||||
|
@ -8,6 +8,7 @@ import { RulesService } from '@ghostfolio/api/app/portfolio/rules.service';
|
|||||||
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
|
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
|
||||||
import { UserModule } from '@ghostfolio/api/app/user/user.module';
|
import { UserModule } from '@ghostfolio/api/app/user/user.module';
|
||||||
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
|
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
|
||||||
|
import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module';
|
||||||
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.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';
|
||||||
@ -27,6 +28,7 @@ import { AiService } from './ai.service';
|
|||||||
controllers: [AiController],
|
controllers: [AiController],
|
||||||
imports: [
|
imports: [
|
||||||
ApiModule,
|
ApiModule,
|
||||||
|
BenchmarkModule,
|
||||||
ConfigurationModule,
|
ConfigurationModule,
|
||||||
DataProviderModule,
|
DataProviderModule,
|
||||||
ExchangeRateDataModule,
|
ExchangeRateDataModule,
|
||||||
|
@ -9,6 +9,7 @@ import { RulesService } from '@ghostfolio/api/app/portfolio/rules.service';
|
|||||||
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
|
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
|
||||||
import { UserModule } from '@ghostfolio/api/app/user/user.module';
|
import { UserModule } from '@ghostfolio/api/app/user/user.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 { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.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 { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module';
|
import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module';
|
||||||
@ -25,6 +26,7 @@ import { PublicController } from './public.controller';
|
|||||||
controllers: [PublicController],
|
controllers: [PublicController],
|
||||||
imports: [
|
imports: [
|
||||||
AccessModule,
|
AccessModule,
|
||||||
|
BenchmarkModule,
|
||||||
DataProviderModule,
|
DataProviderModule,
|
||||||
ExchangeRateDataModule,
|
ExchangeRateDataModule,
|
||||||
ImpersonationModule,
|
ImpersonationModule,
|
||||||
|
@ -9,6 +9,7 @@ import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redac
|
|||||||
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 { ApiModule } from '@ghostfolio/api/services/api/api.module';
|
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
|
||||||
|
import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module';
|
||||||
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.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';
|
||||||
@ -33,6 +34,7 @@ import { RulesService } from './rules.service';
|
|||||||
imports: [
|
imports: [
|
||||||
AccessModule,
|
AccessModule,
|
||||||
ApiModule,
|
ApiModule,
|
||||||
|
BenchmarkModule,
|
||||||
ConfigurationModule,
|
ConfigurationModule,
|
||||||
DataGatheringModule,
|
DataGatheringModule,
|
||||||
DataProviderModule,
|
DataProviderModule,
|
||||||
|
@ -20,6 +20,7 @@ import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models
|
|||||||
import { RegionalMarketClusterRiskEurope } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/europe';
|
import { RegionalMarketClusterRiskEurope } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/europe';
|
||||||
import { RegionalMarketClusterRiskJapan } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/japan';
|
import { RegionalMarketClusterRiskJapan } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/japan';
|
||||||
import { RegionalMarketClusterRiskNorthAmerica } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/north-america';
|
import { RegionalMarketClusterRiskNorthAmerica } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/north-america';
|
||||||
|
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.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 { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service';
|
import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service';
|
||||||
@ -100,6 +101,7 @@ export class PortfolioService {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private readonly accountBalanceService: AccountBalanceService,
|
private readonly accountBalanceService: AccountBalanceService,
|
||||||
private readonly accountService: AccountService,
|
private readonly accountService: AccountService,
|
||||||
|
private readonly benchmarkService: BenchmarkService,
|
||||||
private readonly calculatorFactory: PortfolioCalculatorFactory,
|
private readonly calculatorFactory: PortfolioCalculatorFactory,
|
||||||
private readonly dataProviderService: DataProviderService,
|
private readonly dataProviderService: DataProviderService,
|
||||||
private readonly exchangeRateDataService: ExchangeRateDataService,
|
private readonly exchangeRateDataService: ExchangeRateDataService,
|
||||||
@ -669,6 +671,7 @@ export class PortfolioService {
|
|||||||
netPerformancePercent: undefined,
|
netPerformancePercent: undefined,
|
||||||
netPerformancePercentWithCurrencyEffect: undefined,
|
netPerformancePercentWithCurrencyEffect: undefined,
|
||||||
netPerformanceWithCurrencyEffect: undefined,
|
netPerformanceWithCurrencyEffect: undefined,
|
||||||
|
performances: undefined,
|
||||||
quantity: undefined,
|
quantity: undefined,
|
||||||
SymbolProfile: undefined,
|
SymbolProfile: undefined,
|
||||||
tags: [],
|
tags: [],
|
||||||
@ -752,6 +755,10 @@ export class PortfolioService {
|
|||||||
activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
|
activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
|
||||||
marketPrice
|
marketPrice
|
||||||
);
|
);
|
||||||
|
let marketPriceMaxDate =
|
||||||
|
marketPrice > activitiesOfHolding[0].unitPriceInAssetProfileCurrency
|
||||||
|
? new Date()
|
||||||
|
: activitiesOfHolding[0].date;
|
||||||
let marketPriceMin = Math.min(
|
let marketPriceMin = Math.min(
|
||||||
activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
|
activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
|
||||||
marketPrice
|
marketPrice
|
||||||
@ -793,7 +800,10 @@ export class PortfolioService {
|
|||||||
quantity: currentQuantity
|
quantity: currentQuantity
|
||||||
});
|
});
|
||||||
|
|
||||||
marketPriceMax = Math.max(marketPrice ?? 0, marketPriceMax);
|
if (marketPrice > marketPriceMax) {
|
||||||
|
marketPriceMax = marketPrice;
|
||||||
|
marketPriceMaxDate = parseISO(date);
|
||||||
|
}
|
||||||
marketPriceMin = Math.min(
|
marketPriceMin = Math.min(
|
||||||
marketPrice ?? Number.MAX_SAFE_INTEGER,
|
marketPrice ?? Number.MAX_SAFE_INTEGER,
|
||||||
marketPriceMin
|
marketPriceMin
|
||||||
@ -809,6 +819,12 @@ export class PortfolioService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const performancePercent =
|
||||||
|
this.benchmarkService.calculateChangeInPercentage(
|
||||||
|
marketPriceMax,
|
||||||
|
marketPrice
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
firstBuyDate,
|
firstBuyDate,
|
||||||
marketPrice,
|
marketPrice,
|
||||||
@ -846,6 +862,12 @@ export class PortfolioService {
|
|||||||
]?.toNumber(),
|
]?.toNumber(),
|
||||||
netPerformanceWithCurrencyEffect:
|
netPerformanceWithCurrencyEffect:
|
||||||
position.netPerformanceWithCurrencyEffectMap?.['max']?.toNumber(),
|
position.netPerformanceWithCurrencyEffectMap?.['max']?.toNumber(),
|
||||||
|
performances: {
|
||||||
|
allTimeHigh: {
|
||||||
|
performancePercent,
|
||||||
|
date: marketPriceMaxDate
|
||||||
|
}
|
||||||
|
},
|
||||||
quantity: quantity.toNumber(),
|
quantity: quantity.toNumber(),
|
||||||
value: this.exchangeRateDataService.toCurrency(
|
value: this.exchangeRateDataService.toCurrency(
|
||||||
quantity.mul(marketPrice ?? 0).toNumber(),
|
quantity.mul(marketPrice ?? 0).toNumber(),
|
||||||
@ -885,6 +907,7 @@ export class PortfolioService {
|
|||||||
|
|
||||||
const historicalDataArray: HistoricalDataItem[] = [];
|
const historicalDataArray: HistoricalDataItem[] = [];
|
||||||
let marketPriceMax = marketPrice;
|
let marketPriceMax = marketPrice;
|
||||||
|
let marketPriceMaxDate = new Date();
|
||||||
let marketPriceMin = marketPrice;
|
let marketPriceMin = marketPrice;
|
||||||
|
|
||||||
for (const [date, { marketPrice }] of Object.entries(
|
for (const [date, { marketPrice }] of Object.entries(
|
||||||
@ -895,13 +918,22 @@ export class PortfolioService {
|
|||||||
value: marketPrice
|
value: marketPrice
|
||||||
});
|
});
|
||||||
|
|
||||||
marketPriceMax = Math.max(marketPrice ?? 0, marketPriceMax);
|
if (marketPrice > marketPriceMax) {
|
||||||
|
marketPriceMax = marketPrice;
|
||||||
|
marketPriceMaxDate = parseISO(date);
|
||||||
|
}
|
||||||
marketPriceMin = Math.min(
|
marketPriceMin = Math.min(
|
||||||
marketPrice ?? Number.MAX_SAFE_INTEGER,
|
marketPrice ?? Number.MAX_SAFE_INTEGER,
|
||||||
marketPriceMin
|
marketPriceMin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const performancePercent =
|
||||||
|
this.benchmarkService.calculateChangeInPercentage(
|
||||||
|
marketPriceMax,
|
||||||
|
marketPrice
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
marketPrice,
|
marketPrice,
|
||||||
marketPriceMax,
|
marketPriceMax,
|
||||||
@ -925,6 +957,12 @@ export class PortfolioService {
|
|||||||
netPerformancePercent: undefined,
|
netPerformancePercent: undefined,
|
||||||
netPerformancePercentWithCurrencyEffect: undefined,
|
netPerformancePercentWithCurrencyEffect: undefined,
|
||||||
netPerformanceWithCurrencyEffect: undefined,
|
netPerformanceWithCurrencyEffect: undefined,
|
||||||
|
performances: {
|
||||||
|
allTimeHigh: {
|
||||||
|
performancePercent,
|
||||||
|
date: marketPriceMaxDate
|
||||||
|
}
|
||||||
|
},
|
||||||
quantity: 0,
|
quantity: 0,
|
||||||
tags: [],
|
tags: [],
|
||||||
transactionCount: undefined,
|
transactionCount: undefined,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
|
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
|
||||||
import {
|
import {
|
||||||
|
Benchmark,
|
||||||
DataProviderInfo,
|
DataProviderInfo,
|
||||||
EnhancedSymbolProfile,
|
EnhancedSymbolProfile,
|
||||||
HistoricalDataItem
|
HistoricalDataItem
|
||||||
@ -29,6 +30,7 @@ export interface PortfolioHoldingResponse {
|
|||||||
netPerformancePercent: number;
|
netPerformancePercent: number;
|
||||||
netPerformancePercentWithCurrencyEffect: number;
|
netPerformancePercentWithCurrencyEffect: number;
|
||||||
netPerformanceWithCurrencyEffect: number;
|
netPerformanceWithCurrencyEffect: number;
|
||||||
|
performances: Benchmark['performances'];
|
||||||
quantity: number;
|
quantity: number;
|
||||||
SymbolProfile: EnhancedSymbolProfile;
|
SymbolProfile: EnhancedSymbolProfile;
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user