Browse Source

Merge pull request #73 from dandevaud/feature/Performance-Enhancements

Fix TimeWeighted performance and readd multi select fitlters
pull/5027/head
dandevaud 1 year ago
committed by GitHub
parent
commit
57740e5229
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      apps/api/src/app/portfolio/portfolio-calculator-novn-baln-buy-and-sell.spec.ts
  2. 291
      apps/api/src/app/portfolio/portfolio-calculator.ts
  3. 4
      apps/client/src/app/components/header/header.component.ts
  4. 6
      apps/client/src/app/services/user/user.service.ts
  5. 3
      libs/common/src/lib/interfaces/symbol-metrics.interface.ts
  6. 51
      libs/ui/src/lib/assistant/assistant.component.ts
  7. 6
      libs/ui/src/lib/assistant/assistant.html

2
apps/api/src/app/portfolio/portfolio-calculator-novn-baln-buy-and-sell.spec.ts

@ -141,7 +141,7 @@ describe('PortfolioCalculator', () => {
netPerformanceInPercentage: 13.100263852242744, netPerformanceInPercentage: 13.100263852242744,
netPerformanceInPercentageWithCurrencyEffect: 13.100263852242744, netPerformanceInPercentageWithCurrencyEffect: 13.100263852242744,
netPerformanceWithCurrencyEffect: 19.86, netPerformanceWithCurrencyEffect: 19.86,
timeWeightedPerformance: 13.100263852242744, timeWeightedPerformance: 0,
totalInvestment: 0, totalInvestment: 0,
totalInvestmentValueWithCurrencyEffect: 0, totalInvestmentValueWithCurrencyEffect: 0,
value: 0, value: 0,

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

@ -317,6 +317,7 @@ export class PortfolioCalculator {
timeWeightedInvestmentValues: { [date: string]: Big }; timeWeightedInvestmentValues: { [date: string]: Big };
timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big }; timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big };
netPerformanceValuesPercentage: { [date: string]: Big }; netPerformanceValuesPercentage: { [date: string]: Big };
unitPrices: { [date: string]: Big };
}; };
} = {}; } = {};
@ -367,6 +368,7 @@ export class PortfolioCalculator {
timeWeightedInvestmentValues: { [date: string]: Big }; timeWeightedInvestmentValues: { [date: string]: Big };
timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big }; timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big };
netPerformanceValuesPercentage: { [date: string]: Big }; netPerformanceValuesPercentage: { [date: string]: Big };
unitPrices: { [date: string]: Big };
}; };
}, },
calculateTimeWeightedPerformance: boolean, calculateTimeWeightedPerformance: boolean,
@ -390,13 +392,11 @@ export class PortfolioCalculator {
? format(previousDate, DATE_FORMAT) ? format(previousDate, DATE_FORMAT)
: null; : null;
let totalCurrentValue = new Big(0); let totalCurrentValue = new Big(0);
let maxTotalInvestmentValue = new Big(0);
let previousTotalInvestmentValue = new Big(0); let previousTotalInvestmentValue = new Big(0);
let timeWeightedPerformance = new Big(0);
if (calculateTimeWeightedPerformance && previousDateString) { if (calculateTimeWeightedPerformance && previousDateString) {
previousTotalInvestmentValue = previousTotalInvestmentValue =
accumulatedValuesByDate[previousDateString].totalInvestmentValue; accumulatedValuesByDate[previousDateString].totalCurrentValue;
} }
for (const symbol of Object.keys(valuesBySymbol)) { for (const symbol of Object.keys(valuesBySymbol)) {
@ -406,6 +406,8 @@ export class PortfolioCalculator {
totalCurrentValue = totalCurrentValue.plus(symbolCurrentValues); totalCurrentValue = totalCurrentValue.plus(symbolCurrentValues);
let timeWeightedPerformanceContribution = new Big(0);
if ( if (
previousTotalInvestmentValue.toNumber() && previousTotalInvestmentValue.toNumber() &&
symbolValues.netPerformanceValuesPercentage && symbolValues.netPerformanceValuesPercentage &&
@ -416,28 +418,22 @@ export class PortfolioCalculator {
const previousValue = const previousValue =
symbolValues.currentValues?.[previousDateString] ?? new Big(0); symbolValues.currentValues?.[previousDateString] ?? new Big(0);
const netPerformance = const netPerformance =
symbolValues.netPerformanceValuesPercentage?.[dateString] ?? symbolValues.unitPrices?.[dateString] &&
new Big(0); symbolValues.unitPrices?.[previousDateString]
const timeWeightedPerformanceContribution = previousValue ? symbolValues.unitPrices[dateString]
.div(symbolValues.unitPrices[previousDateString])
.minus(1)
: new Big(0);
timeWeightedPerformanceContribution = previousValue
.div(previousTotalInvestmentValue) .div(previousTotalInvestmentValue)
.mul(netPerformance) .mul(netPerformance);
.mul(100);
timeWeightedPerformance = timeWeightedPerformance.plus(
timeWeightedPerformanceContribution
);
} }
let totalTimeWeightedPerformance = timeWeightedPerformance.plus(
accumulatedValuesByDate[previousDateString]
?.totalTimeWeightedPerformance ?? new Big(0)
);
accumulatedValuesByDate = this.accumulatedValuesByDate( accumulatedValuesByDate = this.accumulatedValuesByDate(
valuesBySymbol, valuesBySymbol,
symbol, symbol,
dateString, dateString,
accumulatedValuesByDate, accumulatedValuesByDate,
totalTimeWeightedPerformance timeWeightedPerformanceContribution
); );
} }
@ -453,6 +449,19 @@ export class PortfolioCalculator {
totalNetPerformanceValue totalNetPerformanceValue
} = accumulatedValuesByDate[dateString]; } = accumulatedValuesByDate[dateString];
let totalNetTimeWeightedPerformance = new Big(0);
if (previousDateString) {
totalNetTimeWeightedPerformance = (
accumulatedValuesByDate[previousDateString]
?.totalTimeWeightedPerformance ?? new Big(0)
)
.plus(1)
.mul(totalTimeWeightedPerformance.plus(1))
.minus(1)
.mul(100);
}
const netPerformanceInPercentage = totalTimeWeightedInvestmentValue.eq(0) const netPerformanceInPercentage = totalTimeWeightedInvestmentValue.eq(0)
? 0 ? 0
: totalNetPerformanceValue : totalNetPerformanceValue
@ -476,7 +485,7 @@ export class PortfolioCalculator {
totalInvestment: totalInvestmentValue.toNumber(), totalInvestment: totalInvestmentValue.toNumber(),
value: totalCurrentValue.toNumber(), value: totalCurrentValue.toNumber(),
valueWithCurrencyEffect: totalCurrentValueWithCurrencyEffect.toNumber(), valueWithCurrencyEffect: totalCurrentValueWithCurrencyEffect.toNumber(),
timeWeightedPerformance: totalTimeWeightedPerformance.toNumber(), timeWeightedPerformance: totalNetTimeWeightedPerformance.toNumber(),
investmentValueWithCurrencyEffect: investmentValueWithCurrencyEffect:
investmentValueWithCurrencyEffect.toNumber(), investmentValueWithCurrencyEffect.toNumber(),
netPerformanceWithCurrencyEffect: netPerformanceWithCurrencyEffect:
@ -589,7 +598,10 @@ export class PortfolioCalculator {
accumulatedValuesByDate[dateString] accumulatedValuesByDate[dateString]
?.totalTimeWeightedInvestmentValueWithCurrencyEffect ?? new Big(0) ?.totalTimeWeightedInvestmentValueWithCurrencyEffect ?? new Big(0)
).add(timeWeightedInvestmentValueWithCurrencyEffect), ).add(timeWeightedInvestmentValueWithCurrencyEffect),
totalTimeWeightedPerformance: timeWeightedPerformance totalTimeWeightedPerformance: (
accumulatedValuesByDate[dateString]?.totalTimeWeightedPerformance ??
new Big(0)
).add(timeWeightedPerformance)
}; };
return accumulatedValuesByDate; return accumulatedValuesByDate;
@ -615,6 +627,7 @@ export class PortfolioCalculator {
timeWeightedInvestmentValues: { [date: string]: Big }; timeWeightedInvestmentValues: { [date: string]: Big };
timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big }; timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big };
netPerformanceValuesPercentage: { [date: string]: Big }; netPerformanceValuesPercentage: { [date: string]: Big };
unitPrices: { [date: string]: Big };
}; };
}, },
currencies: { [symbol: string]: string } currencies: { [symbol: string]: string }
@ -630,7 +643,8 @@ export class PortfolioCalculator {
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
timeWeightedInvestmentValues, timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect, timeWeightedInvestmentValuesWithCurrencyEffect,
netPerformanceValuesPercentage netPerformanceValuesPercentage,
unitPrices
} = this.getSymbolMetrics({ } = this.getSymbolMetrics({
end, end,
marketSymbolMap, marketSymbolMap,
@ -652,7 +666,8 @@ export class PortfolioCalculator {
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
timeWeightedInvestmentValues, timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect, timeWeightedInvestmentValuesWithCurrencyEffect,
netPerformanceValuesPercentage netPerformanceValuesPercentage,
unitPrices
}; };
} }
} }
@ -1162,78 +1177,55 @@ export class PortfolioCalculator {
symbol: string; symbol: string;
calculatePerformance?: boolean; calculatePerformance?: boolean;
}): SymbolMetrics { }): SymbolMetrics {
const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; let {
const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = { averagePriceAtStartDate,
Value: {}, totalUnits,
WithCurrencyEffect: {} totalInvestment,
}; investmentAtStartDate,
let fees: WithCurrencyEffect<Big> = { valueAtStartDate,
Value: new Big(0), maxTotalInvestment,
WithCurrencyEffect: new Big(0) averagePriceAtEndDate,
}; initialValue,
let feesAtStartDate: WithCurrencyEffect<Big> = { fees,
Value: new Big(0), feesAtStartDate,
WithCurrencyEffect: new Big(0) lastAveragePrice,
}; grossPerformanceFromSells,
let grossPerformance: WithCurrencyEffect<Big> = { totalInvestmentWithGrossPerformanceFromSell,
Value: new Big(0), grossPerformance,
WithCurrencyEffect: new Big(0) grossPerformanceAtStartDate,
}; currentValues,
let grossPerformanceAtStartDate: WithCurrencyEffect<Big> = { netPerformanceValues,
Value: new Big(0), netPerformanceValuesPercentage,
WithCurrencyEffect: new Big(0) investmentValues,
}; investmentValuesAccumulated,
let grossPerformanceFromSells: WithCurrencyEffect<Big> = { maxInvestmentValues,
Value: new Big(0), timeWeightedInvestmentValues
WithCurrencyEffect: new Big(0) }: {
}; averagePriceAtStartDate: Big;
let averagePriceAtEndDate = new Big(0); totalUnits: Big;
let averagePriceAtStartDate = new Big(0); totalInvestment: WithCurrencyEffect<Big>;
const investmentValues: WithCurrencyEffect<{ [date: string]: Big }> = { investmentAtStartDate: any;
Value: {}, valueAtStartDate: WithCurrencyEffect<Big>;
WithCurrencyEffect: {} maxTotalInvestment: Big;
}; averagePriceAtEndDate: Big;
const maxInvestmentValues: { [date: string]: Big } = {}; initialValue: any;
let maxTotalInvestment = new Big(0); fees: WithCurrencyEffect<Big>;
const netPerformanceValuesPercentage: { [date: string]: Big } = {}; feesAtStartDate: WithCurrencyEffect<Big>;
let initialValue; lastAveragePrice: WithCurrencyEffect<Big>;
let investmentAtStartDate; grossPerformanceFromSells: WithCurrencyEffect<Big>;
const investmentValuesAccumulated: WithCurrencyEffect<{ totalInvestmentWithGrossPerformanceFromSell: WithCurrencyEffect<Big>;
[date: string]: Big; grossPerformance: WithCurrencyEffect<Big>;
}> = { grossPerformanceAtStartDate: WithCurrencyEffect<Big>;
Value: {}, currentValues: WithCurrencyEffect<{ [date: string]: Big }>;
WithCurrencyEffect: {} netPerformanceValues: WithCurrencyEffect<{ [date: string]: Big }>;
}; netPerformanceValuesPercentage: { [date: string]: Big };
let lastAveragePrice: WithCurrencyEffect<Big> = { investmentValues: WithCurrencyEffect<{ [date: string]: Big }>;
Value: new Big(0), investmentValuesAccumulated: WithCurrencyEffect<{ [date: string]: Big }>;
WithCurrencyEffect: new Big(0) maxInvestmentValues: { [date: string]: Big };
}; timeWeightedInvestmentValues: WithCurrencyEffect<{ [date: string]: Big }>;
const netPerformanceValues: WithCurrencyEffect<{ [date: string]: Big }> = { } = this.InitializeSymbolMetricValues();
Value: {},
WithCurrencyEffect: {}
};
const timeWeightedInvestmentValues: WithCurrencyEffect<{
[date: string]: Big;
}> = {
Value: {},
WithCurrencyEffect: {}
};
let totalInvestment: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let totalInvestmentWithGrossPerformanceFromSell: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let totalUnits = new Big(0); const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)];
let valueAtStartDate: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
// Clone orders to keep the original values in this.orders // Clone orders to keep the original values in this.orders
let orders: PortfolioOrderItem[] = cloneDeep(this.orders).filter( let orders: PortfolioOrderItem[] = cloneDeep(this.orders).filter(
@ -1268,7 +1260,8 @@ export class PortfolioCalculator {
timeWeightedInvestmentValuesWithCurrencyEffect: {}, timeWeightedInvestmentValuesWithCurrencyEffect: {},
totalInvestment: new Big(0), totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0), totalInvestmentWithCurrencyEffect: new Big(0),
netPerformanceValuesPercentage: {} netPerformanceValuesPercentage: {},
unitPrices: {}
}; };
} }
@ -1309,7 +1302,8 @@ export class PortfolioCalculator {
timeWeightedInvestmentWithCurrencyEffect: new Big(0), timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalInvestment: new Big(0), totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0), totalInvestmentWithCurrencyEffect: new Big(0),
netPerformanceValuesPercentage: {} netPerformanceValuesPercentage: {},
unitPrices: {}
}; };
} }
@ -1385,6 +1379,12 @@ export class PortfolioCalculator {
calculatePerformance calculatePerformance
); );
let unitPrices = Object.keys(marketSymbolMap).reduce(
(obj, date) =>
(obj = Object.assign(obj, { [date]: marketSymbolMap[date][symbol] })),
{}
);
return { return {
currentValues: result.currentValues.Value, currentValues: result.currentValues.Value,
currentValuesWithCurrencyEffect: result.currentValues.WithCurrencyEffect, currentValuesWithCurrencyEffect: result.currentValues.WithCurrencyEffect,
@ -1422,7 +1422,106 @@ export class PortfolioCalculator {
result.timeWeightedAverageInvestmentBetweenStartAndEndDate.Value, result.timeWeightedAverageInvestmentBetweenStartAndEndDate.Value,
timeWeightedInvestmentWithCurrencyEffect: timeWeightedInvestmentWithCurrencyEffect:
result.timeWeightedAverageInvestmentBetweenStartAndEndDate result.timeWeightedAverageInvestmentBetweenStartAndEndDate
.WithCurrencyEffect .WithCurrencyEffect,
unitPrices
};
}
private InitializeSymbolMetricValues() {
const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = {
Value: {},
WithCurrencyEffect: {}
};
let fees: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let feesAtStartDate: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let grossPerformance: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let grossPerformanceAtStartDate: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let grossPerformanceFromSells: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let averagePriceAtEndDate = new Big(0);
let averagePriceAtStartDate = new Big(0);
const investmentValues: WithCurrencyEffect<{ [date: string]: Big }> = {
Value: {},
WithCurrencyEffect: {}
};
const maxInvestmentValues: { [date: string]: Big } = {};
let maxTotalInvestment = new Big(0);
const netPerformanceValuesPercentage: { [date: string]: Big } = {};
let initialValue;
let investmentAtStartDate;
const investmentValuesAccumulated: WithCurrencyEffect<{
[date: string]: Big;
}> = {
Value: {},
WithCurrencyEffect: {}
};
let lastAveragePrice: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
const netPerformanceValues: WithCurrencyEffect<{ [date: string]: Big }> = {
Value: {},
WithCurrencyEffect: {}
};
const timeWeightedInvestmentValues: WithCurrencyEffect<{
[date: string]: Big;
}> = {
Value: {},
WithCurrencyEffect: {}
};
let totalInvestment: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let totalInvestmentWithGrossPerformanceFromSell: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
let totalUnits = new Big(0);
let valueAtStartDate: WithCurrencyEffect<Big> = {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
};
return {
averagePriceAtStartDate,
totalUnits,
totalInvestment,
investmentAtStartDate,
valueAtStartDate,
maxTotalInvestment,
averagePriceAtEndDate,
initialValue,
fees,
feesAtStartDate,
lastAveragePrice,
grossPerformanceFromSells,
totalInvestmentWithGrossPerformanceFromSell,
grossPerformance,
grossPerformanceAtStartDate,
currentValues,
netPerformanceValues,
netPerformanceValuesPercentage,
investmentValues,
investmentValuesAccumulated,
maxInvestmentValues,
timeWeightedInvestmentValues
}; };
} }

