@decafhub/decaf-client-extras 0.5.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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.5.0"
2
+ ".": "0.5.1"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.1](https://github.com/teloscube/decaf-client-javascript-extras/compare/v0.5.0...v0.5.1) (2024-08-31)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * make grouping option configurable for holdings tree function ([ae97991](https://github.com/teloscube/decaf-client-javascript-extras/commit/ae97991f23393d04d85f782baedbd635a247db88))
9
+
3
10
  ## [0.5.0](https://github.com/teloscube/decaf-client-javascript-extras/compare/v0.4.0...v0.5.0) (2024-08-14)
4
11
 
5
12
 
@@ -1,10 +1,10 @@
1
1
  import { Decimal } from '@telostat/prelude';
2
2
  import { ValuationReportHolding, ValuationReportHoldingClassification } from '../-valuation-report-shared';
3
- import { ValuationReportHoldingsTreeNode, ValuationReportHoldingsTreeNodeValue } from './-types';
3
+ import { AvailableAddresserKeys, ValuationReportHoldingsTreeNode, ValuationReportHoldingsTreeNodeValue } from './-types';
4
4
  export declare function makeValuationReportHoldingsTreeNodeValue(): ValuationReportHoldingsTreeNodeValue;
5
5
  export declare function updateTotals(nav: Decimal, investment: Decimal, tree: ValuationReportHoldingsTreeNode): ValuationReportHoldingsTreeNodeValue;
6
6
  export declare function resortChildren(node: ValuationReportHoldingsTreeNode): ValuationReportHoldingsTreeNode[];
7
7
  export declare function retreatTree(nav: Decimal, investment: Decimal, tree: ValuationReportHoldingsTreeNode): void;
8
8
  export declare function makeValuationReportHoldingsTreeNode(address: ValuationReportHoldingClassification): ValuationReportHoldingsTreeNode;
9
9
  export declare function addValuationReportHoldingToTree(tree: ValuationReportHoldingsTreeNode, address: ValuationReportHoldingClassification, holding: ValuationReportHolding): void;
10
- export declare function makeValuationReportHoldingsTree(nav: Decimal, investment: Decimal, holdings: ValuationReportHolding[]): ValuationReportHoldingsTreeNode;
10
+ export declare function makeValuationReportHoldingsTree(nav: Decimal, investment: Decimal, holdings: ValuationReportHolding[], addressKey?: AvailableAddresserKeys): ValuationReportHoldingsTreeNode;
@@ -1,5 +1,5 @@
1
1
  import { Just, List, Maybe, Nothing, safeDiv, sumDecimals, Tuple, zero } from '@telostat/prelude';
2
- import { compareStringArrays } from './-utils';
2
+ import { addressers, compareStringArrays } from './-utils';
3
3
  export function makeValuationReportHoldingsTreeNodeValue() {
4
4
  return {
5
5
  investment: zero,
@@ -102,13 +102,15 @@ export function addValuationReportHoldingToTree(tree, address, holding) {
102
102
  // Done, we append the holding to the current node and return from the procedure:
103
103
  node.holdings.push(holding);
104
104
  }
105
- export function makeValuationReportHoldingsTree(nav, investment, holdings) {
105
+ export function makeValuationReportHoldingsTree(nav, investment, holdings, addressKey = 'classification') {
106
106
  // Initialize the tree:
107
107
  const tree = makeValuationReportHoldingsTreeNode([]);
108
108
  tree.name = '« Total »';
109
109
  // Iterate over the holdings and attempt to add to the tree:
110
110
  for (const holding of holdings) {
111
- addValuationReportHoldingToTree(tree, holding.classification, holding);
111
+ // Get the address of the holding:
112
+ const address = addressers[addressKey](holding);
113
+ addValuationReportHoldingToTree(tree, address, holding);
112
114
  }
113
115
  // Retreat the tree:
114
116
  retreatTree(nav, investment, tree);
@@ -21,3 +21,6 @@ export interface ValuationReportHoldingsTreeNodeValue {
21
21
  pnl: Decimal;
22
22
  pnlRatio: Decimal;
23
23
  }
24
+ export type HoldingAddress = ValuationReportHoldingClassification;
25
+ export type HoldingAddresser = (holding: ValuationReportHolding) => HoldingAddress;
26
+ export type AvailableAddresserKeys = 'classification' | 'currency' | 'country' | 'issuer' | 'sector';
@@ -1 +1,7 @@
1
+ import { Maybe } from '@telostat/prelude';
2
+ import { ValuationReportHolding } from '../-valuation-report-shared';
3
+ import { AvailableAddresserKeys, HoldingAddresser } from './-types';
1
4
  export declare function compareStringArrays(x: string[], y: string[]): number;
5
+ export declare function composeHoldingAddressers(addressers: Array<HoldingAddresser>): HoldingAddresser;
6
+ export declare function makeSimpleAddresser(def: string, labeler: (holding: ValuationReportHolding) => Maybe<string>): HoldingAddresser;
7
+ export declare const addressers: Record<AvailableAddresserKeys, HoldingAddresser>;
@@ -10,3 +10,32 @@ export function compareStringArrays(x, y) {
10
10
  }
11
11
  return Math.sign(xLen - yLen);
12
12
  }
13
+ export function composeHoldingAddressers(addressers) {
14
+ return (holding) => addressers.reduce((p, c) => [...p, ...c(holding)], []);
15
+ }
16
+ export function makeSimpleAddresser(def, labeler) {
17
+ return (holding) => {
18
+ // Attempt to get the label:
19
+ const label = labeler(holding).orDefault('') || def;
20
+ // Get the value:
21
+ const value = label.toUpperCase();
22
+ // Done, return:
23
+ return [{ name: value, order: value }];
24
+ };
25
+ }
26
+ export const addressers = {
27
+ classification: (holding) => {
28
+ // Get the classification:
29
+ const classification = holding.classification;
30
+ // Build the address and return:
31
+ return classification.map((x) => ({
32
+ // label: x.name,
33
+ name: x.name.toUpperCase(),
34
+ order: `${x.order}`.toUpperCase(),
35
+ }));
36
+ },
37
+ currency: makeSimpleAddresser('[Undefined Currency]', (holding) => holding.artifact.ccy),
38
+ country: makeSimpleAddresser('[Undefined Country]', (holding) => holding.artifact.country),
39
+ issuer: makeSimpleAddresser('[Undefined Issuer]', (holding) => holding.artifact.issuer),
40
+ sector: makeSimpleAddresser('[Undefined Sector]', (holding) => holding.artifact.sector),
41
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decafhub/decaf-client-extras",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "DECAF Client Extras",
5
5
  "author": "Teloscube Pte Ltd",
6
6
  "license": "MIT",
@@ -1,10 +1,10 @@
1
1
  import { Decimal } from '@telostat/prelude';
2
2
  import { ValuationReportHolding, ValuationReportHoldingClassification } from '../-valuation-report-shared';
3
- import { ValuationReportHoldingsTreeNode, ValuationReportHoldingsTreeNodeValue } from './-types';
3
+ import { AvailableAddresserKeys, ValuationReportHoldingsTreeNode, ValuationReportHoldingsTreeNodeValue } from './-types';
4
4
  export declare function makeValuationReportHoldingsTreeNodeValue(): ValuationReportHoldingsTreeNodeValue;
5
5
  export declare function updateTotals(nav: Decimal, investment: Decimal, tree: ValuationReportHoldingsTreeNode): ValuationReportHoldingsTreeNodeValue;
6
6
  export declare function resortChildren(node: ValuationReportHoldingsTreeNode): ValuationReportHoldingsTreeNode[];
7
7
  export declare function retreatTree(nav: Decimal, investment: Decimal, tree: ValuationReportHoldingsTreeNode): void;
8
8
  export declare function makeValuationReportHoldingsTreeNode(address: ValuationReportHoldingClassification): ValuationReportHoldingsTreeNode;
9
9
  export declare function addValuationReportHoldingToTree(tree: ValuationReportHoldingsTreeNode, address: ValuationReportHoldingClassification, holding: ValuationReportHolding): void;
10
- export declare function makeValuationReportHoldingsTree(nav: Decimal, investment: Decimal, holdings: ValuationReportHolding[]): ValuationReportHoldingsTreeNode;
10
+ export declare function makeValuationReportHoldingsTree(nav: Decimal, investment: Decimal, holdings: ValuationReportHolding[], addressKey?: AvailableAddresserKeys): ValuationReportHoldingsTreeNode;
@@ -165,8 +165,9 @@ function addValuationReportHoldingToTree(tree, address, holding) {
165
165
  node.holdings.push(holding);
166
166
  }
167
167
  exports.addValuationReportHoldingToTree = addValuationReportHoldingToTree;
168
- function makeValuationReportHoldingsTree(nav, investment, holdings) {
168
+ function makeValuationReportHoldingsTree(nav, investment, holdings, addressKey) {
169
169
  var e_2, _a;
170
+ if (addressKey === void 0) { addressKey = 'classification'; }
170
171
  // Initialize the tree:
171
172
  var tree = makeValuationReportHoldingsTreeNode([]);
172
173
  tree.name = '« Total »';
@@ -174,7 +175,9 @@ function makeValuationReportHoldingsTree(nav, investment, holdings) {
174
175
  // Iterate over the holdings and attempt to add to the tree:
175
176
  for (var holdings_1 = __values(holdings), holdings_1_1 = holdings_1.next(); !holdings_1_1.done; holdings_1_1 = holdings_1.next()) {
176
177
  var holding = holdings_1_1.value;
177
- addValuationReportHoldingToTree(tree, holding.classification, holding);
178
+ // Get the address of the holding:
179
+ var address = _utils_1.addressers[addressKey](holding);
180
+ addValuationReportHoldingToTree(tree, address, holding);
178
181
  }
179
182
  }
180
183
  catch (e_2_1) { e_2 = { error: e_2_1 }; }
@@ -21,3 +21,6 @@ export interface ValuationReportHoldingsTreeNodeValue {
21
21
  pnl: Decimal;
22
22
  pnlRatio: Decimal;
23
23
  }
24
+ export type HoldingAddress = ValuationReportHoldingClassification;
25
+ export type HoldingAddresser = (holding: ValuationReportHolding) => HoldingAddress;
26
+ export type AvailableAddresserKeys = 'classification' | 'currency' | 'country' | 'issuer' | 'sector';
@@ -1 +1,7 @@
1
+ import { Maybe } from '@telostat/prelude';
2
+ import { ValuationReportHolding } from '../-valuation-report-shared';
3
+ import { AvailableAddresserKeys, HoldingAddresser } from './-types';
1
4
  export declare function compareStringArrays(x: string[], y: string[]): number;
5
+ export declare function composeHoldingAddressers(addressers: Array<HoldingAddresser>): HoldingAddresser;
6
+ export declare function makeSimpleAddresser(def: string, labeler: (holding: ValuationReportHolding) => Maybe<string>): HoldingAddresser;
7
+ export declare const addressers: Record<AvailableAddresserKeys, HoldingAddresser>;
@@ -1,6 +1,31 @@
1
1
  "use strict";
2
+ var __read = (this && this.__read) || function (o, n) {
3
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
4
+ if (!m) return o;
5
+ var i = m.call(o), r, ar = [], e;
6
+ try {
7
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
8
+ }
9
+ catch (error) { e = { error: error }; }
10
+ finally {
11
+ try {
12
+ if (r && !r.done && (m = i["return"])) m.call(i);
13
+ }
14
+ finally { if (e) throw e.error; }
15
+ }
16
+ return ar;
17
+ };
18
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
19
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
20
+ if (ar || !(i in from)) {
21
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
22
+ ar[i] = from[i];
23
+ }
24
+ }
25
+ return to.concat(ar || Array.prototype.slice.call(from));
26
+ };
2
27
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compareStringArrays = void 0;
28
+ exports.addressers = exports.makeSimpleAddresser = exports.composeHoldingAddressers = exports.compareStringArrays = void 0;
4
29
  function compareStringArrays(x, y) {
5
30
  var xLen = x.length;
6
31
  var yLen = y.length;
@@ -14,3 +39,36 @@ function compareStringArrays(x, y) {
14
39
  return Math.sign(xLen - yLen);
15
40
  }
16
41
  exports.compareStringArrays = compareStringArrays;
42
+ function composeHoldingAddressers(addressers) {
43
+ return function (holding) {
44
+ return addressers.reduce(function (p, c) { return __spreadArray(__spreadArray([], __read(p), false), __read(c(holding)), false); }, []);
45
+ };
46
+ }
47
+ exports.composeHoldingAddressers = composeHoldingAddressers;
48
+ function makeSimpleAddresser(def, labeler) {
49
+ return function (holding) {
50
+ // Attempt to get the label:
51
+ var label = labeler(holding).orDefault('') || def;
52
+ // Get the value:
53
+ var value = label.toUpperCase();
54
+ // Done, return:
55
+ return [{ name: value, order: value }];
56
+ };
57
+ }
58
+ exports.makeSimpleAddresser = makeSimpleAddresser;
59
+ exports.addressers = {
60
+ classification: function (holding) {
61
+ // Get the classification:
62
+ var classification = holding.classification;
63
+ // Build the address and return:
64
+ return classification.map(function (x) { return ({
65
+ // label: x.name,
66
+ name: x.name.toUpperCase(),
67
+ order: "".concat(x.order).toUpperCase(),
68
+ }); });
69
+ },
70
+ currency: makeSimpleAddresser('[Undefined Currency]', function (holding) { return holding.artifact.ccy; }),
71
+ country: makeSimpleAddresser('[Undefined Country]', function (holding) { return holding.artifact.country; }),
72
+ issuer: makeSimpleAddresser('[Undefined Issuer]', function (holding) { return holding.artifact.issuer; }),
73
+ sector: makeSimpleAddresser('[Undefined Sector]', function (holding) { return holding.artifact.sector; }),
74
+ };
@@ -154,7 +154,7 @@ describe('Reports', () => {
154
154
  const nav = value.figures.nav;
155
155
  const inv = value.figures.investment;
156
156
  const holdings = value.holdings;
157
- const tree = makeValuationReportHoldingsTree(nav, inv, holdings);
157
+ const tree = makeValuationReportHoldingsTree(nav, inv, holdings, 'country');
158
158
  expect(tree).toBeDefined();
159
159
  expect(safeDiv(tree.totals.netExposure, nav).orDefault(zero)).toEqual(tree.totals.netExposureRatio);
160
160
  },
@@ -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
+ };