Browse Source

fix(api): move getCashOrders to order service

pull/5650/head
KenTandrian 3 weeks ago
parent
commit
7ebef0baf4
  1. 114
      apps/api/src/app/order/order.service.ts
  2. 119
      apps/api/src/app/portfolio/portfolio.service.ts

114
apps/api/src/app/order/order.service.ts

@ -1,7 +1,10 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface';
import { AssetProfileChangedEvent } from '@ghostfolio/api/events/asset-profile-changed.event';
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event';
import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor';
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 { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service';
@ -16,6 +19,7 @@ import {
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import {
ActivitiesResponse,
Activity,
AssetProfileIdentifier,
EnhancedSymbolProfile,
Filter
@ -43,7 +47,9 @@ import { v4 as uuidv4 } from 'uuid';
export class OrderService {
public constructor(
private readonly accountService: AccountService,
private readonly accountBalanceService: AccountBalanceService,
private readonly dataGatheringService: DataGatheringService,
private readonly dataProviderService: DataProviderService,
private readonly eventEmitter: EventEmitter2,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly prismaService: PrismaService,
@ -317,6 +323,96 @@ export class OrderService {
return count;
}
public async getCashOrders({
cashDetails,
userCurrency,
userId
}: {
cashDetails: CashDetails;
userCurrency: string;
userId: string;
}): Promise<ActivitiesResponse> {
const activities: 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:
this.dataProviderService.getDataSourceForExchangeRates(),
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
activities.push({
...syntheticActivityTemplate,
type: 'BUY',
value: balanceItem.value - currentBalance,
valueInBaseCurrency:
balanceItem.valueInBaseCurrency - currentBalanceInBaseCurrency
});
} else if (currentBalance > balanceItem.value) {
// SELL
activities.push({
...syntheticActivityTemplate,
type: 'SELL',
value: currentBalance - balanceItem.value,
valueInBaseCurrency:
currentBalanceInBaseCurrency - balanceItem.valueInBaseCurrency
});
}
currentBalance = balanceItem.value;
currentBalanceInBaseCurrency = balanceItem.valueInBaseCurrency;
}
}
return {
activities,
count: activities.length
};
}
public async getLatestOrder({ dataSource, symbol }: AssetProfileIdentifier) {
return this.prismaService.order.findFirst({
orderBy: {
@ -620,12 +716,28 @@ export class OrderService {
userCurrency: string;
userId: string;
}) {
return this.getOrders({
const cashDetails = await this.accountService.getCashDetails({
filters,
userId,
currency: userCurrency
});
const cashOrders = await this.getCashOrders({
cashDetails,
userCurrency,
userId
});
const nonCashOrders = await this.getOrders({
filters,
userCurrency,
userId,
withExcludedAccountsAndActivities: false // TODO
});
return {
activities: [...nonCashOrders.activities, ...cashOrders.activities],
count: nonCashOrders.count + cashOrders.count
};
}
public async getStatisticsByCurrency(

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

@ -318,93 +318,6 @@ 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:
this.dataProviderService.getDataSourceForExchangeRates(),
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
@ -588,16 +501,11 @@ export class PortfolioService {
userId,
currency: userCurrency
});
const cashActivities = await this.getCashActivities({
cashDetails,
userCurrency,
userId
});
const portfolioCalculator = this.calculatorFactory.createCalculator({
activities,
filters,
userId,
activities: [...activities, ...cashActivities],
calculationType: this.getUserPerformanceCalculationType(user),
currency: userCurrency
});
@ -715,10 +623,10 @@ export class PortfolioService {
allocationInPercentage: filteredValueInBaseCurrency.eq(0)
? 0
: valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(),
assetClass: assetProfile.assetClass,
assetSubClass: assetProfile.assetSubClass,
countries: assetProfile.countries,
dataSource: assetProfile.dataSource,
assetClass: assetProfile?.assetClass,
assetSubClass: assetProfile?.assetSubClass,
countries: assetProfile?.countries,
dataSource: assetProfile?.dataSource,
dateOfFirstActivity: parseDate(firstBuyDate),
dividend: dividend?.toNumber() ?? 0,
grossPerformance: grossPerformance?.toNumber() ?? 0,
@ -727,8 +635,8 @@ export class PortfolioService {
grossPerformancePercentageWithCurrencyEffect?.toNumber() ?? 0,
grossPerformanceWithCurrencyEffect:
grossPerformanceWithCurrencyEffect?.toNumber() ?? 0,
holdings: assetProfile.holdings.map(
({ allocationInPercentage, name }) => {
holdings:
assetProfile?.holdings.map(({ allocationInPercentage, name }) => {
return {
allocationInPercentage,
name,
@ -736,10 +644,9 @@ export class PortfolioService {
.mul(allocationInPercentage)
.toNumber()
};
}
),
}) ?? [],
investment: investment.toNumber(),
name: assetProfile.name,
name: assetProfile?.name,
netPerformance: netPerformance?.toNumber() ?? 0,
netPerformancePercent: netPerformancePercentage?.toNumber() ?? 0,
netPerformancePercentWithCurrencyEffect:
@ -749,8 +656,8 @@ export class PortfolioService {
netPerformanceWithCurrencyEffect:
netPerformanceWithCurrencyEffectMap?.[dateRange]?.toNumber() ?? 0,
quantity: quantity.toNumber(),
sectors: assetProfile.sectors,
url: assetProfile.url,
sectors: assetProfile?.sectors,
url: assetProfile?.url,
valueInBaseCurrency: valueInBaseCurrency.toNumber()
};
}
@ -2251,7 +2158,7 @@ export class PortfolioService {
accounts[account?.id || UNKNOWN_KEY] = {
balance: 0,
currency: account?.currency,
name: account.name,
name: account?.name,
valueInBaseCurrency: currentValueOfSymbolInBaseCurrency
};
}
@ -2265,7 +2172,7 @@ export class PortfolioService {
platforms[account?.platformId || UNKNOWN_KEY] = {
balance: 0,
currency: account?.currency,
name: account.platform?.name,
name: account?.platform?.name,
valueInBaseCurrency: currentValueOfSymbolInBaseCurrency
};
}

Loading…
Cancel
Save