4
apps/client/src/app/components/header/header.component.ts

@ -179,7 +179,9 @@ export class HeaderComponent implements OnChanges {
filtersType = 'tags'; filtersType = 'tags';
} }
userSetting[`filters.${filtersType}`] = filter.id ? [filter.id] : null; userSetting[`filters.${filtersType}`] = filters
.filter((f) => f.type === filter.type)
.map((f) => f.id);
} }
this.dataService this.dataService

6
apps/client/src/app/services/user/user.service.ts

@ -53,21 +53,21 @@ export class UserService extends ObservableStore<UserStoreState> {
if (user.settings['filters.accounts']) { if (user.settings['filters.accounts']) {
filters.push({ filters.push({
id: user.settings['filters.accounts'][0], id: user.settings['filters.accounts'].join(','),
type: 'ACCOUNT' type: 'ACCOUNT'
}); });
} }
if (user.settings['filters.assetClasses']) { if (user.settings['filters.assetClasses']) {
filters.push({ filters.push({
id: user.settings['filters.assetClasses'][0], id: user.settings['filters.assetClasses'].join(','),
type: 'ASSET_CLASS' type: 'ASSET_CLASS'
}); });
} }
if (user.settings['filters.tags']) { if (user.settings['filters.tags']) {
filters.push({ filters.push({
id: user.settings['filters.tags'][0], id: user.settings['filters.tags'].join(','),
type: 'TAG' type: 'TAG'
}); });
} }

3
libs/common/src/lib/interfaces/symbol-metrics.interface.ts

@ -44,4 +44,7 @@ export interface SymbolMetrics {
timeWeightedInvestmentWithCurrencyEffect: Big; timeWeightedInvestmentWithCurrencyEffect: Big;
totalInvestment: Big; totalInvestment: Big;
totalInvestmentWithCurrencyEffect: Big; totalInvestmentWithCurrencyEffect: Big;
unitPrices: {
[date: string]: Big;
};
} }

