@decafhub/decaf-client-extras 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/.github/workflows/test.yml +1 -1
  2. package/.release-please-manifest.json +1 -1
  3. package/CHANGELOG.md +23 -0
  4. package/es/reports/valuation/-remote-valuation-report-account.d.ts +150 -0
  5. package/es/reports/valuation/-remote-valuation-report-account.js +135 -0
  6. package/es/reports/valuation/-valuation-report-account.d.ts +79 -0
  7. package/es/reports/valuation/-valuation-report-account.js +1 -0
  8. package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.d.ts +2 -2
  9. package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.js +5 -3
  10. package/es/reports/valuation/-valuation-report-holdings-tree/-types.d.ts +3 -0
  11. package/es/reports/valuation/-valuation-report-holdings-tree/-utils.d.ts +6 -0
  12. package/es/reports/valuation/-valuation-report-holdings-tree/-utils.js +29 -0
  13. package/es/reports/valuation/index.d.ts +3 -0
  14. package/es/reports/valuation/index.js +2 -0
  15. package/package.json +1 -1
  16. package/release-please-config.json +1 -0
  17. package/reports/valuation/-remote-valuation-report-account.d.ts +150 -0
  18. package/reports/valuation/-remote-valuation-report-account.js +196 -0
  19. package/reports/valuation/-valuation-report-account.d.ts +79 -0
  20. package/reports/valuation/-valuation-report-account.js +2 -0
  21. package/reports/valuation/-valuation-report-holdings-tree/-machinery.d.ts +2 -2
  22. package/reports/valuation/-valuation-report-holdings-tree/-machinery.js +5 -2
  23. package/reports/valuation/-valuation-report-holdings-tree/-types.d.ts +3 -0
  24. package/reports/valuation/-valuation-report-holdings-tree/-utils.d.ts +6 -0
  25. package/reports/valuation/-valuation-report-holdings-tree/-utils.js +59 -1
  26. package/reports/valuation/index.d.ts +3 -0
  27. package/reports/valuation/index.js +4 -1
  28. package/src/{index.test.ts → reports/index.test.ts} +70 -4
  29. package/src/reports/valuation/-remote-valuation-report-account.ts +297 -0
  30. package/src/reports/valuation/-valuation-report-account.ts +92 -0
  31. package/src/reports/valuation/-valuation-report-holdings-tree/-machinery.ts +12 -4
  32. package/src/reports/valuation/-valuation-report-holdings-tree/-types.ts +10 -0
  33. package/src/reports/valuation/-valuation-report-holdings-tree/-utils.ts +43 -0
  34. package/src/reports/valuation/index.ts +3 -0
@@ -2,12 +2,16 @@ import { buildDecafClient, DecafClient, gql } from '@decafhub/decaf-client';
2
2
  import { safeDiv, zero } from '@telostat/prelude';
3
3
  import { fail } from 'assert';
4
4
  import dayjs from 'dayjs';
5
- import { DecafPortfolioId, mkCurrencyCodeError } from './commons';
6
- import { makeValuationReportHoldingsTree } from './reports/valuation/';
5
+ import { DecafAccountId, DecafPortfolioId, mkCurrencyCodeError } from '../commons';
6
+ import { makeValuationReportHoldingsTree } from './valuation';
7
7
  import {
8
8
  fetchPortfolioValuationReport,
9
9
  fetchRemotePortfolioValuationReport,
10
- } from './reports/valuation/-remote-valuation-report-portfolio';
10
+ } from './valuation/-remote-valuation-report-portfolio';
11
+ import {
12
+ fetchAccountValuationReport,
13
+ fetchRemoteAccountValuationReport,
14
+ } from './valuation/-remote-valuation-report-account';
11
15
 
12
16
  const API_URL = process.env.TESTING_API_URL;
13
17
  const API_KEY = process.env.TESTING_API_KEY;
@@ -22,9 +26,19 @@ const FIRST_PORTFOLIO_QUERY = gql`
22
26
  }
23
27
  `;
24
28
 
