Feature/improve portfolio details endpoint (#302)
* Make details endpoint fault tolerant (do not throw error) * Update changelog
This commit is contained in:
parent
c71a4c078e
commit
c2ab6a6c44
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved the fault tolerance of the portfolio details endpoint
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed the node engine version mismatch in `package.json`
|
- Fixed the node engine version mismatch in `package.json`
|
||||||
|
@ -125,17 +125,12 @@ export class PortfolioController {
|
|||||||
@Query('range') range,
|
@Query('range') range,
|
||||||
@Res() res: Response
|
@Res() res: Response
|
||||||
): Promise<{ [symbol: string]: PortfolioPosition }> {
|
): Promise<{ [symbol: string]: PortfolioPosition }> {
|
||||||
let details: { [symbol: string]: PortfolioPosition } = {};
|
const { details, hasErrors } = await this.portfolioService.getDetails(
|
||||||
|
impersonationId,
|
||||||
|
range
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
if (hasErrors || hasNotDefinedValuesInObject(details)) {
|
||||||
details = await this.portfolioService.getDetails(impersonationId, range);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
|
|
||||||
res.status(StatusCodes.ACCEPTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasNotDefinedValuesInObject(details)) {
|
|
||||||
res.status(StatusCodes.ACCEPTED);
|
res.status(StatusCodes.ACCEPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,10 @@ export class PortfolioService {
|
|||||||
public async getDetails(
|
public async getDetails(
|
||||||
aImpersonationId: string,
|
aImpersonationId: string,
|
||||||
aDateRange: DateRange = 'max'
|
aDateRange: DateRange = 'max'
|
||||||
): Promise<{ [symbol: string]: PortfolioPosition }> {
|
): Promise<{
|
||||||
|
details: { [symbol: string]: PortfolioPosition };
|
||||||
|
hasErrors: boolean;
|
||||||
|
}> {
|
||||||
const userId = await this.getUserId(aImpersonationId);
|
const userId = await this.getUserId(aImpersonationId);
|
||||||
|
|
||||||
const userCurrency = this.request.user.Settings.currency;
|
const userCurrency = this.request.user.Settings.currency;
|
||||||
@ -168,7 +171,7 @@ export class PortfolioService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (transactionPoints?.length <= 0) {
|
if (transactionPoints?.length <= 0) {
|
||||||
return {};
|
return { details: {}, hasErrors: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
portfolioCalculator.setTransactionPoints(transactionPoints);
|
portfolioCalculator.setTransactionPoints(transactionPoints);
|
||||||
@ -179,16 +182,12 @@ export class PortfolioService {
|
|||||||
startDate
|
startDate
|
||||||
);
|
);
|
||||||
|
|
||||||
if (currentPositions.hasErrors) {
|
|
||||||
throw new Error('Missing information');
|
|
||||||
}
|
|
||||||
|
|
||||||
const cashDetails = await this.accountService.getCashDetails(
|
const cashDetails = await this.accountService.getCashDetails(
|
||||||
userId,
|
userId,
|
||||||
userCurrency
|
userCurrency
|
||||||
);
|
);
|
||||||
|
|
||||||
const result: { [symbol: string]: PortfolioPosition } = {};
|
const details: { [symbol: string]: PortfolioPosition } = {};
|
||||||
const totalInvestment = currentPositions.totalInvestment.plus(
|
const totalInvestment = currentPositions.totalInvestment.plus(
|
||||||
cashDetails.balance
|
cashDetails.balance
|
||||||
);
|
);
|
||||||
@ -218,7 +217,7 @@ export class PortfolioService {
|
|||||||
const value = item.quantity.mul(item.marketPrice);
|
const value = item.quantity.mul(item.marketPrice);
|
||||||
const symbolProfile = symbolProfileMap[item.symbol];
|
const symbolProfile = symbolProfileMap[item.symbol];
|
||||||
const dataProviderResponse = dataProviderResponses[item.symbol];
|
const dataProviderResponse = dataProviderResponses[item.symbol];
|
||||||
result[item.symbol] = {
|
details[item.symbol] = {
|
||||||
accounts,
|
accounts,
|
||||||
allocationCurrent: value.div(totalValue).toNumber(),
|
allocationCurrent: value.div(totalValue).toNumber(),
|
||||||
allocationInvestment: item.investment.div(totalInvestment).toNumber(),
|
allocationInvestment: item.investment.div(totalInvestment).toNumber(),
|
||||||
@ -226,8 +225,9 @@ export class PortfolioService {
|
|||||||
countries: symbolProfile.countries,
|
countries: symbolProfile.countries,
|
||||||
currency: item.currency,
|
currency: item.currency,
|
||||||
exchange: dataProviderResponse.exchange,
|
exchange: dataProviderResponse.exchange,
|
||||||
grossPerformance: item.grossPerformance.toNumber(),
|
grossPerformance: item.grossPerformance?.toNumber() ?? 0,
|
||||||
grossPerformancePercent: item.grossPerformancePercentage.toNumber(),
|
grossPerformancePercent:
|
||||||
|
item.grossPerformancePercentage?.toNumber() ?? 0,
|
||||||
investment: item.investment.toNumber(),
|
investment: item.investment.toNumber(),
|
||||||
marketPrice: item.marketPrice,
|
marketPrice: item.marketPrice,
|
||||||
marketState: dataProviderResponse.marketState,
|
marketState: dataProviderResponse.marketState,
|
||||||
@ -241,13 +241,13 @@ export class PortfolioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add a cash position for each currency
|
// TODO: Add a cash position for each currency
|
||||||
result[ghostfolioCashSymbol] = await this.getCashPosition({
|
details[ghostfolioCashSymbol] = await this.getCashPosition({
|
||||||
cashDetails,
|
cashDetails,
|
||||||
investment: totalInvestment,
|
investment: totalInvestment,
|
||||||
value: totalValue
|
value: totalValue
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return { details, hasErrors: currentPositions.hasErrors };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getPosition(
|
public async getPosition(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user