@decafhub/decaf-client-extras 0.5.0 → 0.5.2
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.
- package/.husky/commit-msg +0 -3
- package/.husky/pre-commit +1 -4
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/commons/-currency.js +4 -4
- package/commons/-id.js +2 -3
- package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.d.ts +2 -2
- package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.js +5 -3
- package/es/reports/valuation/-valuation-report-holdings-tree/-types.d.ts +3 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-utils.d.ts +6 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-utils.js +29 -0
- package/eslint.config.mjs +54 -0
- package/package.json +29 -24
- package/postinstall.sh +1 -1
- package/reports/valuation/-remote-valuation-report-account.js +4 -5
- package/reports/valuation/-remote-valuation-report-consolidated.js +3 -4
- package/reports/valuation/-remote-valuation-report-portfolio.js +4 -5
- package/reports/valuation/-remote-valuation-report-shared.js +7 -8
- package/reports/valuation/-valuation-report-holdings-tree/-machinery.d.ts +2 -2
- package/reports/valuation/-valuation-report-holdings-tree/-machinery.js +12 -10
- package/reports/valuation/-valuation-report-holdings-tree/-types.d.ts +3 -0
- package/reports/valuation/-valuation-report-holdings-tree/-utils.d.ts +6 -0
- package/reports/valuation/-valuation-report-holdings-tree/-utils.js +60 -2
- package/reports/valuation/-valuation-report-shared.js +2 -3
- package/shell.nix +10 -5
- package/src/reports/index.test.ts +1 -1
- package/src/reports/valuation/-valuation-report-holdings-tree/-machinery.ts +12 -4
- package/src/reports/valuation/-valuation-report-holdings-tree/-types.ts +10 -0
- package/src/reports/valuation/-valuation-report-holdings-tree/-utils.ts +43 -0
- package/.eslintignore +0 -3
- package/.eslintrc.js +0 -23
- package/nix/default.nix +0 -58
- package/nix/sources.json +0 -14
- package/nix/sources.nix +0 -194
package/.husky/commit-msg
CHANGED
package/.husky/pre-commit
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.2](https://github.com/teloscube/decaf-client-javascript-extras/compare/v0.5.1...v0.5.2) (2024-09-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* upgrade dependencies ([81f3b80](https://github.com/teloscube/decaf-client-javascript-extras/commit/81f3b80307f17e0a85f88e9f1202551b77155004))
|
|
9
|
+
|
|
10
|
+
## [0.5.1](https://github.com/teloscube/decaf-client-javascript-extras/compare/v0.5.0...v0.5.1) (2024-08-31)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* make grouping option configurable for holdings tree function ([ae97991](https://github.com/teloscube/decaf-client-javascript-extras/commit/ae97991f23393d04d85f782baedbd635a247db88))
|
|
16
|
+
|
|
3
17
|
## [0.5.0](https://github.com/teloscube/decaf-client-javascript-extras/compare/v0.4.0...v0.5.0) (2024-08-14)
|
|
4
18
|
|
|
5
19
|
|
package/commons/-currency.js
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
8
|
+
exports.REGEXP_CURRENCY_CODE = void 0;
|
|
9
|
+
exports.mkCurrencyCode = mkCurrencyCode;
|
|
10
|
+
exports.mkCurrencyCodeError = mkCurrencyCodeError;
|
|
11
|
+
exports.unCurrencyCode = unCurrencyCode;
|
|
9
12
|
var prelude_1 = require("@telostat/prelude");
|
|
10
13
|
/**
|
|
11
14
|
* Regular expression for currency codes in our concept.
|
|
@@ -24,7 +27,6 @@ exports.REGEXP_CURRENCY_CODE = /^[A-Z][a-zA-Z]*$/;
|
|
|
24
27
|
function mkCurrencyCode(x) {
|
|
25
28
|
return exports.REGEXP_CURRENCY_CODE.test(x) ? (0, prelude_1.Just)(x) : prelude_1.Nothing;
|
|
26
29
|
}
|
|
27
|
-
exports.mkCurrencyCode = mkCurrencyCode;
|
|
28
30
|
/**
|
|
29
31
|
* (Unsafely) attempts to create a {@link CurrencyCode} value with the given
|
|
30
32
|
* currency code.
|
|
@@ -41,7 +43,6 @@ function mkCurrencyCodeError(x) {
|
|
|
41
43
|
throw new Error("Invalid currency code: ".concat(x));
|
|
42
44
|
});
|
|
43
45
|
}
|
|
44
|
-
exports.mkCurrencyCodeError = mkCurrencyCodeError;
|
|
45
46
|
/**
|
|
46
47
|
* Return the currency code as a string value.
|
|
47
48
|
*
|
|
@@ -53,4 +54,3 @@ exports.mkCurrencyCodeError = mkCurrencyCodeError;
|
|
|
53
54
|
function unCurrencyCode(x) {
|
|
54
55
|
return x;
|
|
55
56
|
}
|
|
56
|
-
exports.unCurrencyCode = unCurrencyCode;
|
package/commons/-id.js
CHANGED
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
* @module
|
|
53
53
|
*/
|
|
54
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
-
exports.
|
|
55
|
+
exports.mkDecafRecordId = mkDecafRecordId;
|
|
56
|
+
exports.unDecafRecordId = unDecafRecordId;
|
|
56
57
|
/**
|
|
57
58
|
* Constructor for DECAF record identifiers.
|
|
58
59
|
*
|
|
@@ -62,7 +63,6 @@ exports.unDecafRecordId = exports.mkDecafRecordId = void 0;
|
|
|
62
63
|
function mkDecafRecordId(x) {
|
|
63
64
|
return x;
|
|
64
65
|
}
|
|
65
|
-
exports.mkDecafRecordId = mkDecafRecordId;
|
|
66
66
|
/**
|
|
67
67
|
* Deconstructor for DECAF record identifiers.
|
|
68
68
|
*
|
|
@@ -72,4 +72,3 @@ exports.mkDecafRecordId = mkDecafRecordId;
|
|
|
72
72
|
function unDecafRecordId(x) {
|
|
73
73
|
return x;
|
|
74
74
|
}
|
|
75
|
-
exports.unDecafRecordId = unDecafRecordId;
|
|
@@ -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
|
-
|
|
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
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { FlatCompat } from '@eslint/eslintrc';
|
|
2
|
+
import js from '@eslint/js';
|
|
3
|
+
import typescriptEslint from '@typescript-eslint/eslint-plugin';
|
|
4
|
+
import tsParser from '@typescript-eslint/parser';
|
|
5
|
+
import prettier from 'eslint-plugin-prettier';
|
|
6
|
+
import globals from 'globals';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const compat = new FlatCompat({
|
|
13
|
+
baseDirectory: __dirname,
|
|
14
|
+
recommendedConfig: js.configs.recommended,
|
|
15
|
+
allConfig: js.configs.all,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export default [
|
|
19
|
+
{
|
|
20
|
+
ignores: ['**/lib', '**/docs', '**/.husky'],
|
|
21
|
+
},
|
|
22
|
+
...compat.extends(
|
|
23
|
+
'standard',
|
|
24
|
+
'prettier',
|
|
25
|
+
'plugin:prettier/recommended',
|
|
26
|
+
'plugin:@typescript-eslint/eslint-recommended'
|
|
27
|
+
),
|
|
28
|
+
{
|
|
29
|
+
plugins: {
|
|
30
|
+
'@typescript-eslint': typescriptEslint,
|
|
31
|
+
prettier,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
languageOptions: {
|
|
35
|
+
globals: {
|
|
36
|
+
...globals.browser,
|
|
37
|
+
Atomics: 'readonly',
|
|
38
|
+
SharedArrayBuffer: 'readonly',
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
parser: tsParser,
|
|
42
|
+
ecmaVersion: 2018,
|
|
43
|
+
sourceType: 'module',
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
rules: {
|
|
47
|
+
'prettier/prettier': 'error',
|
|
48
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
49
|
+
'no-use-before-define': 'off',
|
|
50
|
+
'@typescript-eslint/no-use-before-define': ['error'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decafhub/decaf-client-extras",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "DECAF Client Extras",
|
|
5
5
|
"author": "Teloscube Pte Ltd",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,33 +30,35 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@telostat/prelude": "^0.5.0",
|
|
33
|
-
"dayjs": "^1.11.
|
|
33
|
+
"dayjs": "^1.11.13"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@commitlint/cli": "^
|
|
37
|
-
"@commitlint/config-conventional": "^
|
|
38
|
-
"@decafhub/decaf-client": "^0.5.
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"eslint": "^8.
|
|
36
|
+
"@commitlint/cli": "^19.4.1",
|
|
37
|
+
"@commitlint/config-conventional": "^19.4.1",
|
|
38
|
+
"@decafhub/decaf-client": "^0.5.1",
|
|
39
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
40
|
+
"@eslint/js": "^9.9.1",
|
|
41
|
+
"@types/jest": "^29.5.12",
|
|
42
|
+
"@types/node": "^22.5.4",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^8.4.0",
|
|
44
|
+
"@typescript-eslint/parser": "^8.4.0",
|
|
45
|
+
"dotenv": "^16.4.5",
|
|
46
|
+
"eslint": "^9.9.1",
|
|
45
47
|
"eslint-config-prettier": "^9.1.0",
|
|
46
|
-
"eslint-
|
|
47
|
-
"eslint-plugin-
|
|
48
|
-
"eslint-plugin-
|
|
49
|
-
"eslint-plugin-prettier": "^5.0.1",
|
|
50
|
-
"eslint-plugin-promise": "^6.1.1",
|
|
48
|
+
"eslint-plugin-n": "^17.10.2",
|
|
49
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
50
|
+
"eslint-plugin-promise": "^7.1.0",
|
|
51
51
|
"eslint-plugin-standard": "^5.0.0",
|
|
52
|
-
"gh-pages": "^6.1.
|
|
53
|
-
"
|
|
52
|
+
"gh-pages": "^6.1.1",
|
|
53
|
+
"globals": "^15.9.0",
|
|
54
|
+
"husky": "^9.1.5",
|
|
54
55
|
"jest": "^29.7.0",
|
|
55
|
-
"lint-staged": "^15.2.
|
|
56
|
-
"prettier": "^3.
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
56
|
+
"lint-staged": "^15.2.10",
|
|
57
|
+
"prettier": "^3.3.3",
|
|
58
|
+
"prettier-plugin-organize-imports": "^4.0.0",
|
|
59
|
+
"ts-jest": "^29.2.5",
|
|
60
|
+
"typedoc": "^0.26.6",
|
|
61
|
+
"typescript": "^5.5.4"
|
|
60
62
|
},
|
|
61
63
|
"lint-staged": {
|
|
62
64
|
"src/**/*.{ts,tsx}": [
|
|
@@ -70,7 +72,10 @@
|
|
|
70
72
|
"useTabs": false,
|
|
71
73
|
"semi": true,
|
|
72
74
|
"singleQuote": true,
|
|
73
|
-
"trailingComma": "es5"
|
|
75
|
+
"trailingComma": "es5",
|
|
76
|
+
"plugins": [
|
|
77
|
+
"prettier-plugin-organize-imports"
|
|
78
|
+
]
|
|
74
79
|
},
|
|
75
80
|
"commitlint": {
|
|
76
81
|
"extends": [
|
package/postinstall.sh
CHANGED
|
@@ -47,7 +47,10 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.
|
|
50
|
+
exports.fetchRemoteAccountValuationReport = fetchRemoteAccountValuationReport;
|
|
51
|
+
exports.toShareClassValue = toShareClassValue;
|
|
52
|
+
exports.recompileAccountValuationReport = recompileAccountValuationReport;
|
|
53
|
+
exports.fetchAccountValuationReport = fetchAccountValuationReport;
|
|
51
54
|
var prelude_1 = require("@telostat/prelude");
|
|
52
55
|
var _remote_valuation_report_shared_1 = require("./-remote-valuation-report-shared");
|
|
53
56
|
/**
|
|
@@ -74,7 +77,6 @@ function fetchRemoteAccountValuationReport(client, query) {
|
|
|
74
77
|
});
|
|
75
78
|
});
|
|
76
79
|
}
|
|
77
|
-
exports.fetchRemoteAccountValuationReport = fetchRemoteAccountValuationReport;
|
|
78
80
|
/**
|
|
79
81
|
* Attempts to recompile remote valuation report share class value.
|
|
80
82
|
*
|
|
@@ -153,7 +155,6 @@ function toShareClassValue(s) {
|
|
|
153
155
|
ytdInt: (0, prelude_1.decimalFromNullable)(s.ytdint),
|
|
154
156
|
};
|
|
155
157
|
}
|
|
156
|
-
exports.toShareClassValue = toShareClassValue;
|
|
157
158
|
/**
|
|
158
159
|
* Attempts to re-compile the raw, remote account valuation report and
|
|
159
160
|
* return it.
|
|
@@ -170,7 +171,6 @@ function recompileAccountValuationReport(x) {
|
|
|
170
171
|
return __assign(__assign({}, report), { account: x.account, subscriptions: (0, prelude_1.decimalFromNullable)(x.subscriptions).orDefault(prelude_1.zero), shareClassValues: x.scvals.map(toShareClassValue) });
|
|
171
172
|
});
|
|
172
173
|
}
|
|
173
|
-
exports.recompileAccountValuationReport = recompileAccountValuationReport;
|
|
174
174
|
/**
|
|
175
175
|
* Attempts to retrieve remote account valuation report, compiles it to
|
|
176
176
|
* {@link AccountValuationReport} and return it.
|
|
@@ -193,4 +193,3 @@ function fetchAccountValuationReport(client, query) {
|
|
|
193
193
|
});
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
|
-
exports.fetchAccountValuationReport = fetchAccountValuationReport;
|
|
@@ -47,7 +47,9 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.
|
|
50
|
+
exports.fetchRemoteConsolidatedValuationReport = fetchRemoteConsolidatedValuationReport;
|
|
51
|
+
exports.recompileConsolidatedValuationReport = recompileConsolidatedValuationReport;
|
|
52
|
+
exports.fetchConsolidatedValuationReport = fetchConsolidatedValuationReport;
|
|
51
53
|
var prelude_1 = require("@telostat/prelude");
|
|
52
54
|
var _remote_valuation_report_shared_1 = require("./-remote-valuation-report-shared");
|
|
53
55
|
/**
|
|
@@ -72,7 +74,6 @@ function fetchRemoteConsolidatedValuationReport(client, query) {
|
|
|
72
74
|
.then(function (x) { return (0, prelude_1.Right)(x.data); })
|
|
73
75
|
.catch(function (err) { return (0, prelude_1.Left)((0, prelude_1.customError)('Error while attempting to fetch remote consolidated valuation report', err)); });
|
|
74
76
|
}
|
|
75
|
-
exports.fetchRemoteConsolidatedValuationReport = fetchRemoteConsolidatedValuationReport;
|
|
76
77
|
/**
|
|
77
78
|
* Attempts to re-compile the raw, remote consolidated valuation report and
|
|
78
79
|
* return it.
|
|
@@ -87,7 +88,6 @@ function recompileConsolidatedValuationReport(x) {
|
|
|
87
88
|
// Add consolidated valuation report specific fields and return:
|
|
88
89
|
return baseReport.map(function (report) { return (__assign(__assign({}, report), { containerType: x.containers.level, containers: x.containers.containers })); });
|
|
89
90
|
}
|
|
90
|
-
exports.recompileConsolidatedValuationReport = recompileConsolidatedValuationReport;
|
|
91
91
|
/**
|
|
92
92
|
* Attempts to retrieve remote consolidated valuation report, compiles it to
|
|
93
93
|
* {@link ConsolidatedValuationReport} and return it.
|
|
@@ -110,4 +110,3 @@ function fetchConsolidatedValuationReport(client, query) {
|
|
|
110
110
|
});
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
|
-
exports.fetchConsolidatedValuationReport = fetchConsolidatedValuationReport;
|
|
@@ -47,7 +47,10 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.
|
|
50
|
+
exports.fetchRemotePortfolioValuationReport = fetchRemotePortfolioValuationReport;
|
|
51
|
+
exports.toShareClassValue = toShareClassValue;
|
|
52
|
+
exports.recompilePortfolioValuationReport = recompilePortfolioValuationReport;
|
|
53
|
+
exports.fetchPortfolioValuationReport = fetchPortfolioValuationReport;
|
|
51
54
|
var prelude_1 = require("@telostat/prelude");
|
|
52
55
|
var _remote_valuation_report_shared_1 = require("./-remote-valuation-report-shared");
|
|
53
56
|
/**
|
|
@@ -70,7 +73,6 @@ function fetchRemotePortfolioValuationReport(client, query) {
|
|
|
70
73
|
.then(function (x) { return (0, prelude_1.Right)(x.data); })
|
|
71
74
|
.catch(function (err) { return (0, prelude_1.Left)((0, prelude_1.customError)('Error while attempting to fetch remote portfolio valuation report', err)); });
|
|
72
75
|
}
|
|
73
|
-
exports.fetchRemotePortfolioValuationReport = fetchRemotePortfolioValuationReport;
|
|
74
76
|
/**
|
|
75
77
|
* Attempts to recompile remote valuation report share class value.
|
|
76
78
|
*
|
|
@@ -149,7 +151,6 @@ function toShareClassValue(s) {
|
|
|
149
151
|
ytdInt: (0, prelude_1.decimalFromNullable)(s.ytdint),
|
|
150
152
|
};
|
|
151
153
|
}
|
|
152
|
-
exports.toShareClassValue = toShareClassValue;
|
|
153
154
|
/**
|
|
154
155
|
* Attempts to re-compile the raw, remote portfolio valuation report and
|
|
155
156
|
* return it.
|
|
@@ -166,7 +167,6 @@ function recompilePortfolioValuationReport(x) {
|
|
|
166
167
|
return __assign(__assign({}, report), { portfolio: x.portfolio, subscriptions: (0, prelude_1.decimalFromNullable)(x.subscriptions).orDefault(prelude_1.zero), shareClassValues: x.scvals.map(toShareClassValue) });
|
|
167
168
|
});
|
|
168
169
|
}
|
|
169
|
-
exports.recompilePortfolioValuationReport = recompilePortfolioValuationReport;
|
|
170
170
|
/**
|
|
171
171
|
* Attempts to retrieve remote portfolio valuation report, compiles it to
|
|
172
172
|
* {@link PortfolioValuationReport} and return it.
|
|
@@ -189,4 +189,3 @@ function fetchPortfolioValuationReport(client, query) {
|
|
|
189
189
|
});
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
|
-
exports.fetchPortfolioValuationReport = fetchPortfolioValuationReport;
|
|
@@ -11,7 +11,13 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.
|
|
14
|
+
exports.toArtifact = toArtifact;
|
|
15
|
+
exports.toAccrual = toAccrual;
|
|
16
|
+
exports.toOrgRef = toOrgRef;
|
|
17
|
+
exports.toMaybeOrgRef = toMaybeOrgRef;
|
|
18
|
+
exports.toBaseHolding = toBaseHolding;
|
|
19
|
+
exports.toHolding = toHolding;
|
|
20
|
+
exports.recompileBaseValuationReport = recompileBaseValuationReport;
|
|
15
21
|
var prelude_1 = require("@telostat/prelude");
|
|
16
22
|
function toArtifact(x) {
|
|
17
23
|
return {
|
|
@@ -34,7 +40,6 @@ function toArtifact(x) {
|
|
|
34
40
|
underlyingId: prelude_1.Maybe.fromNullable(x.underlying_id),
|
|
35
41
|
};
|
|
36
42
|
}
|
|
37
|
-
exports.toArtifact = toArtifact;
|
|
38
43
|
function toAccrual(x) {
|
|
39
44
|
return {
|
|
40
45
|
name: x.name,
|
|
@@ -53,21 +58,18 @@ function toAccrual(x) {
|
|
|
53
58
|
}); }),
|
|
54
59
|
};
|
|
55
60
|
}
|
|
56
|
-
exports.toAccrual = toAccrual;
|
|
57
61
|
function toOrgRef(x) {
|
|
58
62
|
return {
|
|
59
63
|
org: (0, prelude_1.decimalFromNullable)(x.org).orDefault(prelude_1.zero),
|
|
60
64
|
ref: (0, prelude_1.decimalFromNullable)(x.ref).orDefault(prelude_1.zero),
|
|
61
65
|
};
|
|
62
66
|
}
|
|
63
|
-
exports.toOrgRef = toOrgRef;
|
|
64
67
|
function toMaybeOrgRef(x) {
|
|
65
68
|
return prelude_1.Maybe.fromNullable(x).chain(function (_a) {
|
|
66
69
|
var org = _a.org, ref = _a.ref;
|
|
67
70
|
return (0, prelude_1.decimalFromNullable)(org).chain(function (o) { return (0, prelude_1.decimalFromNullable)(ref).chain(function (r) { return (0, prelude_1.Just)({ org: o, ref: r }); }); });
|
|
68
71
|
});
|
|
69
72
|
}
|
|
70
|
-
exports.toMaybeOrgRef = toMaybeOrgRef;
|
|
71
73
|
function toBaseHolding(nav, x) {
|
|
72
74
|
return {
|
|
73
75
|
artifact: toArtifact(x.artifact),
|
|
@@ -100,7 +102,6 @@ function toBaseHolding(nav, x) {
|
|
|
100
102
|
lastdate: x.lastdate,
|
|
101
103
|
};
|
|
102
104
|
}
|
|
103
|
-
exports.toBaseHolding = toBaseHolding;
|
|
104
105
|
function toHolding(nav, x) {
|
|
105
106
|
return __assign(__assign({}, toBaseHolding(nav, x)), { classification: x.tags.classification.map(function (n) { return (__assign(__assign({}, n), { order: n.order || '' })); }), accounts: x.accounts, children: prelude_1.Maybe.fromNullable(x.children)
|
|
106
107
|
.filter(function (mc) { return mc.length !== 0; })
|
|
@@ -108,7 +109,6 @@ function toHolding(nav, x) {
|
|
|
108
109
|
return mc.map(function (c) { return (__assign(__assign({}, toBaseHolding(nav, c)), { account: c.accounts[0] })); });
|
|
109
110
|
}) });
|
|
110
111
|
}
|
|
111
|
-
exports.toHolding = toHolding;
|
|
112
112
|
/**
|
|
113
113
|
* Attempts to re-compile the raw, remote base valuation report and
|
|
114
114
|
* return it.
|
|
@@ -145,4 +145,3 @@ function recompileBaseValuationReport(x) {
|
|
|
145
145
|
};
|
|
146
146
|
return (0, prelude_1.Right)(report);
|
|
147
147
|
}
|
|
148
|
-
exports.recompileBaseValuationReport = recompileBaseValuationReport;
|
|
@@ -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;
|
|
@@ -36,7 +36,13 @@ var __values = (this && this.__values) || function(o) {
|
|
|
36
36
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.makeValuationReportHoldingsTreeNodeValue = makeValuationReportHoldingsTreeNodeValue;
|
|
40
|
+
exports.updateTotals = updateTotals;
|
|
41
|
+
exports.resortChildren = resortChildren;
|
|
42
|
+
exports.retreatTree = retreatTree;
|
|
43
|
+
exports.makeValuationReportHoldingsTreeNode = makeValuationReportHoldingsTreeNode;
|
|
44
|
+
exports.addValuationReportHoldingToTree = addValuationReportHoldingToTree;
|
|
45
|
+
exports.makeValuationReportHoldingsTree = makeValuationReportHoldingsTree;
|
|
40
46
|
var prelude_1 = require("@telostat/prelude");
|
|
41
47
|
var _utils_1 = require("./-utils");
|
|
42
48
|
function makeValuationReportHoldingsTreeNodeValue() {
|
|
@@ -55,7 +61,6 @@ function makeValuationReportHoldingsTreeNodeValue() {
|
|
|
55
61
|
pnlRatio: prelude_1.zero,
|
|
56
62
|
};
|
|
57
63
|
}
|
|
58
|
-
exports.makeValuationReportHoldingsTreeNodeValue = makeValuationReportHoldingsTreeNodeValue;
|
|
59
64
|
function updateTotals(nav, investment, tree) {
|
|
60
65
|
var holdings = tree.holdings;
|
|
61
66
|
var children = tree.children;
|
|
@@ -87,7 +92,6 @@ function updateTotals(nav, investment, tree) {
|
|
|
87
92
|
pnlRatio: (0, prelude_1.safeDiv)(pnl, investment).orDefault(prelude_1.zero),
|
|
88
93
|
};
|
|
89
94
|
}
|
|
90
|
-
exports.updateTotals = updateTotals;
|
|
91
95
|
function resortChildren(node) {
|
|
92
96
|
return node.children.sort(function (t1, t2) {
|
|
93
97
|
// Get current address segments:
|
|
@@ -104,7 +108,6 @@ function resortChildren(node) {
|
|
|
104
108
|
.orDefaultLazy(function () { return (segment1.isNothing() ? -1 : 1); });
|
|
105
109
|
});
|
|
106
110
|
}
|
|
107
|
-
exports.resortChildren = resortChildren;
|
|
108
111
|
function retreatTree(nav, investment, tree) {
|
|
109
112
|
// First, retreat all children (recursive):
|
|
110
113
|
tree.children.forEach(function (x) { return retreatTree(nav, investment, x); });
|
|
@@ -113,7 +116,6 @@ function retreatTree(nav, investment, tree) {
|
|
|
113
116
|
// Resort children:
|
|
114
117
|
tree.children = resortChildren(tree);
|
|
115
118
|
}
|
|
116
|
-
exports.retreatTree = retreatTree;
|
|
117
119
|
function makeValuationReportHoldingsTreeNode(address) {
|
|
118
120
|
return {
|
|
119
121
|
name: prelude_1.List.last(address)
|
|
@@ -125,7 +127,6 @@ function makeValuationReportHoldingsTreeNode(address) {
|
|
|
125
127
|
totals: makeValuationReportHoldingsTreeNodeValue(),
|
|
126
128
|
};
|
|
127
129
|
}
|
|
128
|
-
exports.makeValuationReportHoldingsTreeNode = makeValuationReportHoldingsTreeNode;
|
|
129
130
|
function addValuationReportHoldingToTree(tree, address, holding) {
|
|
130
131
|
var e_1, _a;
|
|
131
132
|
// Get the starting (current) node:
|
|
@@ -164,9 +165,9 @@ function addValuationReportHoldingToTree(tree, address, holding) {
|
|
|
164
165
|
// Done, we append the holding to the current node and return from the procedure:
|
|
165
166
|
node.holdings.push(holding);
|
|
166
167
|
}
|
|
167
|
-
|
|
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
|
-
|
|
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 }; }
|
|
@@ -189,4 +192,3 @@ function makeValuationReportHoldingsTree(nav, investment, holdings) {
|
|
|
189
192
|
// Done, return:
|
|
190
193
|
return tree;
|
|
191
194
|
}
|
|
192
|
-
exports.makeValuationReportHoldingsTree = makeValuationReportHoldingsTree;
|
|
@@ -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,34 @@
|
|
|
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.
|
|
28
|
+
exports.addressers = void 0;
|
|
29
|
+
exports.compareStringArrays = compareStringArrays;
|
|
30
|
+
exports.composeHoldingAddressers = composeHoldingAddressers;
|
|
31
|
+
exports.makeSimpleAddresser = makeSimpleAddresser;
|
|
4
32
|
function compareStringArrays(x, y) {
|
|
5
33
|
var xLen = x.length;
|
|
6
34
|
var yLen = y.length;
|
|
@@ -13,4 +41,34 @@ function compareStringArrays(x, y) {
|
|
|
13
41
|
}
|
|
14
42
|
return Math.sign(xLen - yLen);
|
|
15
43
|
}
|
|
16
|
-
|
|
44
|
+
function composeHoldingAddressers(addressers) {
|
|
45
|
+
return function (holding) {
|
|
46
|
+
return addressers.reduce(function (p, c) { return __spreadArray(__spreadArray([], __read(p), false), __read(c(holding)), false); }, []);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function makeSimpleAddresser(def, labeler) {
|
|
50
|
+
return function (holding) {
|
|
51
|
+
// Attempt to get the label:
|
|
52
|
+
var label = labeler(holding).orDefault('') || def;
|
|
53
|
+
// Get the value:
|
|
54
|
+
var value = label.toUpperCase();
|
|
55
|
+
// Done, return:
|
|
56
|
+
return [{ name: value, order: value }];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
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
|
+
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.isValuationHolding = isValuationHolding;
|
|
4
|
+
exports.isValuationChildHolding = isValuationChildHolding;
|
|
4
5
|
function isValuationHolding(x) {
|
|
5
6
|
return 'accounts' in x;
|
|
6
7
|
}
|
|
7
|
-
exports.isValuationHolding = isValuationHolding;
|
|
8
8
|
function isValuationChildHolding(x) {
|
|
9
9
|
return 'account' in x;
|
|
10
10
|
}
|
|
11
|
-
exports.isValuationChildHolding = isValuationChildHolding;
|
package/shell.nix
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
{
|
|
1
|
+
with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/24.05.tar.gz") { };
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
stdenv.mkDerivation {
|
|
4
|
+
name = "decaf-client-javascript-extras";
|
|
5
|
+
|
|
6
|
+
buildInputs = with pkgs; [
|
|
7
|
+
nodejs_18
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
NODE_OPTIONS = "--max-old-space-size=4096";
|
|
11
|
+
}
|
|
@@ -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 {
|
|
5
|
-
|
|
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
|
-
|
|
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
|
+
};
|
package/.eslintignore
DELETED
package/.eslintrc.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
env: {
|
|
3
|
-
browser: true,
|
|
4
|
-
es6: true,
|
|
5
|
-
},
|
|
6
|
-
globals: {
|
|
7
|
-
Atomics: 'readonly',
|
|
8
|
-
SharedArrayBuffer: 'readonly',
|
|
9
|
-
},
|
|
10
|
-
parser: '@typescript-eslint/parser',
|
|
11
|
-
parserOptions: {
|
|
12
|
-
ecmaVersion: 2018,
|
|
13
|
-
sourceType: 'module',
|
|
14
|
-
},
|
|
15
|
-
plugins: ['@typescript-eslint', 'prettier'],
|
|
16
|
-
extends: ['standard', 'prettier', 'plugin:prettier/recommended', 'plugin:@typescript-eslint/eslint-recommended'],
|
|
17
|
-
rules: {
|
|
18
|
-
'prettier/prettier': 'error',
|
|
19
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
20
|
-
'no-use-before-define': 'off',
|
|
21
|
-
'@typescript-eslint/no-use-before-define': ['error'],
|
|
22
|
-
},
|
|
23
|
-
};
|
package/nix/default.nix
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
{ ... }:
|
|
2
|
-
|
|
3
|
-
let
|
|
4
|
-
## Set the name:
|
|
5
|
-
name = "decaf-client-javascript-extras";
|
|
6
|
-
|
|
7
|
-
## Repository root:
|
|
8
|
-
root = ../.;
|
|
9
|
-
|
|
10
|
-
## Import sources:
|
|
11
|
-
sources = import ./sources.nix;
|
|
12
|
-
|
|
13
|
-
## Import telosnix:
|
|
14
|
-
telosnix = import sources.telosnix { };
|
|
15
|
-
|
|
16
|
-
## Import nixpkgs:
|
|
17
|
-
pkgs = import telosnix.pkgs-sources.stable { };
|
|
18
|
-
|
|
19
|
-
## Get the devshell:
|
|
20
|
-
devshell = telosnix.tools.devshell {
|
|
21
|
-
name = "${name}-devshell";
|
|
22
|
-
src = ./.;
|
|
23
|
-
quickstart = ../README.md;
|
|
24
|
-
guide = [
|
|
25
|
-
{ name = "readme"; title = "Introduction"; path = ../README.md; }
|
|
26
|
-
];
|
|
27
|
-
extensions = { };
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
## Declare dependencies for our shell:
|
|
31
|
-
deps = [
|
|
32
|
-
pkgs.git
|
|
33
|
-
pkgs.nodejs
|
|
34
|
-
|
|
35
|
-
devshell
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
## Define our shell:
|
|
39
|
-
shell = pkgs.mkShell {
|
|
40
|
-
buildInputs = deps;
|
|
41
|
-
|
|
42
|
-
shellHook = ''
|
|
43
|
-
## Greet:
|
|
44
|
-
devsh welcome
|
|
45
|
-
'';
|
|
46
|
-
|
|
47
|
-
DEVSHELL_ROOT = "${toString root}";
|
|
48
|
-
DECAF_JS_SKIP_POSTINSTALL = "1";
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
in
|
|
52
|
-
{
|
|
53
|
-
name = name;
|
|
54
|
-
pkgs = pkgs;
|
|
55
|
-
sources = sources;
|
|
56
|
-
telosnix = telosnix;
|
|
57
|
-
shell = shell;
|
|
58
|
-
}
|
package/nix/sources.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"telosnix": {
|
|
3
|
-
"branch": "v0.0.6",
|
|
4
|
-
"description": null,
|
|
5
|
-
"homepage": null,
|
|
6
|
-
"owner": "telostat",
|
|
7
|
-
"repo": "telos.nix",
|
|
8
|
-
"rev": "c0b76b80df8c8cc61383bee9fdcb81e45b53f919",
|
|
9
|
-
"sha256": "08kd5ivhm3hjkiw28cifmbjywbm7fsvzbwb7prsdnqmam6ij278i",
|
|
10
|
-
"type": "tarball",
|
|
11
|
-
"url": "https://github.com/telostat/telos.nix/archive/c0b76b80df8c8cc61383bee9fdcb81e45b53f919.tar.gz",
|
|
12
|
-
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
|
13
|
-
}
|
|
14
|
-
}
|
package/nix/sources.nix
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# This file has been generated by Niv.
|
|
2
|
-
|
|
3
|
-
let
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# The fetchers. fetch_<type> fetches specs of type <type>.
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
fetch_file = pkgs: name: spec:
|
|
10
|
-
let
|
|
11
|
-
name' = sanitizeName name + "-src";
|
|
12
|
-
in
|
|
13
|
-
if spec.builtin or true then
|
|
14
|
-
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
|
|
15
|
-
else
|
|
16
|
-
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
|
|
17
|
-
|
|
18
|
-
fetch_tarball = pkgs: name: spec:
|
|
19
|
-
let
|
|
20
|
-
name' = sanitizeName name + "-src";
|
|
21
|
-
in
|
|
22
|
-
if spec.builtin or true then
|
|
23
|
-
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
|
|
24
|
-
else
|
|
25
|
-
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
|
|
26
|
-
|
|
27
|
-
fetch_git = name: spec:
|
|
28
|
-
let
|
|
29
|
-
ref =
|
|
30
|
-
if spec ? ref then spec.ref else
|
|
31
|
-
if spec ? branch then "refs/heads/${spec.branch}" else
|
|
32
|
-
if spec ? tag then "refs/tags/${spec.tag}" else
|
|
33
|
-
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
|
|
34
|
-
submodules = if spec ? submodules then spec.submodules else false;
|
|
35
|
-
submoduleArg =
|
|
36
|
-
let
|
|
37
|
-
nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0;
|
|
38
|
-
emptyArgWithWarning =
|
|
39
|
-
if submodules == true
|
|
40
|
-
then
|
|
41
|
-
builtins.trace
|
|
42
|
-
(
|
|
43
|
-
"The niv input \"${name}\" uses submodules "
|
|
44
|
-
+ "but your nix's (${builtins.nixVersion}) builtins.fetchGit "
|
|
45
|
-
+ "does not support them"
|
|
46
|
-
)
|
|
47
|
-
{}
|
|
48
|
-
else {};
|
|
49
|
-
in
|
|
50
|
-
if nixSupportsSubmodules
|
|
51
|
-
then { inherit submodules; }
|
|
52
|
-
else emptyArgWithWarning;
|
|
53
|
-
in
|
|
54
|
-
builtins.fetchGit
|
|
55
|
-
({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg);
|
|
56
|
-
|
|
57
|
-
fetch_local = spec: spec.path;
|
|
58
|
-
|
|
59
|
-
fetch_builtin-tarball = name: throw
|
|
60
|
-
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
|
|
61
|
-
$ niv modify ${name} -a type=tarball -a builtin=true'';
|
|
62
|
-
|
|
63
|
-
fetch_builtin-url = name: throw
|
|
64
|
-
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
|
|
65
|
-
$ niv modify ${name} -a type=file -a builtin=true'';
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
# Various helpers
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
|
|
72
|
-
sanitizeName = name:
|
|
73
|
-
(
|
|
74
|
-
concatMapStrings (s: if builtins.isList s then "-" else s)
|
|
75
|
-
(
|
|
76
|
-
builtins.split "[^[:alnum:]+._?=-]+"
|
|
77
|
-
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
|
|
78
|
-
)
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
# The set of packages used when specs are fetched using non-builtins.
|
|
82
|
-
mkPkgs = sources: system:
|
|
83
|
-
let
|
|
84
|
-
sourcesNixpkgs =
|
|
85
|
-
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
|
|
86
|
-
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
|
|
87
|
-
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
|
|
88
|
-
in
|
|
89
|
-
if builtins.hasAttr "nixpkgs" sources
|
|
90
|
-
then sourcesNixpkgs
|
|
91
|
-
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
|
|
92
|
-
import <nixpkgs> {}
|
|
93
|
-
else
|
|
94
|
-
abort
|
|
95
|
-
''
|
|
96
|
-
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
|
|
97
|
-
add a package called "nixpkgs" to your sources.json.
|
|
98
|
-
'';
|
|
99
|
-
|
|
100
|
-
# The actual fetching function.
|
|
101
|
-
fetch = pkgs: name: spec:
|
|
102
|
-
|
|
103
|
-
if ! builtins.hasAttr "type" spec then
|
|
104
|
-
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
|
|
105
|
-
else if spec.type == "file" then fetch_file pkgs name spec
|
|
106
|
-
else if spec.type == "tarball" then fetch_tarball pkgs name spec
|
|
107
|
-
else if spec.type == "git" then fetch_git name spec
|
|
108
|
-
else if spec.type == "local" then fetch_local spec
|
|
109
|
-
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
|
|
110
|
-
else if spec.type == "builtin-url" then fetch_builtin-url name
|
|
111
|
-
else
|
|
112
|
-
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
|
|
113
|
-
|
|
114
|
-
# If the environment variable NIV_OVERRIDE_${name} is set, then use
|
|
115
|
-
# the path directly as opposed to the fetched source.
|
|
116
|
-
replace = name: drv:
|
|
117
|
-
let
|
|
118
|
-
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
|
|
119
|
-
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
|
|
120
|
-
in
|
|
121
|
-
if ersatz == "" then drv else
|
|
122
|
-
# this turns the string into an actual Nix path (for both absolute and
|
|
123
|
-
# relative paths)
|
|
124
|
-
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
|
|
125
|
-
|
|
126
|
-
# Ports of functions for older nix versions
|
|
127
|
-
|
|
128
|
-
# a Nix version of mapAttrs if the built-in doesn't exist
|
|
129
|
-
mapAttrs = builtins.mapAttrs or (
|
|
130
|
-
f: set: with builtins;
|
|
131
|
-
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
|
135
|
-
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
|
|
136
|
-
|
|
137
|
-
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
|
138
|
-
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
|
139
|
-
|
|
140
|
-
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
|
141
|
-
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
|
142
|
-
concatMapStrings = f: list: concatStrings (map f list);
|
|
143
|
-
concatStrings = builtins.concatStringsSep "";
|
|
144
|
-
|
|
145
|
-
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
|
|
146
|
-
optionalAttrs = cond: as: if cond then as else {};
|
|
147
|
-
|
|
148
|
-
# fetchTarball version that is compatible between all the versions of Nix
|
|
149
|
-
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
|
|
150
|
-
let
|
|
151
|
-
inherit (builtins) lessThan nixVersion fetchTarball;
|
|
152
|
-
in
|
|
153
|
-
if lessThan nixVersion "1.12" then
|
|
154
|
-
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
|
155
|
-
else
|
|
156
|
-
fetchTarball attrs;
|
|
157
|
-
|
|
158
|
-
# fetchurl version that is compatible between all the versions of Nix
|
|
159
|
-
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
|
|
160
|
-
let
|
|
161
|
-
inherit (builtins) lessThan nixVersion fetchurl;
|
|
162
|
-
in
|
|
163
|
-
if lessThan nixVersion "1.12" then
|
|
164
|
-
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
|
165
|
-
else
|
|
166
|
-
fetchurl attrs;
|
|
167
|
-
|
|
168
|
-
# Create the final "sources" from the config
|
|
169
|
-
mkSources = config:
|
|
170
|
-
mapAttrs (
|
|
171
|
-
name: spec:
|
|
172
|
-
if builtins.hasAttr "outPath" spec
|
|
173
|
-
then abort
|
|
174
|
-
"The values in sources.json should not have an 'outPath' attribute"
|
|
175
|
-
else
|
|
176
|
-
spec // { outPath = replace name (fetch config.pkgs name spec); }
|
|
177
|
-
) config.sources;
|
|
178
|
-
|
|
179
|
-
# The "config" used by the fetchers
|
|
180
|
-
mkConfig =
|
|
181
|
-
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
|
|
182
|
-
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
|
|
183
|
-
, system ? builtins.currentSystem
|
|
184
|
-
, pkgs ? mkPkgs sources system
|
|
185
|
-
}: rec {
|
|
186
|
-
# The sources, i.e. the attribute set of spec name to spec
|
|
187
|
-
inherit sources;
|
|
188
|
-
|
|
189
|
-
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
|
|
190
|
-
inherit pkgs;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
in
|
|
194
|
-
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
|