51
libs/ui/src/lib/assistant/assistant.component.ts

@ -24,6 +24,7 @@ import {
import { FormBuilder, FormControl } from '@angular/forms'; import { FormBuilder, FormControl } from '@angular/forms';
import { MatMenuTrigger } from '@angular/material/menu'; import { MatMenuTrigger } from '@angular/material/menu';
import { Account, AssetClass } from '@prisma/client'; import { Account, AssetClass } from '@prisma/client';
import { filter } from 'lodash';
import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs'; import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs';
import { import {
catchError, catchError,
@ -117,9 +118,9 @@ export class AssistantComponent implements OnChanges, OnDestroy, OnInit {
{ label: $localize`Max`, value: 'max' } { label: $localize`Max`, value: 'max' }
]; ];
public filterForm = this.formBuilder.group({ public filterForm = this.formBuilder.group({
account: new FormControl<string>(undefined), account: new FormControl<string[]>(undefined),
assetClass: new FormControl<string>(undefined), assetClass: new FormControl<string[]>(undefined),
tag: new FormControl<string>(undefined) tag: new FormControl<string[]>(undefined)
}); });
public isLoading = false; public isLoading = false;
public isOpen = false; public isOpen = false;
@ -203,9 +204,9 @@ export class AssistantComponent implements OnChanges, OnDestroy, OnInit {
this.filterForm.setValue( this.filterForm.setValue(
{ {
account: this.user?.settings?.['filters.accounts']?.[0] ?? null, account: this.user?.settings?.['filters.accounts'] ?? null,
assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null, assetClass: this.user?.settings?.['filters.assetClasses'] ?? null,
tag: this.user?.settings?.['filters.tags']?.[0] ?? null tag: this.user?.settings?.['filters.tags'] ?? null
}, },
{ {
emitEvent: false emitEvent: false
@ -213,7 +214,7 @@ export class AssistantComponent implements OnChanges, OnDestroy, OnInit {
); );
} }
public hasFilter(aFormValue: { [key: string]: string }) { public hasFilter(aFormValue: { [key: string]: string[] }) {
return Object.values(aFormValue).some((value) => { return Object.values(aFormValue).some((value) => {
return !!value; return !!value;
}); });
@ -243,20 +244,28 @@ export class AssistantComponent implements OnChanges, OnDestroy, OnInit {
} }
public onApplyFilters() { public onApplyFilters() {
this.filtersChanged.emit([ let accountFilters =
{ this.filterForm
id: this.filterForm.get('account').value, .get('account')
type: 'ACCOUNT' .value?.reduce(
}, (arr, val) => [...arr, { id: val, type: 'ACCOUNT' }],
{ []
id: this.filterForm.get('assetClass').value, ) ?? [];
type: 'ASSET_CLASS' let assetClassFilters =
}, this.filterForm
{ .get('assetClass')
id: this.filterForm.get('tag').value, .value?.reduce(
type: 'TAG' (arr, val) => [...arr, { id: val, type: 'ASSET_CLASS' }],
} []
]); ) ?? [];
let tagFilters =
this.filterForm
.get('tag')
.value?.reduce((arr, val) => [...arr, { id: val, type: 'TAG' }], []) ??
[];
let filters = [...accountFilters, ...assetClassFilters];
filters = [...filters, ...tagFilters];
this.filtersChanged.emit(filters);
this.onCloseAssistant(); this.onCloseAssistant();
} }

6
libs/ui/src/lib/assistant/assistant.html

@ -105,7 +105,7 @@
<div class="mb-3"> <div class="mb-3">
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Accounts</mat-label> <mat-label i18n>Accounts</mat-label>
<mat-select formControlName="account"> <mat-select formControlName="account" multiple>
<mat-option [value]="null" /> <mat-option [value]="null" />
@for (account of accounts; track account.id) { @for (account of accounts; track account.id) {
<mat-option [value]="account.id"> <mat-option [value]="account.id">
@ -125,7 +125,7 @@
<div class="mb-3"> <div class="mb-3">
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Tags</mat-label> <mat-label i18n>Tags</mat-label>
<mat-select formControlName="tag"> <mat-select formControlName="tag" multiple>
<mat-option [value]="null" /> <mat-option [value]="null" />
@for (tag of tags; track tag.id) { @for (tag of tags; track tag.id) {
<mat-option [value]="tag.id">{{ tag.label }}</mat-option> <mat-option [value]="tag.id">{{ tag.label }}</mat-option>
@ -136,7 +136,7 @@
<div class="mb-3"> <div class="mb-3">
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Asset Classes</mat-label> <mat-label i18n>Asset Classes</mat-label>
<mat-select formControlName="assetClass"> <mat-select formControlName="assetClass" multiple>
<mat-option [value]="null" /> <mat-option [value]="null" />
@for (assetClass of assetClasses; track assetClass.id) { @for (assetClass of assetClasses; track assetClass.id) {
<mat-option [value]="assetClass.id" <mat-option [value]="assetClass.id"

Loading…
Cancel
Save