Browse Source

Task/deprecate transactionCount in portfolio calculator and service (#6228)

* Deprecate transactionCount in favor of activitiesCount

* Update changelog
pull/5150/merge
Thomas Kaul 1 day ago
committed by GitHub
parent
commit
71902e39d1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 3
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  3. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts
  4. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts
  5. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts
  6. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts
  7. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts
  8. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts
  9. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts
  10. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts
  11. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts
  12. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts
  13. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
  14. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts
  15. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts
  16. 3
      apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts
  17. 22
      apps/api/src/app/portfolio/portfolio.service.ts
  18. 4
      libs/common/src/lib/interfaces/portfolio-position.interface.ts
  19. 3
      libs/common/src/lib/interfaces/responses/accounts-response.interface.ts
  20. 3
      libs/common/src/lib/models/timeline-position.ts
  21. 4
      libs/common/src/lib/types/account-with-value.type.ts
  22. 7
      libs/ui/src/lib/mocks/holdings.ts

1
CHANGELOG.md

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Deprecated `transactionCount` in favor of `activitiesCount` in the portfolio calculator and service
- Removed the deprecated `firstBuyDate` from the endpoint `GET api/v1/portfolio/holding/:dataSource/:symbol`
## 2.232.0 - 2026-01-19

3
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -407,6 +407,7 @@ export abstract class PortfolioCalculator {
includeInTotalAssetValue,
timeWeightedInvestment,
timeWeightedInvestmentWithCurrencyEffect,
activitiesCount: item.activitiesCount,
averagePrice: item.averagePrice,
currency: item.currency,
dataSource: item.dataSource,
@ -993,6 +994,7 @@ export abstract class PortfolioCalculator {
investment,
skipErrors,
symbol,
activitiesCount: oldAccumulatedSymbol.activitiesCount + 1,
averagePrice: newQuantity.eq(0)
? new Big(0)
: investment.div(newQuantity).abs(),
@ -1016,6 +1018,7 @@ export abstract class PortfolioCalculator {
skipErrors,
symbol,
tags,
activitiesCount: 1,
averagePrice: unitPrice,
dividend: new Big(0),
firstBuyDate: date,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts

@ -139,6 +139,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 2,
averagePrice: new Big('139.75'),
currency: 'CHF',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts

@ -155,6 +155,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 3,
averagePrice: new Big('0'),
currency: 'CHF',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -139,6 +139,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 2,
averagePrice: new Big('0'),
currency: 'CHF',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts

@ -129,6 +129,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 1,
averagePrice: new Big('136.6'),
currency: 'CHF',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts

@ -190,6 +190,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 1,
averagePrice: new Big('44558.42'),
currency: 'USD',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts

@ -153,6 +153,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 2,
averagePrice: new Big('320.43'),
currency: 'USD',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts

@ -190,6 +190,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 1,
averagePrice: new Big('44558.42'),
currency: 'USD',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts

@ -230,6 +230,7 @@ describe('PortfolioCalculator', () => {
* Value in base currency: 2000 USD * 0.91 = 1820 CHF
*/
expect(position).toMatchObject<TimelinePosition>({
activitiesCount: 2,
averagePrice: new Big(1),
currency: 'USD',
dataSource: DataSource.YAHOO,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts

@ -135,6 +135,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 1,
averagePrice: new Big('89.12'),
currency: 'USD',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts

@ -131,6 +131,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 2,
averagePrice: new Big('298.58'),
currency: 'USD',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts

@ -135,6 +135,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 2,
averagePrice: new Big('75.80'),
currency: 'CHF',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -188,6 +188,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 2,
averagePrice: new Big('0'),
currency: 'CHF',
dataSource: 'YAHOO',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts

@ -116,6 +116,7 @@ describe('PortfolioCalculator', () => {
hasErrors: false,
positions: [
{
activitiesCount: 1,
averagePrice: new Big('500000'),
currency: 'USD',
dataSource: 'MANUAL',

3
apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts

@ -2,6 +2,7 @@ import { AssetSubClass, DataSource, Tag } from '@prisma/client';
import { Big } from 'big.js';
export interface TransactionPointSymbol {
activitiesCount: number;
assetSubClass: AssetSubClass;
averagePrice: Big;
currency: string;
@ -16,5 +17,7 @@ export interface TransactionPointSymbol {
skipErrors: boolean;
symbol: string;
tags?: Tag[];
/** @deprecated use activitiesCount instead */
transactionCount: number;
}

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

@ -179,9 +179,9 @@ export class PortfolioService {
return Promise.all(
accounts.map(async (account) => {
let activitiesCount = 0;
let dividendInBaseCurrency = 0;
let interestInBaseCurrency = 0;
let transactionCount = 0;
for (const {
currency,
@ -214,7 +214,7 @@ export class PortfolioService {
}
if (!isDraft) {
transactionCount += 1;
activitiesCount += 1;
}
}
@ -223,9 +223,9 @@ export class PortfolioService {
const result = {
...account,
activitiesCount,
dividendInBaseCurrency,
interestInBaseCurrency,
transactionCount,
valueInBaseCurrency,
allocationInPercentage: 0,
balanceInBaseCurrency: this.exchangeRateDataService.toCurrency(
@ -233,6 +233,7 @@ export class PortfolioService {
account.currency,
userCurrency
),
transactionCount: activitiesCount,
value: this.exchangeRateDataService.toCurrency(
valueInBaseCurrency,
userCurrency,
@ -262,6 +263,8 @@ export class PortfolioService {
withExcludedAccounts
});
let activitiesCount = 0;
const searchQuery = filters.find(({ type }) => {
return type === 'SEARCH_QUERY';
})?.id;
@ -284,6 +287,8 @@ export class PortfolioService {
let transactionCount = 0;
for (const account of accounts) {
activitiesCount += account.activitiesCount;
totalBalanceInBaseCurrency = totalBalanceInBaseCurrency.plus(
account.balanceInBaseCurrency
);
@ -296,6 +301,7 @@ export class PortfolioService {
totalValueInBaseCurrency = totalValueInBaseCurrency.plus(
account.valueInBaseCurrency
);
transactionCount += account.transactionCount;
}
@ -310,6 +316,7 @@ export class PortfolioService {
return {
accounts,
activitiesCount,
transactionCount,
totalBalanceInBaseCurrency: totalBalanceInBaseCurrency.toNumber(),
totalDividendInBaseCurrency: totalDividendInBaseCurrency.toNumber(),
@ -567,6 +574,7 @@ export class PortfolioService {
}
for (const {
activitiesCount,
currency,
dividend,
firstBuyDate,
@ -610,6 +618,7 @@ export class PortfolioService {
}
holdings[symbol] = {
activitiesCount,
currency,
markets,
marketsAdvanced,
@ -789,6 +798,7 @@ export class PortfolioService {
}
const {
activitiesCount,
averagePrice,
currency,
dividendInBaseCurrency,
@ -807,8 +817,7 @@ export class PortfolioService {
quantity,
tags,
timeWeightedInvestment,
timeWeightedInvestmentWithCurrencyEffect,
transactionCount
timeWeightedInvestmentWithCurrencyEffect
} = holding;
const activitiesOfHolding = activities.filter(({ SymbolProfile }) => {
@ -914,12 +923,12 @@ export class PortfolioService {
);
return {
activitiesCount,
marketPrice,
marketPriceMax,
marketPriceMin,
SymbolProfile,
tags,
activitiesCount: transactionCount,
averagePrice: averagePrice.toNumber(),
dataProviderInfo: portfolioCalculator.getDataProviderInfos()?.[0],
dateOfFirstActivity: firstBuyDate,
@ -1657,6 +1666,7 @@ export class PortfolioService {
}): PortfolioPosition {
return {
currency,
activitiesCount: 0,
allocationInPercentage: 0,
assetClass: AssetClass.LIQUIDITY,
assetSubClass: AssetSubClass.CASH,

4
libs/common/src/lib/interfaces/portfolio-position.interface.ts

@ -7,6 +7,7 @@ import { Holding } from './holding.interface';
import { Sector } from './sector.interface';
export interface PortfolioPosition {
activitiesCount: number;
allocationInPercentage: number;
assetClass?: AssetClass;
assetClassLabel?: string;
@ -38,7 +39,10 @@ export interface PortfolioPosition {
sectors: Sector[];
symbol: string;
tags?: Tag[];
/** @deprecated use activitiesCount instead */
transactionCount: number;
type?: string;
url?: string;
valueInBaseCurrency?: number;

3
libs/common/src/lib/interfaces/responses/accounts-response.interface.ts

@ -2,9 +2,12 @@ import { AccountWithValue } from '@ghostfolio/common/types';
export interface AccountsResponse {
accounts: AccountWithValue[];
activitiesCount: number;
totalBalanceInBaseCurrency: number;
totalDividendInBaseCurrency: number;
totalInterestInBaseCurrency: number;
totalValueInBaseCurrency: number;
/** @deprecated use activitiesCount instead */
transactionCount: number;
}

3
libs/common/src/lib/models/timeline-position.ts

@ -9,6 +9,8 @@ import { Big } from 'big.js';
import { Transform, Type } from 'class-transformer';
export class TimelinePosition {
activitiesCount: number;
@Transform(transformToBig, { toClassOnly: true })
@Type(() => Big)
averagePrice: Big;
@ -92,6 +94,7 @@ export class TimelinePosition {
@Type(() => Big)
timeWeightedInvestmentWithCurrencyEffect: Big;
/** @deprecated use activitiesCount instead */
transactionCount: number;
@Transform(transformToBig, { toClassOnly: true })

4
libs/common/src/lib/types/account-with-value.type.ts

@ -1,12 +1,16 @@
import { Account as AccountModel, Platform } from '@prisma/client';
export type AccountWithValue = AccountModel & {
activitiesCount: number;
allocationInPercentage: number;
balanceInBaseCurrency: number;
dividendInBaseCurrency: number;
interestInBaseCurrency: number;
platform?: Platform;
/** @deprecated use activitiesCount instead */
transactionCount: number;
value: number;
valueInBaseCurrency: number;
};

7
libs/ui/src/lib/mocks/holdings.ts

@ -2,6 +2,7 @@ import { PortfolioPosition } from '@ghostfolio/common/interfaces';
export const holdings: PortfolioPosition[] = [
{
activitiesCount: 1,
allocationInPercentage: 0.042990776363386086,
assetClass: 'EQUITY' as any,
assetClassLabel: 'Equity',
@ -45,6 +46,7 @@ export const holdings: PortfolioPosition[] = [
valueInBaseCurrency: 12230
},
{
activitiesCount: 2,
allocationInPercentage: 0.02377401948293552,
assetClass: 'EQUITY' as any,
assetClassLabel: 'Equity',
@ -88,6 +90,7 @@ export const holdings: PortfolioPosition[] = [
valueInBaseCurrency: 6763.224181360202
},
{
activitiesCount: 1,
allocationInPercentage: 0.08038536990007467,
assetClass: 'EQUITY' as any,
assetClassLabel: 'Equity',
@ -131,6 +134,7 @@ export const holdings: PortfolioPosition[] = [
valueInBaseCurrency: 22868
},
{
activitiesCount: 1,
allocationInPercentage: 0.19216416482928922,
assetClass: 'LIQUIDITY' as any,
assetClassLabel: 'Liquidity',
@ -162,6 +166,7 @@ export const holdings: PortfolioPosition[] = [
valueInBaseCurrency: 54666.7898248
},
{
activitiesCount: 1,
allocationInPercentage: 0.04307127421937313,
assetClass: 'EQUITY' as any,
assetClassLabel: 'Equity',
@ -205,6 +210,7 @@ export const holdings: PortfolioPosition[] = [
valueInBaseCurrency: 12252.9
},
{
activitiesCount: 1,
allocationInPercentage: 0.18762679306394897,
assetClass: 'EQUITY' as any,
assetClassLabel: 'Equity',
@ -248,6 +254,7 @@ export const holdings: PortfolioPosition[] = [
valueInBaseCurrency: 53376
},
{
activitiesCount: 5,
allocationInPercentage: 0.053051250766657634,
assetClass: 'EQUITY' as any,
assetClassLabel: 'Equity',

Loading…
Cancel
Save