25
- describe('Main', () => {
29
+ const FIRST_ACCOUNT_QUERY = gql`
30
+ query GetFirstAccount {
31
+ account(limit: 1) {
32
+ id
33
+ name
34
+ }
35
+ }
36
+ `;
37
+
38
+ describe('Reports', () => {
26
39
  let client: DecafClient;
27
40
  let portfolioId: DecafPortfolioId;
41
+ let accountId: DecafAccountId;
28
42
 
29
43
  beforeAll(() => {
30
44
  jest.resetModules();
@@ -52,6 +66,16 @@ describe('Main', () => {
52
66
  }
53
67
  });
54
68
 
69
+ test('take the first account', async () => {
70
+ try {
71
+ const { data } = await client.microlot.query({ query: FIRST_ACCOUNT_QUERY });
72
+ accountId = data?.account?.[0].id;
73
+ expect(accountId).toBeDefined();
74
+ } catch (e) {
75
+ fail('Error while fetching the first account');
76
+ }
77
+ });
78
+
55
79
  test('get a remote portfolio report successfuly', async () => {
56
80
  const eValue = await fetchRemotePortfolioValuationReport(client, {
57
81
  portfolio: portfolioId,
@@ -66,6 +90,7 @@ describe('Main', () => {
66
90
  `Success! remote valuation for portfolio ID ${value.portfolio.id} is reported at ${value.reported}`
67
91
  );
68
92
  expect(value).toBeDefined();
93
+ expect(value.portfolio.id).toEqual(portfolioId);
69
94
  },
70
95
  });
71
96
  });
@@ -94,4 +119,45 @@ describe('Main', () => {
94
119
  },
95
120
  });
96
121
  });
122
+
123
+ test('get a remote account report successfuly', async () => {
124
+ const eValue = await fetchRemoteAccountValuationReport(client, {
125
+ account: accountId,
126
+ date: dayjs(new Date()).format('YYYY-MM-DD'),
127
+ dateType: 'settlement',
128
+ currency: mkCurrencyCodeError('EUR'),
129
+ });
130
+ eValue.caseOf({
131
+ Left: (e) => fail('Error while fetching the remote account report: ' + e.msg),
132
+ Right: (value) => {
133
+ console.log(`Success! remote valuation for account ID ${value.account.id} is reported at ${value.reported}`);
134
+ expect(value).toBeDefined();
135
+ expect(value.account.id).toEqual(accountId);
136
+ },
137
+ });
138
+ });
139
+
140
+ test('get an account report, check the tree', async () => {
141
+ const eValue = await fetchAccountValuationReport(client, {
142
+ account: accountId,
143
+ date: dayjs(new Date()).format('YYYY-MM-DD'),
144
+ dateType: 'settlement',
145
+ currency: mkCurrencyCodeError('EUR'),
146
+ });
147
+ eValue.caseOf({
148
+ Left: (e) => fail('Error while fetching the remote account report: ' + String(e)),
149
+ Right: (value) => {
150
+ console.log(`Success! remote valuation for account ID ${value.account.id} is reported at ${value.asof}`);
151
+
152
+ expect(value).toBeDefined();
153
+
154
+ const nav = value.figures.nav;
155
+ const inv = value.figures.investment;
156
+ const holdings = value.holdings;
157
+ const tree = makeValuationReportHoldingsTree(nav, inv, holdings, 'country');
158
+ expect(tree).toBeDefined();
159
+ expect(safeDiv(tree.totals.netExposure, nav).orDefault(zero)).toEqual(tree.totals.netExposureRatio);
160
+ },
161
+ });
162
+ });
97
163
  });
