Browse Source

Merge e8918b147f into 7dc74fe681

pull/5650/merge
Kenrick Tandrian 2 days ago
committed by GitHub
parent
commit
a21c2ed015
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 107
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 4
      apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts
  4. 5
      apps/api/src/services/exchange-rate-data/interfaces/exchange-rate-data.interface.ts

1
CHANGELOG.md

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added a close holding button to the holding detail dialog
- Extended the holdings endpoint to include the performance with currency effect for cash
- Extended the user detail dialog in the users section of the admin control panel
### Changed

107
apps/api/src/app/portfolio/portfolio.service.ts

@ -319,6 +319,92 @@ export class PortfolioService {
};
}
public async getCashActivities({
cashDetails,
userCurrency,
userId
}: {
cashDetails: CashDetails;
userCurrency: string;
userId: string;
}) {
const syntheticActivities: Activity[] = [];
for (const account of cashDetails.accounts) {
const { balances } = await this.accountBalanceService.getAccountBalances({
filters: [{ id: account.id, type: 'ACCOUNT' }],
userCurrency,
userId
});
let currentBalance = 0;
let currentBalanceInBaseCurrency = 0;
for (const balanceItem of balances) {
const syntheticActivityTemplate: Activity = {
userId,
accountId: account.id,
accountUserId: account.userId,
comment: account.name,
createdAt: new Date(balanceItem.date),
currency: account.currency,
date: new Date(balanceItem.date),
fee: 0,
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
id: balanceItem.id,
isDraft: false,
quantity: 1,
SymbolProfile: {
activitiesCount: 0,
assetClass: 'LIQUIDITY',
assetSubClass: 'CASH',
countries: [],
createdAt: new Date(balanceItem.date),
currency: account.currency,
dataSource: 'YAHOO',
holdings: [],
id: account.currency,
isActive: true,
sectors: [],
symbol: account.currency,
updatedAt: new Date(balanceItem.date)
},
symbolProfileId: account.currency,
type: 'BUY',
unitPrice: 1,
unitPriceInAssetProfileCurrency: 1,
updatedAt: new Date(balanceItem.date),
valueInBaseCurrency: 0,
value: 0
};
if (currentBalance < balanceItem.value) {
// BUY
syntheticActivities.push({
...syntheticActivityTemplate,
type: 'BUY',
value: balanceItem.value - currentBalance,
valueInBaseCurrency:
balanceItem.valueInBaseCurrency - currentBalanceInBaseCurrency
});
} else if (currentBalance > balanceItem.value) {
// SELL
syntheticActivities.push({
...syntheticActivityTemplate,
type: 'SELL',
value: currentBalance - balanceItem.value,
valueInBaseCurrency:
currentBalanceInBaseCurrency - balanceItem.valueInBaseCurrency
});
}
currentBalance = balanceItem.value;
currentBalanceInBaseCurrency = balanceItem.valueInBaseCurrency;
}
}
return syntheticActivities;
}
public async getDividends({
activities,
groupBy
@ -488,6 +574,7 @@ export class PortfolioService {
(user.settings?.settings as UserSettings)?.emergencyFund ?? 0
);
// Activities for non-cash assets
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
filters,
@ -495,23 +582,29 @@ export class PortfolioService {
userId
});
const portfolioCalculator = this.calculatorFactory.createCalculator({
activities,
// Synthetic activities for cash
const cashDetails = await this.accountService.getCashDetails({
filters,
userId,
calculationType: this.getUserPerformanceCalculationType(user),
currency: userCurrency
});
const cashActivities = await this.getCashActivities({
cashDetails,
userCurrency,
userId
});
const { createdAt, currentValueInBaseCurrency, hasErrors, positions } =
await portfolioCalculator.getSnapshot();
const cashDetails = await this.accountService.getCashDetails({
const portfolioCalculator = this.calculatorFactory.createCalculator({
filters,
userId,
activities: [...activities, ...cashActivities],
calculationType: this.getUserPerformanceCalculationType(user),
currency: userCurrency
});
const { createdAt, currentValueInBaseCurrency, hasErrors, positions } =
await portfolioCalculator.getSnapshot();
const holdings: PortfolioDetails['holdings'] = {};
const totalValueInBaseCurrency = currentValueInBaseCurrency.plus(

4
apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts

@ -26,6 +26,8 @@ import {
import { isNumber } from 'lodash';
import ms from 'ms';
import { ExchangeRatesByCurrency } from './interfaces/exchange-rate-data.interface';
@Injectable()
export class ExchangeRateDataService {
private currencies: string[] = [];
@ -58,7 +60,7 @@ export class ExchangeRateDataService {
endDate?: Date;
startDate: Date;
targetCurrency: string;
}) {
}): Promise<ExchangeRatesByCurrency> {
if (!startDate) {
return {};
}

5
apps/api/src/services/exchange-rate-data/interfaces/exchange-rate-data.interface.ts

@ -0,0 +1,5 @@
export interface ExchangeRatesByCurrency {
[currency: string]: {
[dateString: string]: number;
};
}
Loading…
Cancel
Save