@decafhub/decaf-client-extras 0.0.5 → 0.1.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.
- package/.github/workflows/release-please.yml +6 -2
- package/.github/workflows/test.yml +6 -2
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +22 -0
- package/commons/-currency.d.ts +22 -6
- package/commons/-currency.js +12 -6
- package/commons/{-date-type.d.ts → -datetype.d.ts} +1 -1
- package/commons/{-date-type.js → -datetype.js} +2 -2
- package/commons/-id.d.ts +109 -17
- package/commons/-id.js +73 -0
- package/commons/index.d.ts +4 -1
- package/commons/index.js +17 -1
- package/es/commons/-currency.d.ts +22 -6
- package/es/commons/-currency.js +12 -6
- package/es/commons/{-date-type.d.ts → -datetype.d.ts} +1 -1
- package/es/commons/{-date-type.js → -datetype.js} +1 -1
- package/es/commons/-id.d.ts +109 -17
- package/es/commons/-id.js +70 -1
- package/es/commons/index.d.ts +4 -1
- package/es/commons/index.js +4 -1
- package/es/reports/valuation/-remote-valuation-report-portfolio.d.ts +15 -15
- package/es/reports/valuation/-remote-valuation-report-portfolio.js +32 -32
- package/es/reports/valuation/-remote-valuation-report-shared.d.ts +4 -4
- package/es/reports/valuation/-remote-valuation-report-shared.js +29 -26
- package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.js +1 -3
- package/es/reports/valuation/-valuation-report-portfolio.d.ts +14 -14
- package/es/reports/valuation/-valuation-report-shared.d.ts +6 -6
- package/nix/default.nix +59 -0
- package/nix/sources.json +14 -0
- package/nix/sources.nix +194 -0
- package/package.json +21 -21
- package/reports/valuation/-remote-valuation-report-portfolio.d.ts +15 -15
- package/reports/valuation/-remote-valuation-report-portfolio.js +31 -31
- package/reports/valuation/-remote-valuation-report-shared.d.ts +4 -4
- package/reports/valuation/-remote-valuation-report-shared.js +28 -25
- package/reports/valuation/-valuation-report-holdings-tree/-machinery.js +7 -9
- package/reports/valuation/-valuation-report-portfolio.d.ts +14 -14
- package/reports/valuation/-valuation-report-shared.d.ts +6 -6
- package/shell.nix +5 -20
- package/src/commons/-currency.test.ts +27 -0
- package/src/commons/-currency.ts +24 -9
- package/src/commons/-datetype.test.ts +10 -0
- package/src/commons/{-date-type.ts → -datetype.ts} +1 -1
- package/src/commons/-id.test.ts +27 -0
- package/src/commons/-id.ts +112 -17
- package/src/commons/index.ts +4 -1
- package/src/index.test.ts +5 -5
- package/src/reports/valuation/-remote-valuation-report-portfolio.ts +54 -54
- package/src/reports/valuation/-remote-valuation-report-shared.ts +34 -31
- package/src/reports/valuation/-valuation-report-holdings-tree/-machinery.ts +5 -7
- package/src/reports/valuation/-valuation-report-portfolio.ts +20 -20
- package/src/reports/valuation/-valuation-report-shared.ts +13 -6
|
@@ -22,7 +22,7 @@ function toArtifact(x) {
|
|
|
22
22
|
symbol: x.symbol,
|
|
23
23
|
name: (0, prelude_1.sanitizedNonEmptyText)(x.name),
|
|
24
24
|
ccy: prelude_1.Maybe.fromNullable(x.ccy),
|
|
25
|
-
quantity: (0, prelude_1.
|
|
25
|
+
quantity: (0, prelude_1.unsafeDecimal)(x.quantity),
|
|
26
26
|
country: (0, prelude_1.sanitizedNonEmptyText)(x.country),
|
|
27
27
|
issuer: (0, prelude_1.sanitizedNonEmptyText)(x.issuer),
|
|
28
28
|
sector: (0, prelude_1.sanitizedNonEmptyText)(x.sector),
|
|
@@ -38,14 +38,17 @@ exports.toArtifact = toArtifact;
|
|
|
38
38
|
function toAccrual(x) {
|
|
39
39
|
return {
|
|
40
40
|
name: x.name,
|
|
41
|
-
value: (0, prelude_1.
|
|
41
|
+
value: (0, prelude_1.unsafeDecimal)(x.value),
|
|
42
42
|
accounts: x.accounts.map(function (y) { return ({
|
|
43
43
|
account: y.account,
|
|
44
|
-
value: (0, prelude_1.
|
|
44
|
+
value: (0, prelude_1.unsafeDecimal)(y.value),
|
|
45
45
|
accruals: y.accruals.map(function (z) { return ({
|
|
46
46
|
artifact: toArtifact(z.artifact),
|
|
47
47
|
ccy: z.ccy,
|
|
48
|
-
value: {
|
|
48
|
+
value: {
|
|
49
|
+
org: (0, prelude_1.decimalFromNullable)(z.value.org).orDefault(prelude_1.zero),
|
|
50
|
+
ref: (0, prelude_1.decimalFromNullable)(z.value.ref).orDefault(prelude_1.zero),
|
|
51
|
+
},
|
|
49
52
|
}); }),
|
|
50
53
|
}); }),
|
|
51
54
|
};
|
|
@@ -53,22 +56,22 @@ function toAccrual(x) {
|
|
|
53
56
|
exports.toAccrual = toAccrual;
|
|
54
57
|
function toOrgRef(x) {
|
|
55
58
|
return {
|
|
56
|
-
org: (0, prelude_1.
|
|
57
|
-
ref: (0, prelude_1.
|
|
59
|
+
org: (0, prelude_1.decimalFromNullable)(x.org).orDefault(prelude_1.zero),
|
|
60
|
+
ref: (0, prelude_1.decimalFromNullable)(x.ref).orDefault(prelude_1.zero),
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
63
|
exports.toOrgRef = toOrgRef;
|
|
61
64
|
function toMaybeOrgRef(x) {
|
|
62
65
|
return prelude_1.Maybe.fromNullable(x).chain(function (_a) {
|
|
63
66
|
var org = _a.org, ref = _a.ref;
|
|
64
|
-
return (0, prelude_1.
|
|
67
|
+
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 }); }); });
|
|
65
68
|
});
|
|
66
69
|
}
|
|
67
70
|
exports.toMaybeOrgRef = toMaybeOrgRef;
|
|
68
71
|
function toBaseHolding(nav, x) {
|
|
69
72
|
return {
|
|
70
73
|
artifact: toArtifact(x.artifact),
|
|
71
|
-
quantity: (0, prelude_1.
|
|
74
|
+
quantity: (0, prelude_1.unsafeDecimal)(x.quantity),
|
|
72
75
|
investment: {
|
|
73
76
|
px: toOrgRef(x.investment.px),
|
|
74
77
|
txncosts: toMaybeOrgRef(x.investment.txncosts),
|
|
@@ -87,12 +90,12 @@ function toBaseHolding(nav, x) {
|
|
|
87
90
|
abs: toOrgRef(x.valuation.exposure.abs),
|
|
88
91
|
},
|
|
89
92
|
},
|
|
90
|
-
valuePercentage: (0, prelude_1.safeDiv)((0, prelude_1.
|
|
91
|
-
netExposurePercentage: (0, prelude_1.safeDiv)((0, prelude_1.
|
|
92
|
-
absExposurePercentage: (0, prelude_1.safeDiv)((0, prelude_1.
|
|
93
|
-
change: (0, prelude_1.
|
|
94
|
-
pnl: (0, prelude_1.
|
|
95
|
-
pnlToInvestment: (0, prelude_1.
|
|
93
|
+
valuePercentage: (0, prelude_1.safeDiv)((0, prelude_1.decimalFromNullable)(x.valuation.value.net.ref).orDefault(prelude_1.zero), nav),
|
|
94
|
+
netExposurePercentage: (0, prelude_1.safeDiv)((0, prelude_1.decimalFromNullable)(x.valuation.exposure.net.ref).orDefault(prelude_1.zero), nav),
|
|
95
|
+
absExposurePercentage: (0, prelude_1.safeDiv)((0, prelude_1.decimalFromNullable)(x.valuation.exposure.abs.ref).orDefault(prelude_1.zero), nav),
|
|
96
|
+
change: (0, prelude_1.decimalFromNullable)(x.change),
|
|
97
|
+
pnl: (0, prelude_1.decimalFromNullable)(x.pnl).orDefault(prelude_1.zero),
|
|
98
|
+
pnlToInvestment: (0, prelude_1.decimalFromNullable)(x.pnl_to_investment),
|
|
96
99
|
opendate: x.opendate,
|
|
97
100
|
lastdate: x.lastdate,
|
|
98
101
|
};
|
|
@@ -115,7 +118,7 @@ exports.toHolding = toHolding;
|
|
|
115
118
|
* report.
|
|
116
119
|
*/
|
|
117
120
|
function recompileBaseValuationReport(x) {
|
|
118
|
-
var nav = (0, prelude_1.
|
|
121
|
+
var nav = (0, prelude_1.decimalFromNullable)(x.nav).orDefault(prelude_1.zero);
|
|
119
122
|
var report = {
|
|
120
123
|
asof: x.reported,
|
|
121
124
|
date: x.asof,
|
|
@@ -124,20 +127,20 @@ function recompileBaseValuationReport(x) {
|
|
|
124
127
|
accounts: x.accounts,
|
|
125
128
|
holdings: x.holdings.map(function (rh) { return toHolding(nav, rh); }),
|
|
126
129
|
accruals: x.accruals.map(toAccrual),
|
|
127
|
-
fxRates: x.fxrates.map(function (r) { return ({ ccy1: r.ccy1, ccy2: r.ccy2, value: (0, prelude_1.
|
|
130
|
+
fxRates: x.fxrates.map(function (r) { return ({ ccy1: r.ccy1, ccy2: r.ccy2, value: (0, prelude_1.unsafeDecimal)(r.value), asof: r.asof }); }),
|
|
128
131
|
figures: {
|
|
129
|
-
investment: (0, prelude_1.
|
|
132
|
+
investment: (0, prelude_1.decimalFromNullable)(x.investment).orDefault(prelude_1.zero),
|
|
130
133
|
valuation: {
|
|
131
|
-
net: (0, prelude_1.
|
|
132
|
-
abs: (0, prelude_1.
|
|
134
|
+
net: (0, prelude_1.decimalFromNullable)(x.valuation_net).orDefault(prelude_1.zero),
|
|
135
|
+
abs: (0, prelude_1.decimalFromNullable)(x.valuation_abs).orDefault(prelude_1.zero),
|
|
133
136
|
},
|
|
134
|
-
accrued: (0, prelude_1.
|
|
135
|
-
liabilities: (0, prelude_1.
|
|
136
|
-
gav: (0, prelude_1.
|
|
137
|
+
accrued: (0, prelude_1.decimalFromNullable)(x.accrued).orDefault(prelude_1.zero),
|
|
138
|
+
liabilities: (0, prelude_1.decimalFromNullable)(x.liabilities).orDefault(prelude_1.zero),
|
|
139
|
+
gav: (0, prelude_1.decimalFromNullable)(x.gav).orDefault(prelude_1.zero),
|
|
137
140
|
nav: nav,
|
|
138
|
-
aum: (0, prelude_1.
|
|
139
|
-
pnl: (0, prelude_1.
|
|
140
|
-
pnlToInvestment: (0, prelude_1.
|
|
141
|
+
aum: (0, prelude_1.decimalFromNullable)(x.aum).orDefault(prelude_1.zero),
|
|
142
|
+
pnl: (0, prelude_1.decimalFromNullable)(x.pnl).orDefault(prelude_1.zero),
|
|
143
|
+
pnlToInvestment: (0, prelude_1.decimalFromNullable)(x.pnl_to_investment),
|
|
141
144
|
},
|
|
142
145
|
};
|
|
143
146
|
return (0, prelude_1.Right)(report);
|
|
@@ -38,13 +38,11 @@ var __values = (this && this.__values) || function(o) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.makeValuationReportHoldingsTree = exports.addValuationReportHoldingToTree = exports.makeValuationReportHoldingsTreeNode = exports.retreatTree = exports.resortChildren = exports.updateTotals = exports.makeValuationReportHoldingsTreeNodeValue = void 0;
|
|
40
40
|
var prelude_1 = require("@telostat/prelude");
|
|
41
|
-
var purify_ts_1 = require("purify-ts");
|
|
42
|
-
var List_1 = require("purify-ts/List");
|
|
43
41
|
var _utils_1 = require("./-utils");
|
|
44
42
|
function makeValuationReportHoldingsTreeNodeValue() {
|
|
45
43
|
return {
|
|
46
44
|
investment: prelude_1.zero,
|
|
47
|
-
accrued:
|
|
45
|
+
accrued: prelude_1.Nothing,
|
|
48
46
|
netValue: prelude_1.zero,
|
|
49
47
|
netValueRatio: prelude_1.zero,
|
|
50
48
|
absValue: prelude_1.zero,
|
|
@@ -73,10 +71,10 @@ function updateTotals(nav, investment, tree) {
|
|
|
73
71
|
var pnl = (0, prelude_1.sumDecimals)(holdings.map(function (x) { return x.pnl; })).add((0, prelude_1.sumDecimals)(children.map(function (x) { return x.totals.pnl; })));
|
|
74
72
|
var accruedsHoldings = holdings.map(function (x) { return x.investment.accrued.map(function (x) { return x.ref; }); });
|
|
75
73
|
var accruedsChildren = children.map(function (x) { return x.totals.accrued; });
|
|
76
|
-
var accrueds =
|
|
74
|
+
var accrueds = prelude_1.Maybe.catMaybes(__spreadArray(__spreadArray([], __read(accruedsHoldings), false), __read(accruedsChildren), false));
|
|
77
75
|
return {
|
|
78
76
|
investment: (0, prelude_1.sumDecimals)(holdings.map(function (x) { return x.investment.value.ref; })).add((0, prelude_1.sumDecimals)(children.map(function (x) { return x.totals.investment; }))),
|
|
79
|
-
accrued: accrueds.length === 0 ?
|
|
77
|
+
accrued: accrueds.length === 0 ? prelude_1.Nothing : (0, prelude_1.Just)((0, prelude_1.sumDecimals)(accrueds)),
|
|
80
78
|
netValue: netValue,
|
|
81
79
|
netValueRatio: (0, prelude_1.safeDiv)(netValue, nav).orDefault(prelude_1.zero),
|
|
82
80
|
absValue: absValue,
|
|
@@ -93,11 +91,11 @@ exports.updateTotals = updateTotals;
|
|
|
93
91
|
function resortChildren(node) {
|
|
94
92
|
return node.children.sort(function (t1, t2) {
|
|
95
93
|
// Get current address segments:
|
|
96
|
-
var segment1 =
|
|
97
|
-
var segment2 =
|
|
94
|
+
var segment1 = prelude_1.List.last(t1.address);
|
|
95
|
+
var segment2 = prelude_1.List.last(t2.address);
|
|
98
96
|
// Compare and return:
|
|
99
97
|
return segment1
|
|
100
|
-
.chain(function (s1) { return segment2.chain(function (s2) { return (0,
|
|
98
|
+
.chain(function (s1) { return segment2.chain(function (s2) { return (0, prelude_1.Just)((0, prelude_1.Tuple)(s1, s2)); }); })
|
|
101
99
|
.map(function (x) { return x.toArray(); })
|
|
102
100
|
.map(function (_a) {
|
|
103
101
|
var _b = __read(_a, 2), x = _b[0], y = _b[1];
|
|
@@ -118,7 +116,7 @@ function retreatTree(nav, investment, tree) {
|
|
|
118
116
|
exports.retreatTree = retreatTree;
|
|
119
117
|
function makeValuationReportHoldingsTreeNode(address) {
|
|
120
118
|
return {
|
|
121
|
-
name:
|
|
119
|
+
name: prelude_1.List.last(address)
|
|
122
120
|
.map(function (x) { return x.name; })
|
|
123
121
|
.orDefault(''),
|
|
124
122
|
address: address,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Decimal, Maybe, SDate, SDateTime } from '@telostat/prelude';
|
|
2
|
-
import {
|
|
2
|
+
import { DecafActionId, CurrencyCode, DecafExternalValuationId, DecafOhlcSeriesId, DecafPortfolioId, DecafPrincipalId, DecafShareClassFeeScheduleId, DecafShareClassId } from '../../commons';
|
|
3
3
|
import { BaseValuationReport, ValuationReportPortfolio } from './-valuation-report-shared';
|
|
4
4
|
export interface PortfolioValuationReport extends BaseValuationReport {
|
|
5
5
|
portfolio: ValuationReportPortfolio;
|
|
@@ -24,13 +24,13 @@ export interface PortfolioValuationReportShareClassValue {
|
|
|
24
24
|
ytdInt: Maybe<Decimal>;
|
|
25
25
|
}
|
|
26
26
|
export interface PortfolioValuationReportShareClass {
|
|
27
|
-
id:
|
|
27
|
+
id: DecafShareClassId;
|
|
28
28
|
created: SDateTime;
|
|
29
|
-
creator: Maybe<
|
|
29
|
+
creator: Maybe<DecafPrincipalId>;
|
|
30
30
|
updated: SDateTime;
|
|
31
|
-
updater: Maybe<
|
|
31
|
+
updater: Maybe<DecafPrincipalId>;
|
|
32
32
|
guid: string;
|
|
33
|
-
portfolio:
|
|
33
|
+
portfolio: DecafPortfolioId;
|
|
34
34
|
name: string;
|
|
35
35
|
currency: CurrencyCode;
|
|
36
36
|
isin: Maybe<string>;
|
|
@@ -42,22 +42,22 @@ export interface PortfolioValuationReportShareClass {
|
|
|
42
42
|
subscriptionRedemptionPeriod: Maybe<string>;
|
|
43
43
|
managementFeeFrequency: Maybe<number>;
|
|
44
44
|
performanceFeeFrequency: Maybe<number>;
|
|
45
|
-
benchmark: Maybe<
|
|
45
|
+
benchmark: Maybe<DecafOhlcSeriesId>;
|
|
46
46
|
description: Maybe<string>;
|
|
47
|
-
feeScheduleIds:
|
|
48
|
-
effectiveFeeScheduleId: Maybe<
|
|
49
|
-
subscriptionIds:
|
|
47
|
+
feeScheduleIds: DecafShareClassFeeScheduleId[];
|
|
48
|
+
effectiveFeeScheduleId: Maybe<DecafShareClassFeeScheduleId>;
|
|
49
|
+
subscriptionIds: DecafActionId[];
|
|
50
50
|
outstanding: Maybe<Decimal>;
|
|
51
51
|
}
|
|
52
52
|
export interface PortfolioValuationReportExternalValue {
|
|
53
|
-
id:
|
|
53
|
+
id: DecafExternalValuationId;
|
|
54
54
|
created: SDateTime;
|
|
55
|
-
creator: Maybe<
|
|
55
|
+
creator: Maybe<DecafPrincipalId>;
|
|
56
56
|
updated: SDateTime;
|
|
57
|
-
updater: Maybe<
|
|
57
|
+
updater: Maybe<DecafPrincipalId>;
|
|
58
58
|
guid: string;
|
|
59
|
-
portfolio:
|
|
60
|
-
shareclass: Maybe<
|
|
59
|
+
portfolio: DecafPortfolioId;
|
|
60
|
+
shareclass: Maybe<DecafShareClassId>;
|
|
61
61
|
date: SDate;
|
|
62
62
|
ccy: CurrencyCode;
|
|
63
63
|
shares: Maybe<Decimal>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Decimal, Maybe, SDate, SDateTime } from '@telostat/prelude';
|
|
2
|
-
import {
|
|
2
|
+
import { CurrencyCode, DateType, DecafAccountId, DecafArtifactId, DecafArtifactTypeId, DecafPortfolioId } from '../../commons';
|
|
3
3
|
/**
|
|
4
4
|
* Type definition for base valuation report.
|
|
5
5
|
*/
|
|
@@ -31,7 +31,7 @@ export interface BaseValuationReport {
|
|
|
31
31
|
* Type definition for account reference in valuation reports.
|
|
32
32
|
*/
|
|
33
33
|
export interface ValuationReportAccount {
|
|
34
|
-
id:
|
|
34
|
+
id: DecafAccountId;
|
|
35
35
|
guid: string;
|
|
36
36
|
name: string;
|
|
37
37
|
}
|
|
@@ -39,7 +39,7 @@ export interface ValuationReportAccount {
|
|
|
39
39
|
* Type definition for portfolio reference in valuation reports.
|
|
40
40
|
*/
|
|
41
41
|
export interface ValuationReportPortfolio {
|
|
42
|
-
id:
|
|
42
|
+
id: DecafPortfolioId;
|
|
43
43
|
guid: string;
|
|
44
44
|
name: string;
|
|
45
45
|
}
|
|
@@ -155,7 +155,7 @@ export interface ValuationReportAccrualByCurrency {
|
|
|
155
155
|
* Type definition of the FINREA artifact type.
|
|
156
156
|
*/
|
|
157
157
|
export interface ValuationReportArtifactType {
|
|
158
|
-
id:
|
|
158
|
+
id: DecafArtifactTypeId;
|
|
159
159
|
name: string;
|
|
160
160
|
order: number;
|
|
161
161
|
}
|
|
@@ -163,7 +163,7 @@ export interface ValuationReportArtifactType {
|
|
|
163
163
|
* Type definition for the artifact as reported in the valuation.
|
|
164
164
|
*/
|
|
165
165
|
export interface ValuationReportArtifact {
|
|
166
|
-
id:
|
|
166
|
+
id: DecafArtifactId;
|
|
167
167
|
guid: string;
|
|
168
168
|
type: ValuationReportArtifactType;
|
|
169
169
|
stype: Maybe<string>;
|
|
@@ -179,7 +179,7 @@ export interface ValuationReportArtifact {
|
|
|
179
179
|
isin: Maybe<string>;
|
|
180
180
|
figi: Maybe<string>;
|
|
181
181
|
expiry: Maybe<SDate>;
|
|
182
|
-
underlyingId: Maybe<
|
|
182
|
+
underlyingId: Maybe<DecafArtifactId>;
|
|
183
183
|
}
|
|
184
184
|
export interface ValuationReportFxRate {
|
|
185
185
|
ccy1: CurrencyCode;
|
package/shell.nix
CHANGED
|
@@ -1,21 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
{ ... }:
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
git
|
|
8
|
-
nodejs-16_x
|
|
9
|
-
yarn
|
|
10
|
-
|
|
11
|
-
figlet
|
|
12
|
-
lolcat
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
shellHook = ''
|
|
16
|
-
## Greet:
|
|
17
|
-
figlet -w 999 -f standard "DECAF CLIENT EXTRAS DEV SHELL" | lolcat -S 179
|
|
18
|
-
'';
|
|
19
|
-
|
|
20
|
-
DECAF_JS_SKIP_POSTINSTALL = "TRUE";
|
|
21
|
-
}
|
|
3
|
+
let
|
|
4
|
+
nix = import ./nix { };
|
|
5
|
+
in
|
|
6
|
+
nix.shell
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Just, Nothing } from '@telostat/prelude';
|
|
2
|
+
import { CurrencyCode, mkCurrencyCode, mkCurrencyCodeError, unCurrencyCode } from './-currency';
|
|
3
|
+
|
|
4
|
+
describe('currency code tests', () => {
|
|
5
|
+
const inputInvalid = ['', ' ', '\n', '\r', '\t', ' \n\r\t ', ' USD', 'USD ', ' USD ', 'U SD'];
|
|
6
|
+
const inputValid = ['U', 'US', 'USD', 'USd'];
|
|
7
|
+
|
|
8
|
+
test('invalid strings are rejected by the smart constructor', () => {
|
|
9
|
+
inputInvalid.forEach((x) => expect(mkCurrencyCode(x)).toBe(Nothing));
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('invalid strings throw errors by the unsafe constructor', () => {
|
|
13
|
+
inputInvalid.forEach((x) => expect(() => mkCurrencyCodeError(x)).toThrow(/^Invalid currency code: /));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('valid strings are accepted by the smart constructor', () => {
|
|
17
|
+
inputValid.forEach((x) => expect(mkCurrencyCode(x)).toStrictEqual(Just(x as CurrencyCode)));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('valid strings are accepted by the unsafe constructor', () => {
|
|
21
|
+
inputValid.forEach((x) => expect(mkCurrencyCodeError(x)).toStrictEqual(x as CurrencyCode));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('currency codes can be converted back to string', () => {
|
|
25
|
+
inputValid.forEach((x) => expect(unCurrencyCode(mkCurrencyCodeError(x))).toStrictEqual(x));
|
|
26
|
+
});
|
|
27
|
+
});
|
package/src/commons/-currency.ts
CHANGED
|
@@ -4,27 +4,40 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Just, Maybe,
|
|
7
|
+
import { Just, Maybe, Nothing } from '@telostat/prelude';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Type
|
|
10
|
+
* Type definition for currency code values.
|
|
11
11
|
*
|
|
12
|
-
* A currency code is (typically) defined as all-uppercase, three
|
|
12
|
+
* A currency code is (typically) defined as all-uppercase, three-letter
|
|
13
|
+
* `string`. In this library, we are particularly using the regular expression
|
|
14
|
+
* {@link REGEXP_CURRENCY_CODE} which allows any uppercase letter followed by
|
|
15
|
+
* uppercase or lowercase letters.
|
|
16
|
+
*
|
|
17
|
+
* As for the type definition: We are using a (not-so-elegant) trick called
|
|
18
|
+
* "tagged-type" to annotate the plain-vanilla `string` type to be the
|
|
19
|
+
* `CurrencyCode` (_poor man's newtype_). Note that during the runtime, all
|
|
20
|
+
* `CurrencyCode` values are simply a `string` values.
|
|
13
21
|
*/
|
|
14
|
-
export type CurrencyCode =
|
|
22
|
+
export type CurrencyCode = string & { readonly __tag: unique symbol };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Regular expression for currency codes in our concept.
|
|
26
|
+
*/
|
|
27
|
+
export const REGEXP_CURRENCY_CODE = /^[A-Z][a-zA-Z]*$/;
|
|
15
28
|
|
|
16
29
|
/**
|
|
17
30
|
* Attempts to create a {@link CurrencyCode} value with the given currency code.
|
|
18
31
|
*
|
|
19
|
-
* This function returns a `Maybe` value. For the
|
|
20
|
-
* error, see {@link mkCurrencyCodeError}.
|
|
32
|
+
* This function returns a `Maybe` value. For the
|
|
33
|
+
* version that throws an error, see {@link mkCurrencyCodeError}.
|
|
21
34
|
*
|
|
22
35
|
* @param x A currency code represented as string.
|
|
23
36
|
* @returns If the argument has leading or trailing spaces OR it is empty,
|
|
24
37
|
* `Nothing` is retured, `Just` {@link CurrencyCode} otherwise.
|
|
25
38
|
*/
|
|
26
39
|
export function mkCurrencyCode(x: string): Maybe<CurrencyCode> {
|
|
27
|
-
return
|
|
40
|
+
return REGEXP_CURRENCY_CODE.test(x) ? Just(x as CurrencyCode) : Nothing;
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
/**
|
|
@@ -40,16 +53,18 @@ export function mkCurrencyCode(x: string): Maybe<CurrencyCode> {
|
|
|
40
53
|
*/
|
|
41
54
|
export function mkCurrencyCodeError(x: string): CurrencyCode {
|
|
42
55
|
return mkCurrencyCode(x).orDefaultLazy(() => {
|
|
43
|
-
throw new Error(`Invalid currency code:
|
|
56
|
+
throw new Error(`Invalid currency code: ${x}`);
|
|
44
57
|
});
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
/**
|
|
48
61
|
* Return the currency code as a string value.
|
|
49
62
|
*
|
|
63
|
+
* In runtime, this is effectively the identity function.
|
|
64
|
+
*
|
|
50
65
|
* @param x {@link CurrencyCode} to be extracted string from.
|
|
51
66
|
* @returns Currency code as a string.
|
|
52
67
|
*/
|
|
53
68
|
export function unCurrencyCode(x: CurrencyCode): string {
|
|
54
|
-
return
|
|
69
|
+
return x as string;
|
|
55
70
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DATE_TYPES } from './-datetype';
|
|
2
|
+
|
|
3
|
+
describe('date-type tests', () => {
|
|
4
|
+
test('we maintain the catalogue of date-type tests', () => {
|
|
5
|
+
expect(DATE_TYPES).toStrictEqual([
|
|
6
|
+
{ label: 'Trade Date', value: 'commitment' },
|
|
7
|
+
{ label: 'Value Date', value: 'settlement' },
|
|
8
|
+
]);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -6,7 +6,7 @@ export type DateType = 'commitment' | 'settlement';
|
|
|
6
6
|
/**
|
|
7
7
|
* Translation table for DECAF FINREA action date types.
|
|
8
8
|
*/
|
|
9
|
-
export const
|
|
9
|
+
export const DATE_TYPES: { label: string; value: DateType }[] = [
|
|
10
10
|
{ label: 'Trade Date', value: 'commitment' },
|
|
11
11
|
{ label: 'Value Date', value: 'settlement' },
|
|
12
12
|
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { DecafActionId, DecafArtifactId, DecafArtifactTypeId, mkDecafRecordId, unDecafRecordId } from './-id';
|
|
2
|
+
|
|
3
|
+
describe('DECAF record identifier tests', () => {
|
|
4
|
+
test('types are aligned and inferred correctly', () => {
|
|
5
|
+
const exampleDecafArtifactId: DecafArtifactId = mkDecafRecordId(42);
|
|
6
|
+
const exampleDecafArtifactIdValue: number = unDecafRecordId(exampleDecafArtifactId);
|
|
7
|
+
expect(exampleDecafArtifactIdValue).toBe(42);
|
|
8
|
+
|
|
9
|
+
const exampleDecafActionId: DecafActionId = mkDecafRecordId(42);
|
|
10
|
+
const exampleDecafActionIdValue: number = unDecafRecordId(exampleDecafActionId);
|
|
11
|
+
expect(exampleDecafActionIdValue).toBe(42);
|
|
12
|
+
|
|
13
|
+
const exampleDecafArtifactTypeId: DecafArtifactTypeId = mkDecafRecordId('CCY');
|
|
14
|
+
const exampleDecafArtifactTypeIdValue: string = unDecafRecordId(exampleDecafArtifactTypeId);
|
|
15
|
+
expect(exampleDecafArtifactTypeIdValue).toBe('CCY');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('type erasure works as expected', () => {
|
|
19
|
+
interface DecafArtifact {
|
|
20
|
+
id: DecafArtifactId;
|
|
21
|
+
type: DecafArtifactTypeId;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const exampleDecafArtifact: DecafArtifact = { id: mkDecafRecordId(10), type: mkDecafRecordId('CCY') };
|
|
25
|
+
expect(exampleDecafArtifact).toStrictEqual({ id: 10, type: 'CCY' });
|
|
26
|
+
});
|
|
27
|
+
});
|
package/src/commons/-id.ts
CHANGED
|
@@ -1,72 +1,167 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* This module provides a collection of DECAF record identifier type
|
|
3
|
+
* definitions. It is not exhaustive and it will be improved on an ongoing
|
|
4
|
+
* basis.
|
|
5
|
+
*
|
|
6
|
+
* Typically, a DECAF record identifier is either number or string. Some DECAF
|
|
7
|
+
* API endoints can consume string values even though a number is expected. We
|
|
8
|
+
* are sticking here to the original type: No `number | string` definitions.
|
|
9
|
+
*
|
|
10
|
+
* Methodologically, we are using a type trick to emulate newtypes in this
|
|
11
|
+
* module: For example, DECAF artifact identifier type is defined as:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* export type DecafArtifactId = number & { readonly __tag: unique symbol };
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* In runtime, there is only a number. The `& { readonly __tag: unique symbol }`
|
|
18
|
+
* is provided to the compiler to distinguish in between `number` identifier
|
|
19
|
+
* values which are representing different DECAF record types.
|
|
20
|
+
*
|
|
21
|
+
* The construction and deconstruction of DECAF record identifiers are done via,
|
|
22
|
+
* respecively, `mkDecafRecordId` and `unDecafRecordId`:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* const exampleDecafArtifactIdValue: number = unDecafRecordId(exampleDecafArtifactId);
|
|
26
|
+
* const exampleDecafArtifactId: DecafArtifactId = mkDecafRecordId(42);
|
|
27
|
+
* expect(exampleDecafArtifactIdValue).toBe(42);
|
|
28
|
+
*
|
|
29
|
+
* const exampleDecafActionId: DecafActionId = mkDecafRecordId(42);
|
|
30
|
+
* const exampleDecafActionIdValue: number = unDecafRecordId(exampleDecafActionId);
|
|
31
|
+
* expect(exampleDecafActionIdValue).toBe(42);
|
|
32
|
+
*
|
|
33
|
+
* const exampleDecafArtifactTypeId: DecafArtifactTypeId = mkDecafRecordId('CCY');
|
|
34
|
+
* const exampleDecafArtifactTypeIdValue: string = unDecafRecordId(exampleDecafArtifactTypeId);
|
|
35
|
+
* expect(exampleDecafArtifactTypeIdValue).toBe('CCY');
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* To re-iterate, the runtime representation is not affected by how DECAF record
|
|
39
|
+
* identifier types are defined:
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* interface DecafArtifact {
|
|
43
|
+
* id: DecafArtifactId;
|
|
44
|
+
* type: DecafArtifactTypeId;
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* const exampleDecafArtifact: DecafArtifact = { id: mkDecafRecordId(10), type: mkDecafRecordId('CCY') };
|
|
48
|
+
* expect(exampleDecafArtifact).toStrictEqual({ id: 10, type: 'CCY' });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @module
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Type definition covering all possible DECAF record identifiers based on
|
|
56
|
+
* `number` values.
|
|
57
|
+
*
|
|
58
|
+
* This type definition must be extended whenever there is a new DECAF record
|
|
59
|
+
* identifier is defined in this module.
|
|
60
|
+
*/
|
|
61
|
+
export type _DecafRecordIdFromNumber = DecafArtifactId | DecafActionId;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Type definition covering all possible DECAF record identifiers based on
|
|
65
|
+
* `string` values.
|
|
66
|
+
*
|
|
67
|
+
* This type definition must be extended whenever there is a new DECAF record
|
|
68
|
+
* identifier is defined in this module.
|
|
69
|
+
*/
|
|
70
|
+
export type _DecafRecordIdFromString = DecafArtifactTypeId;
|
|
71
|
+
|
|
72
|
+
/* Signature for overloaded `mkDecafRecordId` function consuming a `number`. */
|
|
73
|
+
export function mkDecafRecordId<T extends _DecafRecordIdFromNumber>(x: number): T;
|
|
74
|
+
|
|
75
|
+
/* Signature for overloaded `mkDecafRecordId` function consuming a `string`. */
|
|
76
|
+
export function mkDecafRecordId<T extends _DecafRecordIdFromString>(x: string): T;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Constructor for DECAF record identifiers.
|
|
80
|
+
*
|
|
81
|
+
* @param x Value to create DECAF record identifier from.
|
|
82
|
+
* @returns DECAF record identifier of type deduced from call-site usage.
|
|
83
|
+
*/
|
|
84
|
+
export function mkDecafRecordId<T>(x: any): T {
|
|
85
|
+
return x as T;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Signature for overloaded `unDecafRecordId` function producing a `number`. */
|
|
89
|
+
export function unDecafRecordId<T extends _DecafRecordIdFromNumber>(x: T): number;
|
|
90
|
+
|
|
91
|
+
/* Signature for overloaded `unDecafRecordId` function producing a `string`. */
|
|
92
|
+
export function unDecafRecordId<K extends _DecafRecordIdFromString>(x: K): string;
|
|
2
93
|
|
|
3
94
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
95
|
+
* Deconstructor for DECAF record identifiers.
|
|
96
|
+
*
|
|
97
|
+
* @param x DECAF record identifier.
|
|
98
|
+
* @returns Value of the DECAF record identifier (deduced from call-site usage).
|
|
6
99
|
*/
|
|
7
|
-
export
|
|
100
|
+
export function unDecafRecordId<T>(x: T): any {
|
|
101
|
+
return x as unknown;
|
|
102
|
+
}
|
|
8
103
|
|
|
9
104
|
/**
|
|
10
105
|
* Type definition for DECAF artifact identifiers.
|
|
11
106
|
*/
|
|
12
|
-
export type
|
|
107
|
+
export type DecafArtifactId = number & { readonly __tag: unique symbol };
|
|
13
108
|
|
|
14
109
|
/**
|
|
15
110
|
* Type definition for DECAF artifact type identifiers.
|
|
16
111
|
*/
|
|
17
|
-
export type
|
|
112
|
+
export type DecafArtifactTypeId = string & { readonly __tag: unique symbol };
|
|
18
113
|
|
|
19
114
|
/**
|
|
20
115
|
* Type definition for DECAF share class identifiers.
|
|
21
116
|
*/
|
|
22
|
-
export type
|
|
117
|
+
export type DecafShareClassId = number & { readonly __tag: unique symbol };
|
|
23
118
|
|
|
24
119
|
/**
|
|
25
120
|
* Type definition for DECAF principal identifiers.
|
|
26
121
|
*/
|
|
27
|
-
export type
|
|
122
|
+
export type DecafPrincipalId = number & { readonly __tag: unique symbol };
|
|
28
123
|
|
|
29
124
|
/**
|
|
30
125
|
* Type definition for DECAF institution identifiers.
|
|
31
126
|
*/
|
|
32
|
-
export type
|
|
127
|
+
export type DecafInstitutionId = number & { readonly __tag: unique symbol };
|
|
33
128
|
|
|
34
129
|
/**
|
|
35
130
|
* Type definition for DECAF team identifiers.
|
|
36
131
|
*/
|
|
37
|
-
export type
|
|
132
|
+
export type DecafTeamId = number & { readonly __tag: unique symbol };
|
|
38
133
|
|
|
39
134
|
/**
|
|
40
135
|
* Type definition for DECAF portfolio identifiers.
|
|
41
136
|
*/
|
|
42
|
-
export type
|
|
137
|
+
export type DecafPortfolioId = number & { readonly __tag: unique symbol };
|
|
43
138
|
|
|
44
139
|
/**
|
|
45
140
|
* Type definition for DECAF portfolio group identifiers.
|
|
46
141
|
*/
|
|
47
|
-
export type
|
|
142
|
+
export type DecafPortfolioGroupId = number & { readonly __tag: unique symbol };
|
|
48
143
|
|
|
49
144
|
/**
|
|
50
145
|
* Type definition for DECAF account identifiers.
|
|
51
146
|
*/
|
|
52
|
-
export type
|
|
147
|
+
export type DecafAccountId = number & { readonly __tag: unique symbol };
|
|
53
148
|
|
|
54
149
|
/**
|
|
55
150
|
* Type definition for DECAF OHLC series identifiers.
|
|
56
151
|
*/
|
|
57
|
-
export type
|
|
152
|
+
export type DecafOhlcSeriesId = number & { readonly __tag: unique symbol };
|
|
58
153
|
|
|
59
154
|
/**
|
|
60
155
|
* Type definition for DECAF share class fee schedule identifiers.
|
|
61
156
|
*/
|
|
62
|
-
export type
|
|
157
|
+
export type DecafShareClassFeeScheduleId = number & { readonly __tag: unique symbol };
|
|
63
158
|
|
|
64
159
|
/**
|
|
65
160
|
* Type definition for DECAF action identifiers.
|
|
66
161
|
*/
|
|
67
|
-
export type
|
|
162
|
+
export type DecafActionId = number & { readonly __tag: unique symbol };
|
|
68
163
|
|
|
69
164
|
/**
|
|
70
165
|
* Type definition for DECAF external valuation identifiers.
|
|
71
166
|
*/
|
|
72
|
-
export type
|
|
167
|
+
export type DecafExternalValuationId = number & { readonly __tag: unique symbol };
|
package/src/commons/index.ts
CHANGED