@@ -0,0 +1,297 @@
1
+ import { DecafClient } from '@decafhub/decaf-client';
2
+ import {
3
+ CustomError,
4
+ customError,
5
+ decimalFromNullable,
6
+ Either,
7
+ Left,
8
+ Maybe,
9
+ Right,
10
+ sanitizedNonEmptyText,
11
+ SDate,
12
+ SDateTime,
13
+ unsafeDecimal,
14
+ zero,
15
+ } from '@telostat/prelude';
16
+ import {
17
+ CurrencyCode,
18
+ DateType,
19
+ DecafAccountId,
20
+ DecafActionId,
21
+ DecafExternalValuationId,
22
+ DecafOhlcSeriesId,
23
+ DecafPortfolioId,
24
+ DecafPrincipalId,
25
+ DecafShareClassFeeScheduleId,
26
+ DecafShareClassId,
27
+ } from '../../commons';
28
+ import { recompileBaseValuationReport, RemoteBaseValuationReport } from './-remote-valuation-report-shared';
29
+ import { ValuationReportAccount } from './-valuation-report-shared';
30
+ import { AccountValuationReport, AccountValuationReportShareClassValue } from './-valuation-report-account';
31
+
32
+ /**
33
+ * Remote account valuation report query type.
34
+ */
35
+ export interface AccountValuationReportQuery {
36
+ /**
37
+ * Date of valuation report.
38
+ */
39
+ date: SDate;
40
+
41
+ /**
42
+ * Date type of the valuation report.
43
+ */
44
+ dateType: DateType;
45
+
46
+ /**
47
+ * Reference currency of the valuation report.
48
+ */
49
+ currency: CurrencyCode;
50
+
51
+ /**
52
+ * Account the valuation report is requested for.
53
+ */
54
+ account: DecafAccountId;
55
+ }
56
+
57
+ /**
58
+ * Type definition for the remote (raw) account valuation report data.
59
+ */
60
+ export interface RemoteAccountValuationReport extends RemoteBaseValuationReport {
61
+ account: ValuationReportAccount;
62
+ scvals: RemoteValuationShareClassValue[];
63
+ subscriptions?: number;
64
+ }
65
+
66
+ /**
67
+ * Type definition for share class valuation on the remote account valuation
68
+ * report.
69
+ */
70
+ export interface RemoteValuationShareClassValue {
71
+ shareclass?: RemoteValuationShareClass;
72
+ external?: RemoteValuationExternalValue;
73
+ nav: number;
74
+ nav_adjusted: number;
75
+ nav_adjusted_total: number;
76
+ coefficient: number;
77
+ gav_refccy: number;
78
+ gav_clsccy: number;
79
+ sharecount_prev: number;
80
+ sharecount_curr: number;
81
+ sharecount_diff: number;
82
+ px_refccy: number;
83
+ px_clsccy: number;
84
+ ytdext?: number;
85
+ ytdint?: number;
86
+ }
87
+
88
+ /**
89
+ * Type definition for share class on the remote account valuation report.
90
+ */
91
+ export interface RemoteValuationShareClass {
92
+ id: DecafShareClassId;
93
+ created: SDateTime;
94
+ creator: DecafPrincipalId;
95
+ updated: SDateTime;
96
+ updater: DecafPrincipalId;
97
+ guid: string;
98
+ portfolio: DecafPortfolioId;
99
+ name: string;
100
+ currency: CurrencyCode;
101
+ isin?: string;
102
+ bbgticker?: string;
103
+ liquidity?: string;
104
+ jurisdiction?: string;
105
+ administrator?: string;
106
+ mininvestment?: number;
107
+ subredperiod?: string;
108
+ freqmngt?: number;
109
+ freqperf?: number;
110
+ benchmark?: DecafOhlcSeriesId;
111
+ description?: string;
112
+ feeschedules: DecafShareClassFeeScheduleId[];
113
+ effectivefeeschedule?: DecafShareClassFeeScheduleId;
114
+ subscriptions: DecafActionId[];
115
+ outstanding?: number;
116
+ }
117
+
118
+ /**
119
+ * Type definition for external valuation on the remote account valuation
120
+ * report.
121
+ */
122
+ export interface RemoteValuationExternalValue {
123
+ id: DecafExternalValuationId;
124
+ created: SDateTime;
125
+ creator: DecafPrincipalId;
126
+ updated: SDateTime;
127
+ updater: DecafPrincipalId;
128
+ guid: string;
129
+ portfolio: DecafPortfolioId;
130
+ shareclass?: DecafShareClassId;
131
+ date: SDate;
132
+ ccy: CurrencyCode;
133
+ shares?: number;
134
+ price?: number;
135
+ nav?: number;
136
+ aum?: number;
137
+ hedgepnl?: number;
138
+ feemngt?: number;
139
+ feeperf?: number;
140
+ otheraccrued?: number;
141
+ totalaccrued?: number;
142
+ subred?: number;
143
+ perfdaily?: number;
144
+ perfweekly?: number;
145
+ perfmonthly?: number;
146
+ perfytd?: number;
147
+ perfstart?: number;
148
+ coefficient?: number;
149
+ }
150
+
151
+ /**
152
+ * Attempts to retrieve remote account valuation report.
153
+ *
154
+ * @param client DECAF Barista client.
155
+ * @param query Remote account valuation report endpoint query parameters.
156
+ * @returns Remote (raw) account valuation report data.
157
+ */
158
+ export async function fetchRemoteAccountValuationReport(
159
+ client: DecafClient,
160
+ query: AccountValuationReportQuery
161
+ ): Promise<Either<CustomError, RemoteAccountValuationReport>> {
162
+ return client.barista
163
+ .get<RemoteAccountValuationReport>('/reports/valuation/account/', {
164
+ params: {
165
+ ccy: query.currency,
166
+ date: query.date,
167
+ type: query.dateType,
168
+ account: `${query.account}`,
169
+ },
170
+ })
171
+ .then((x) => Right(x.data))
172
+ .catch((err) => Left(customError('Error while attempting to fetch remote account valuation report', err)));
173
+ }
174
+
175
+ /**
176
+ * Attempts to recompile remote valuation report share class value.
177
+ *
178
+ * @param x remote valuation report share class value object.
179
+ * @return Recompiled valuation report share class value object.
180
+ */
181
+ export function toShareClassValue(s: RemoteValuationShareClassValue): AccountValuationReportShareClassValue {
182
+ const shareclass = Maybe.fromNullable(s.shareclass).map((x) => ({
183
+ id: x.id,
184
+ created: x.created,
185
+ creator: Maybe.fromNullable(x.creator),
186
+ updated: x.updated,
187
+ updater: Maybe.fromNullable(x.updater),
188
+ guid: x.guid,
189
+ portfolio: x.portfolio,
190
+ name: x.name,
191
+ currency: x.currency,
192
+ isin: sanitizedNonEmptyText(x.isin),
193
+ bbgticker: sanitizedNonEmptyText(x.bbgticker),
194
+ liquidity: sanitizedNonEmptyText(x.liquidity),
195
+ jurisdiction: sanitizedNonEmptyText(x.jurisdiction),
196
+ administrator: sanitizedNonEmptyText(x.administrator),
197
+ minimumInvestment: Maybe.fromNullable(x.mininvestment),
198
+ subscriptionRedemptionPeriod: sanitizedNonEmptyText(x.subredperiod),
199
+ managementFeeFrequency: Maybe.fromNullable(x.freqmngt),
200
+ performanceFeeFrequency: Maybe.fromNullable(x.freqperf),
201
+ benchmark: Maybe.fromNullable(x.benchmark),
202
+ description: sanitizedNonEmptyText(x.description),
203
+ feeScheduleIds: x.feeschedules,
204
+ effectiveFeeScheduleId: Maybe.fromNullable(x.effectivefeeschedule),
205
+ subscriptionIds: x.subscriptions,
206
+ outstanding: decimalFromNullable(x.outstanding),
207
+ }));
208
+
209
+ return {
210
+ shareclass,
211
+ external: Maybe.fromNullable(s.external).map((ev) => ({
212
+ id: ev.id,
213
+ created: ev.created,
214
+ creator: Maybe.fromNullable(ev.updater),
215
+ updated: ev.updated,
216
+ updater: Maybe.fromNullable(ev.updater),
217
+ guid: ev.guid,
218
+ portfolio: ev.portfolio,
219
+ shareclass: Maybe.fromNullable(ev.shareclass),
220
+ date: ev.date,
221
+ ccy: ev.ccy,
222
+ shares: decimalFromNullable(ev.shares),
223
+ price: decimalFromNullable(ev.price),
224
+ nav: decimalFromNullable(ev.nav),
225
+ aum: decimalFromNullable(ev.aum),
226
+ hedgepnl: decimalFromNullable(ev.hedgepnl),
227
+ feemngt: decimalFromNullable(ev.feemngt),
228
+ feeperf: decimalFromNullable(ev.feeperf),
229
+ otheraccrued: decimalFromNullable(ev.otheraccrued),
230
+ totalaccrued: decimalFromNullable(ev.totalaccrued),
231
+ subred: decimalFromNullable(ev.subred),
232
+ perfdaily: decimalFromNullable(ev.perfdaily),
233
+ perfweekly: decimalFromNullable(ev.perfweekly),
234
+ perfmonthly: decimalFromNullable(ev.perfmonthly),
235
+ perfytd: decimalFromNullable(ev.perfytd),
236
+ perfstart: decimalFromNullable(ev.perfstart),
237
+ coefficient: decimalFromNullable(ev.coefficient),
238
+ })),
239
+ nav: unsafeDecimal(s.nav),
240
+ navAdjusted: unsafeDecimal(s.nav_adjusted),
241
+ navAdjustedTotal: unsafeDecimal(s.nav_adjusted_total),
242
+ coefficient: unsafeDecimal(s.coefficient),
243
+ gavRefccy: unsafeDecimal(s.gav_refccy),
244
+ gavClsccy: unsafeDecimal(s.gav_clsccy),
245
+ sharecountPrev: Maybe.fromNullable(s.sharecount_prev).map(unsafeDecimal),
246
+ sharecountCurr: Maybe.fromNullable(s.sharecount_curr).map(unsafeDecimal),
247
+ sharecountDiff: Maybe.fromNullable(s.sharecount_diff).map(unsafeDecimal),
248
+ pxRefCcy: decimalFromNullable(s.px_refccy),
249
+ pxClsCcy: decimalFromNullable(s.px_clsccy),
250
+ ytdExt: decimalFromNullable(s.ytdext),
251
+ ytdInt: decimalFromNullable(s.ytdint),
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Attempts to re-compile the raw, remote account valuation report and
257
+ * return it.
258
+ *
259
+ * @param x Raw, remote account valuation report.
260
+ * @returns Either of an error message or the re-compiled account valuation
261
+ * report.
262
+ */
263
+ export function recompileAccountValuationReport(
264
+ x: RemoteAccountValuationReport
265
+ ): Either<CustomError, AccountValuationReport> {
266
+ // Attempt to get the base valuation report:
267
+ const baseReport = recompileBaseValuationReport(x);
268
+
269
+ // Add consolidated valuation report specific fields and return:
270
+ return baseReport.map((report) => {
271
+ return {
272
+ ...report,
273
+ account: x.account,
274
+ subscriptions: decimalFromNullable(x.subscriptions).orDefault(zero),
275
+ shareClassValues: x.scvals.map(toShareClassValue),
276
+ };
277
+ });
278
+ }
279
+
280
+ /**
281
+ * Attempts to retrieve remote account valuation report, compiles it to
282
+ * {@link AccountValuationReport} and return it.
283
+ *
284
+ * @param client DECAF Barista client.
285
+ * @param query Remote account valuation report endpoint query parameters.
286
+ * @returns Recompiled account valuation report data.
287
+ */
288
+ export async function fetchAccountValuationReport(
289
+ client: DecafClient,
290
+ query: AccountValuationReportQuery
291
+ ): Promise<Either<CustomError, AccountValuationReport>> {
292
+ // Attempt to fetch the remote, raw report:
293
+ const rawReport = await fetchRemoteAccountValuationReport(client, query);
294
+
295
+ // Attempt to recompile the report (if any) and return:
296
+ return rawReport.chain(recompileAccountValuationReport);
297
+ }
@@ -0,0 +1,92 @@
1
+ import { Decimal, Maybe, SDate, SDateTime } from '@telostat/prelude';
2
+ import {
3
+ DecafActionId,
4
+ CurrencyCode,
5
+ DecafExternalValuationId,
6
+ DecafOhlcSeriesId,
7
+ DecafPortfolioId,
8
+ DecafPrincipalId,
9
+ DecafShareClassFeeScheduleId,
10
+ DecafShareClassId,
11
+ } from '../../commons';
12
+ import { BaseValuationReport, ValuationReportAccount } from './-valuation-report-shared';
13
+
14
+ export interface AccountValuationReport extends BaseValuationReport {
15
+ account: ValuationReportAccount;
16
+ subscriptions: Decimal;
17
+ shareClassValues: AccountValuationReportShareClassValue[];
18
+ }
19
+
20
+ export interface AccountValuationReportShareClassValue {
21
+ shareclass: Maybe<AccountValuationReportShareClass>;
22
+ external: Maybe<AccountValuationReportExternalValue>;
23
+ nav: Decimal;
24
+ navAdjusted: Decimal;
25
+ navAdjustedTotal: Decimal;
26
+ coefficient: Decimal;
27
+ gavRefccy: Decimal;
28
+ gavClsccy: Decimal;
29
+ sharecountPrev: Maybe<Decimal>;
30
+ sharecountCurr: Maybe<Decimal>;
31
+ sharecountDiff: Maybe<Decimal>;
32
+ pxRefCcy: Maybe<Decimal>;
33
+ pxClsCcy: Maybe<Decimal>;
34
+ ytdExt: Maybe<Decimal>;
35
+ ytdInt: Maybe<Decimal>;
36
+ }
37
+
38
+ export interface AccountValuationReportShareClass {
39
+ id: DecafShareClassId;
40
+ created: SDateTime;
41
+ creator: Maybe<DecafPrincipalId>;
42
+ updated: SDateTime;
43
+ updater: Maybe<DecafPrincipalId>;
44
+ guid: string;
45
+ portfolio: DecafPortfolioId;
46
+ name: string;
47
+ currency: CurrencyCode;
48
+ isin: Maybe<string>;
49
+ bbgticker: Maybe<string>;
50
+ liquidity: Maybe<string>;
51
+ jurisdiction: Maybe<string>;
52
+ administrator: Maybe<string>;
53
+ minimumInvestment: Maybe<number>;
54
+ subscriptionRedemptionPeriod: Maybe<string>;
55
+ managementFeeFrequency: Maybe<number>;
56
+ performanceFeeFrequency: Maybe<number>;
57
+ benchmark: Maybe<DecafOhlcSeriesId>;
58
+ description: Maybe<string>;
59
+ feeScheduleIds: DecafShareClassFeeScheduleId[];
60
+ effectiveFeeScheduleId: Maybe<DecafShareClassFeeScheduleId>;
61
+ subscriptionIds: DecafActionId[];
62
+ outstanding: Maybe<Decimal>;
63
+ }
64
+
65
+ export interface AccountValuationReportExternalValue {
66
+ id: DecafExternalValuationId;
67
+ created: SDateTime;
68
+ creator: Maybe<DecafPrincipalId>;
69
+ updated: SDateTime;
70
+ updater: Maybe<DecafPrincipalId>;
71
+ guid: string;
72
+ portfolio: DecafPortfolioId;
73
+ shareclass: Maybe<DecafShareClassId>;
74
+ date: SDate;
75
+ ccy: CurrencyCode;
76
+ shares: Maybe<Decimal>;
77
+ price: Maybe<Decimal>;
78
+ nav: Maybe<Decimal>;
79
+ aum: Maybe<Decimal>;
80
+ hedgepnl: Maybe<Decimal>;
81
+ feemngt: Maybe<Decimal>;
82
+ feeperf: Maybe<Decimal>;
83
+ otheraccrued: Maybe<Decimal>;
84
+ totalaccrued: Maybe<Decimal>;
85
+ subred: Maybe<Decimal>;
86
+ perfdaily: Maybe<Decimal>;
87
+ perfweekly: Maybe<Decimal>;
88
+ perfmonthly: Maybe<Decimal>;
89
+ perfytd: Maybe<Decimal>;
90
+ perfstart: Maybe<Decimal>;
91
+ coefficient: Maybe<Decimal>;
92
+ }
@@ -1,8 +1,12 @@
1
1
  import { Decimal, Just, List, Maybe, Nothing, safeDiv, sumDecimals, Tuple, zero } from '@telostat/prelude';
2
2
  import { ValuationReportHolding, ValuationReportHoldingClassification } from '../-valuation-report-shared';
3
3
  import { DecafArtifactTypeId } from '../../../commons';
4
- import { ValuationReportHoldingsTreeNode, ValuationReportHoldingsTreeNodeValue } from './-types';
5
- import { compareStringArrays } from './-utils';
4
+ import {
5
+ AvailableAddresserKeys,
6
+ ValuationReportHoldingsTreeNode,
7
+ ValuationReportHoldingsTreeNodeValue,
8
+ } from './-types';
9
+ import { addressers, compareStringArrays } from './-utils';
6
10
 
7
11
  export function makeValuationReportHoldingsTreeNodeValue(): ValuationReportHoldingsTreeNodeValue {
8
12
  return {
@@ -161,7 +165,8 @@ export function addValuationReportHoldingToTree(
161
165
  export function makeValuationReportHoldingsTree(
162
166
  nav: Decimal,
163
167
  investment: Decimal,
164
- holdings: ValuationReportHolding[]
168
+ holdings: ValuationReportHolding[],
169
+ addressKey: AvailableAddresserKeys = 'classification'
165
170
  ): ValuationReportHoldingsTreeNode {
166
171
  // Initialize the tree:
167
172
  const tree = makeValuationReportHoldingsTreeNode([]);
@@ -169,7 +174,10 @@ export function makeValuationReportHoldingsTree(
169
174
 
170
175
  // Iterate over the holdings and attempt to add to the tree:
171
176
  for (const holding of holdings) {
172
- addValuationReportHoldingToTree(tree, holding.classification, holding);
177
+ // Get the address of the holding:
178
+ const address = addressers[addressKey](holding);
179
+
180
+ addValuationReportHoldingToTree(tree, address, holding);
173
181
  }
174
182
 
175
183
  // Retreat the tree:
@@ -23,3 +23,13 @@ export interface ValuationReportHoldingsTreeNodeValue {
23
23
  pnl: Decimal;
24
24
  pnlRatio: Decimal;
25
25
  }
26
+
27
+ // export interface HoldingAddressSegment {
28
+ // value: string;
29
+ // label: string;
30
+ // order: string | number;
31
+ // }
32
+
33
+ export type HoldingAddress = ValuationReportHoldingClassification; // HoldingAddressSegment[];
34
+ export type HoldingAddresser = (holding: ValuationReportHolding) => HoldingAddress;
35
+ export type AvailableAddresserKeys = 'classification' | 'currency' | 'country' | 'issuer' | 'sector';
@@ -1,3 +1,7 @@
1
+ import { Maybe } from '@telostat/prelude';
2
+ import { ValuationReportHolding } from '../-valuation-report-shared';
3
+ import { AvailableAddresserKeys, HoldingAddress, HoldingAddresser } from './-types';
4
+
1
5
  export function compareStringArrays(x: string[], y: string[]): number {
2
6
  const xLen = x.length;
3
7
  const yLen = y.length;
@@ -13,3 +17,42 @@ export function compareStringArrays(x: string[], y: string[]): number {
13
17
 
14
18
  return Math.sign(xLen - yLen);
15
19
  }
20
+
21
+ export function composeHoldingAddressers(addressers: Array<HoldingAddresser>): HoldingAddresser {
22
+ return (holding: ValuationReportHolding) =>
23
+ addressers.reduce((p: HoldingAddress, c: HoldingAddresser) => [...p, ...c(holding)], []);
24
+ }
25
+
26
+ export function makeSimpleAddresser(
27
+ def: string,
28
+ labeler: (holding: ValuationReportHolding) => Maybe<string>
29
+ ): HoldingAddresser {
30
+ return (holding: ValuationReportHolding) => {
31
+ // Attempt to get the label:
32
+ const label = labeler(holding).orDefault('') || def;
33
+
34
+ // Get the value:
35
+ const value = label.toUpperCase();
36
+
37
+ // Done, return:
38
+ return [{ name: value, order: value }];
39
+ };
40
+ }
41
+
42
+ export const addressers: Record<AvailableAddresserKeys, HoldingAddresser> = {
43
+ classification: (holding: ValuationReportHolding) => {
44
+ // Get the classification:
45
+ const classification = holding.classification;
46
+
47
+ // Build the address and return:
48
+ return classification.map((x) => ({
49
+ // label: x.name,
50
+ name: x.name.toUpperCase(),
51
+ order: `${x.order}`.toUpperCase(),
52
+ }));
53
+ },
54
+ currency: makeSimpleAddresser('[Undefined Currency]', (holding: ValuationReportHolding) => holding.artifact.ccy),
55
+ country: makeSimpleAddresser('[Undefined Country]', (holding: ValuationReportHolding) => holding.artifact.country),
56
+ issuer: makeSimpleAddresser('[Undefined Issuer]', (holding: ValuationReportHolding) => holding.artifact.issuer),
57
+ sector: makeSimpleAddresser('[Undefined Sector]', (holding: ValuationReportHolding) => holding.artifact.sector),
58
+ };
@@ -2,7 +2,10 @@ export { fetchConsolidatedValuationReport } from './-remote-valuation-report-con
2
2
  export type { ConsolidatedValuationReportQuery } from './-remote-valuation-report-consolidated';
3
3
  export { fetchPortfolioValuationReport } from './-remote-valuation-report-portfolio';
4
4
  export type { PortfolioValuationReportQuery } from './-remote-valuation-report-portfolio';
5
+ export { fetchAccountValuationReport } from './-remote-valuation-report-account';
6
+ export type { AccountValuationReportQuery } from './-remote-valuation-report-account';
5
7
  export * from './-valuation-report-consolidated';
6
8
  export * from './-valuation-report-holdings-tree';
7
9
  export * from './-valuation-report-portfolio';
8
10
  export * from './-valuation-report-shared';
11
+ export * from './-valuation-report-account';