@decafhub/decaf-client-extras 0.0.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/.editorconfig +9 -0
- package/.env.example +4 -0
- package/.eslintignore +3 -0
- package/.eslintrc.js +23 -0
- package/.github/workflows/release-please.yml +47 -0
- package/.github/workflows/test.yml +29 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +4 -0
- package/.release-please-manifest.json +3 -0
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +10 -0
- package/commons/-currency.d.ts +42 -0
- package/commons/-currency.js +50 -0
- package/commons/-date-type.d.ts +11 -0
- package/commons/-date-type.js +10 -0
- package/commons/-id.d.ts +58 -0
- package/commons/-id.js +2 -0
- package/commons/index.d.ts +3 -0
- package/commons/index.js +19 -0
- package/es/commons/-currency.d.ts +42 -0
- package/es/commons/-currency.js +44 -0
- package/es/commons/-date-type.d.ts +11 -0
- package/es/commons/-date-type.js +7 -0
- package/es/commons/-id.d.ts +58 -0
- package/es/commons/-id.js +1 -0
- package/es/commons/index.d.ts +3 -0
- package/es/commons/index.js +3 -0
- package/es/index.d.ts +3 -0
- package/es/index.js +3 -0
- package/es/reports/index.d.ts +1 -0
- package/es/reports/index.js +1 -0
- package/es/reports/valuation/-remote-valuation-report-consolidated.d.ts +69 -0
- package/es/reports/valuation/-remote-valuation-report-consolidated.js +56 -0
- package/es/reports/valuation/-remote-valuation-report-portfolio.d.ts +150 -0
- package/es/reports/valuation/-remote-valuation-report-portfolio.js +134 -0
- package/es/reports/valuation/-remote-valuation-report-shared.d.ts +233 -0
- package/es/reports/valuation/-remote-valuation-report-shared.js +127 -0
- package/es/reports/valuation/-valuation-report-consolidated.d.ts +35 -0
- package/es/reports/valuation/-valuation-report-consolidated.js +1 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.d.ts +10 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-machinery.js +116 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-types.d.ts +23 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-types.js +1 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-utils.d.ts +1 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/-utils.js +12 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/index.d.ts +2 -0
- package/es/reports/valuation/-valuation-report-holdings-tree/index.js +2 -0
- package/es/reports/valuation/-valuation-report-portfolio.d.ts +79 -0
- package/es/reports/valuation/-valuation-report-portfolio.js +1 -0
- package/es/reports/valuation/-valuation-report-shared.d.ts +189 -0
- package/es/reports/valuation/-valuation-report-shared.js +6 -0
- package/es/reports/valuation/index.d.ts +8 -0
- package/es/reports/valuation/index.js +6 -0
- package/index.d.ts +3 -0
- package/index.js +32 -0
- package/jest.config.js +6 -0
- package/package.json +79 -0
- package/postinstall.sh +16 -0
- package/release-please-config.json +9 -0
- package/reports/index.d.ts +1 -0
- package/reports/index.js +27 -0
- package/reports/valuation/-remote-valuation-report-consolidated.d.ts +69 -0
- package/reports/valuation/-remote-valuation-report-consolidated.js +113 -0
- package/reports/valuation/-remote-valuation-report-portfolio.d.ts +150 -0
- package/reports/valuation/-remote-valuation-report-portfolio.js +191 -0
- package/reports/valuation/-remote-valuation-report-shared.d.ts +233 -0
- package/reports/valuation/-remote-valuation-report-shared.js +145 -0
- package/reports/valuation/-valuation-report-consolidated.d.ts +35 -0
- package/reports/valuation/-valuation-report-consolidated.js +2 -0
- package/reports/valuation/-valuation-report-holdings-tree/-machinery.d.ts +10 -0
- package/reports/valuation/-valuation-report-holdings-tree/-machinery.js +189 -0
- package/reports/valuation/-valuation-report-holdings-tree/-types.d.ts +23 -0
- package/reports/valuation/-valuation-report-holdings-tree/-types.js +2 -0
- package/reports/valuation/-valuation-report-holdings-tree/-utils.d.ts +1 -0
- package/reports/valuation/-valuation-report-holdings-tree/-utils.js +16 -0
- package/reports/valuation/-valuation-report-holdings-tree/index.d.ts +2 -0
- package/reports/valuation/-valuation-report-holdings-tree/index.js +20 -0
- package/reports/valuation/-valuation-report-portfolio.d.ts +79 -0
- package/reports/valuation/-valuation-report-portfolio.js +2 -0
- package/reports/valuation/-valuation-report-shared.d.ts +189 -0
- package/reports/valuation/-valuation-report-shared.js +11 -0
- package/reports/valuation/index.d.ts +8 -0
- package/reports/valuation/index.js +25 -0
- package/shell.nix +21 -0
- package/src/commons/-currency.ts +55 -0
- package/src/commons/-date-type.ts +12 -0
- package/src/commons/-id.ts +72 -0
- package/src/commons/index.ts +3 -0
- package/src/index.test.ts +67 -0
- package/src/index.ts +3 -0
- package/src/reports/index.ts +1 -0
- package/src/reports/valuation/-remote-valuation-report-consolidated.ts +121 -0
- package/src/reports/valuation/-remote-valuation-report-portfolio.ts +294 -0
- package/src/reports/valuation/-remote-valuation-report-shared.ts +313 -0
- package/src/reports/valuation/-valuation-report-consolidated.ts +46 -0
- package/src/reports/valuation/-valuation-report-holdings-tree/-machinery.ts +171 -0
- package/src/reports/valuation/-valuation-report-holdings-tree/-types.ts +25 -0
- package/src/reports/valuation/-valuation-report-holdings-tree/-utils.ts +15 -0
- package/src/reports/valuation/-valuation-report-holdings-tree/index.ts +2 -0
- package/src/reports/valuation/-valuation-report-portfolio.ts +92 -0
- package/src/reports/valuation/-valuation-report-shared.ts +217 -0
- package/src/reports/valuation/index.ts +8 -0
- package/tsconfig.es.json +13 -0
- package/tsconfig.json +36 -0
- package/typedoc.json +8 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asDecimal,
|
|
3
|
+
CustomError,
|
|
4
|
+
Decimal,
|
|
5
|
+
Either,
|
|
6
|
+
Just,
|
|
7
|
+
Maybe,
|
|
8
|
+
maybeDecimal,
|
|
9
|
+
Right,
|
|
10
|
+
safeDiv,
|
|
11
|
+
sanitizedNonEmptyText,
|
|
12
|
+
SDate,
|
|
13
|
+
SDateTime,
|
|
14
|
+
zero,
|
|
15
|
+
} from '@telostat/prelude';
|
|
16
|
+
import { ArtifactId, ArtifactTypeId, CurrencyCode, DateType } from '../../commons';
|
|
17
|
+
import {
|
|
18
|
+
BaseValuationReport,
|
|
19
|
+
BaseValuationReportHolding,
|
|
20
|
+
ValuationReportAccount,
|
|
21
|
+
ValuationReportAccounts,
|
|
22
|
+
ValuationReportAccrual,
|
|
23
|
+
ValuationReportArtifact,
|
|
24
|
+
ValuationReportFigureOrgRef,
|
|
25
|
+
ValuationReportHolding,
|
|
26
|
+
} from './-valuation-report-shared';
|
|
27
|
+
|
|
28
|
+
export interface RemoteBaseValuationReport {
|
|
29
|
+
reported: SDateTime;
|
|
30
|
+
asof: SDate;
|
|
31
|
+
type: DateType;
|
|
32
|
+
ccy: CurrencyCode;
|
|
33
|
+
accounts: ValuationReportAccounts;
|
|
34
|
+
holdings: RemoteValuationReportHolding[];
|
|
35
|
+
accruals: RemoteValuationReportAccrual[];
|
|
36
|
+
investment?: number;
|
|
37
|
+
valuation_net?: number;
|
|
38
|
+
valuation_abs?: number;
|
|
39
|
+
accrued?: number;
|
|
40
|
+
liabilities?: number;
|
|
41
|
+
gav?: number;
|
|
42
|
+
nav?: number;
|
|
43
|
+
aum?: number;
|
|
44
|
+
pnl?: number;
|
|
45
|
+
pnl_to_investment?: number;
|
|
46
|
+
fxrates: RemoteValuationReportFxRate[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface RemoteValuationReportFxRate {
|
|
50
|
+
ccy1: CurrencyCode;
|
|
51
|
+
ccy2: CurrencyCode;
|
|
52
|
+
value: number; // TODO: Check when no such rate is defined.
|
|
53
|
+
asof: SDate;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Valuation holding.
|
|
58
|
+
*/
|
|
59
|
+
export interface RemoteValuationReportHolding {
|
|
60
|
+
artifact: RemoteValuationReportArtifact;
|
|
61
|
+
tags: { classification: { name: string; order?: string | number }[] };
|
|
62
|
+
quantity: number;
|
|
63
|
+
accounts: ValuationReportAccount[];
|
|
64
|
+
investment: {
|
|
65
|
+
px: { org?: number; ref?: number };
|
|
66
|
+
txncosts: { org?: number; ref?: number };
|
|
67
|
+
accrued: { org?: number; ref?: number };
|
|
68
|
+
value: { org?: number; ref?: number };
|
|
69
|
+
};
|
|
70
|
+
valuation: {
|
|
71
|
+
px: { org?: number; ref?: number };
|
|
72
|
+
accrued: { org?: number; ref?: number };
|
|
73
|
+
value: {
|
|
74
|
+
net: { org?: number; ref?: number };
|
|
75
|
+
abs: { org?: number; ref?: number };
|
|
76
|
+
};
|
|
77
|
+
exposure: {
|
|
78
|
+
net: { org?: number; ref?: number };
|
|
79
|
+
abs: { org?: number; ref?: number };
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
children: RemoteValuationReportChildHolding[];
|
|
83
|
+
change?: number;
|
|
84
|
+
pnl?: number;
|
|
85
|
+
pnl_to_investment?: number;
|
|
86
|
+
opendate: SDate;
|
|
87
|
+
lastdate: SDate;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Valuation child holding.
|
|
92
|
+
*/
|
|
93
|
+
export interface RemoteValuationReportChildHolding {
|
|
94
|
+
artifact: RemoteValuationReportArtifact;
|
|
95
|
+
tags: {};
|
|
96
|
+
quantity: number;
|
|
97
|
+
accounts: ValuationReportAccount[];
|
|
98
|
+
investment: {
|
|
99
|
+
px: { org?: number; ref?: number };
|
|
100
|
+
txncosts: { org?: number; ref?: number };
|
|
101
|
+
accrued: { org?: number; ref?: number };
|
|
102
|
+
value: { org?: number; ref?: number };
|
|
103
|
+
};
|
|
104
|
+
valuation: {
|
|
105
|
+
px: { org?: number; ref?: number };
|
|
106
|
+
accrued: { org?: number; ref?: number };
|
|
107
|
+
value: {
|
|
108
|
+
net: { org?: number; ref?: number };
|
|
109
|
+
abs: { org?: number; ref?: number };
|
|
110
|
+
};
|
|
111
|
+
exposure: {
|
|
112
|
+
net: { org?: number; ref?: number };
|
|
113
|
+
abs: { org?: number; ref?: number };
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
change?: number;
|
|
117
|
+
pnl?: number;
|
|
118
|
+
pnl_to_investment?: number;
|
|
119
|
+
opendate: SDate;
|
|
120
|
+
lastdate: SDate;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Valuation artifact.
|
|
125
|
+
*/
|
|
126
|
+
export interface RemoteValuationReportArtifact {
|
|
127
|
+
id: ArtifactId;
|
|
128
|
+
guid: string;
|
|
129
|
+
type: { id: ArtifactTypeId; name: string; order: number };
|
|
130
|
+
stype?: string;
|
|
131
|
+
symbol: string;
|
|
132
|
+
name?: string;
|
|
133
|
+
ccy?: CurrencyCode;
|
|
134
|
+
quantity: number;
|
|
135
|
+
country?: string;
|
|
136
|
+
issuer?: string;
|
|
137
|
+
sector?: string;
|
|
138
|
+
mic?: string;
|
|
139
|
+
ticker?: string;
|
|
140
|
+
isin?: string;
|
|
141
|
+
figi?: string;
|
|
142
|
+
expiry?: SDate;
|
|
143
|
+
underlying_id?: ArtifactId;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Valuation accrual.
|
|
148
|
+
*/
|
|
149
|
+
export interface RemoteValuationReportAccrual {
|
|
150
|
+
name: string;
|
|
151
|
+
value: number;
|
|
152
|
+
accounts: RemoteValuationReportAccrualByAccount[];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Valuation accrual by account.
|
|
157
|
+
*/
|
|
158
|
+
export interface RemoteValuationReportAccrualByAccount {
|
|
159
|
+
account: ValuationReportAccount;
|
|
160
|
+
value: number;
|
|
161
|
+
accruals: RemoteValuationReportAccrualByCurrency[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Valuation accrual by account by currency.
|
|
166
|
+
*/
|
|
167
|
+
export interface RemoteValuationReportAccrualByCurrency {
|
|
168
|
+
artifact: RemoteValuationReportArtifact;
|
|
169
|
+
ccy: CurrencyCode;
|
|
170
|
+
value: { org?: number; ref?: number };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function toArtifact(x: RemoteValuationReportArtifact): ValuationReportArtifact {
|
|
174
|
+
return {
|
|
175
|
+
id: x.id,
|
|
176
|
+
guid: x.guid,
|
|
177
|
+
type: x.type,
|
|
178
|
+
stype: sanitizedNonEmptyText(x.stype),
|
|
179
|
+
symbol: x.symbol,
|
|
180
|
+
name: sanitizedNonEmptyText(x.name),
|
|
181
|
+
ccy: Maybe.fromNullable(x.ccy),
|
|
182
|
+
quantity: asDecimal(x.quantity),
|
|
183
|
+
country: sanitizedNonEmptyText(x.country),
|
|
184
|
+
issuer: sanitizedNonEmptyText(x.issuer),
|
|
185
|
+
sector: sanitizedNonEmptyText(x.sector),
|
|
186
|
+
mic: sanitizedNonEmptyText(x.mic),
|
|
187
|
+
ticker: sanitizedNonEmptyText(x.ticker),
|
|
188
|
+
isin: sanitizedNonEmptyText(x.isin),
|
|
189
|
+
figi: sanitizedNonEmptyText(x.figi),
|
|
190
|
+
expiry: Maybe.fromNullable(x.expiry),
|
|
191
|
+
underlyingId: Maybe.fromNullable(x.underlying_id),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function toAccrual(x: RemoteValuationReportAccrual): ValuationReportAccrual {
|
|
196
|
+
return {
|
|
197
|
+
name: x.name,
|
|
198
|
+
value: asDecimal(x.value),
|
|
199
|
+
accounts: x.accounts.map((y) => ({
|
|
200
|
+
account: y.account,
|
|
201
|
+
value: asDecimal(y.value),
|
|
202
|
+
accruals: y.accruals.map((z) => ({
|
|
203
|
+
artifact: toArtifact(z.artifact),
|
|
204
|
+
ccy: z.ccy,
|
|
205
|
+
value: { org: asDecimal(z.value.org || 0), ref: asDecimal(z.value.ref || 0) },
|
|
206
|
+
})),
|
|
207
|
+
})),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function toOrgRef(x: { org?: number; ref?: number }): ValuationReportFigureOrgRef {
|
|
212
|
+
return {
|
|
213
|
+
org: maybeDecimal(x.org).orDefault(zero),
|
|
214
|
+
ref: maybeDecimal(x.ref).orDefault(zero),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function toMaybeOrgRef(x?: { org?: number; ref?: number }): Maybe<ValuationReportFigureOrgRef> {
|
|
219
|
+
return Maybe.fromNullable(x).chain(({ org, ref }) =>
|
|
220
|
+
maybeDecimal(org).chain((o) => maybeDecimal(ref).chain((r) => Just({ org: o, ref: r })))
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function toBaseHolding(
|
|
225
|
+
nav: Decimal,
|
|
226
|
+
x: RemoteValuationReportHolding | RemoteValuationReportChildHolding
|
|
227
|
+
): BaseValuationReportHolding {
|
|
228
|
+
return {
|
|
229
|
+
artifact: toArtifact(x.artifact),
|
|
230
|
+
quantity: asDecimal(x.quantity),
|
|
231
|
+
investment: {
|
|
232
|
+
px: toOrgRef(x.investment.px),
|
|
233
|
+
txncosts: toMaybeOrgRef(x.investment.txncosts),
|
|
234
|
+
accrued: toMaybeOrgRef(x.investment.accrued),
|
|
235
|
+
value: toOrgRef(x.investment.value),
|
|
236
|
+
},
|
|
237
|
+
valuation: {
|
|
238
|
+
px: toOrgRef(x.valuation.px),
|
|
239
|
+
accrued: toMaybeOrgRef(x.valuation.accrued),
|
|
240
|
+
value: {
|
|
241
|
+
net: toOrgRef(x.valuation.value.net),
|
|
242
|
+
abs: toOrgRef(x.valuation.value.abs),
|
|
243
|
+
},
|
|
244
|
+
exposure: {
|
|
245
|
+
net: toOrgRef(x.valuation.exposure.net),
|
|
246
|
+
abs: toOrgRef(x.valuation.exposure.abs),
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
valuePercentage: safeDiv(maybeDecimal(x.valuation.value.net.ref).orDefault(zero), nav),
|
|
250
|
+
netExposurePercentage: safeDiv(maybeDecimal(x.valuation.exposure.net.ref).orDefault(zero), nav),
|
|
251
|
+
absExposurePercentage: safeDiv(maybeDecimal(x.valuation.exposure.abs.ref).orDefault(zero), nav),
|
|
252
|
+
change: maybeDecimal(x.change),
|
|
253
|
+
pnl: maybeDecimal(x.pnl).orDefault(zero),
|
|
254
|
+
pnlToInvestment: maybeDecimal(x.pnl_to_investment),
|
|
255
|
+
opendate: x.opendate,
|
|
256
|
+
lastdate: x.lastdate,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function toHolding(nav: Decimal, x: RemoteValuationReportHolding): ValuationReportHolding {
|
|
261
|
+
return {
|
|
262
|
+
...toBaseHolding(nav, x),
|
|
263
|
+
classification: x.tags.classification.map((n) => ({ ...n, order: n.order || '' })),
|
|
264
|
+
accounts: x.accounts,
|
|
265
|
+
children: Maybe.fromNullable(x.children)
|
|
266
|
+
.filter((mc) => mc.length !== 0)
|
|
267
|
+
.map((mc) =>
|
|
268
|
+
mc.map((c) => ({
|
|
269
|
+
...toBaseHolding(nav, c),
|
|
270
|
+
account: c.accounts[0] as ValuationReportAccount,
|
|
271
|
+
}))
|
|
272
|
+
),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Attempts to re-compile the raw, remote base valuation report and
|
|
278
|
+
* return it.
|
|
279
|
+
*
|
|
280
|
+
* @param x Raw, remote base valuation report.
|
|
281
|
+
* @returns Either of an error message or the re-compiled base valuation
|
|
282
|
+
* report.
|
|
283
|
+
*/
|
|
284
|
+
export function recompileBaseValuationReport(x: RemoteBaseValuationReport): Either<CustomError, BaseValuationReport> {
|
|
285
|
+
const nav = maybeDecimal(x.nav).orDefault(zero);
|
|
286
|
+
|
|
287
|
+
const report: BaseValuationReport = {
|
|
288
|
+
asof: x.reported,
|
|
289
|
+
date: x.asof,
|
|
290
|
+
dateType: x.type,
|
|
291
|
+
currency: x.ccy,
|
|
292
|
+
accounts: x.accounts,
|
|
293
|
+
holdings: x.holdings.map((rh) => toHolding(nav, rh)),
|
|
294
|
+
accruals: x.accruals.map(toAccrual),
|
|
295
|
+
fxRates: x.fxrates.map((r) => ({ ccy1: r.ccy1, ccy2: r.ccy2, value: asDecimal(r.value), asof: r.asof })),
|
|
296
|
+
figures: {
|
|
297
|
+
investment: maybeDecimal(x.investment).orDefault(zero),
|
|
298
|
+
valuation: {
|
|
299
|
+
net: maybeDecimal(x.valuation_net).orDefault(zero),
|
|
300
|
+
abs: maybeDecimal(x.valuation_abs).orDefault(zero),
|
|
301
|
+
},
|
|
302
|
+
accrued: maybeDecimal(x.accrued).orDefault(zero),
|
|
303
|
+
liabilities: maybeDecimal(x.liabilities).orDefault(zero),
|
|
304
|
+
gav: maybeDecimal(x.gav).orDefault(zero),
|
|
305
|
+
nav,
|
|
306
|
+
aum: maybeDecimal(x.aum).orDefault(zero),
|
|
307
|
+
pnl: maybeDecimal(x.pnl).orDefault(zero),
|
|
308
|
+
pnlToInvestment: maybeDecimal(x.pnl_to_investment),
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
return Right(report);
|
|
313
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BaseValuationReport } from './-valuation-report-shared';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definition for consolidated valuation report.
|
|
5
|
+
*/
|
|
6
|
+
export interface ConsolidatedValuationReport extends BaseValuationReport {
|
|
7
|
+
/**
|
|
8
|
+
* Type of containers consolidated.
|
|
9
|
+
*/
|
|
10
|
+
containerType: ConsolidatedValuationReportContainerType;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Containers consolidated.
|
|
14
|
+
*/
|
|
15
|
+
containers: ConsolidatedValuationReportContainer[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Type definition for container types to be consolidated.
|
|
20
|
+
*/
|
|
21
|
+
export type ConsolidatedValuationReportContainerType =
|
|
22
|
+
| 'account'
|
|
23
|
+
| 'portfolio'
|
|
24
|
+
| 'team'
|
|
25
|
+
| 'custodian'
|
|
26
|
+
| 'portfolio-group';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Type definition for valuation report containers.
|
|
30
|
+
*/
|
|
31
|
+
export interface ConsolidatedValuationReportContainer {
|
|
32
|
+
/**
|
|
33
|
+
* Id of the container.
|
|
34
|
+
*/
|
|
35
|
+
id: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* GUID of the container.
|
|
39
|
+
*/
|
|
40
|
+
guid: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Name of the container.
|
|
44
|
+
*/
|
|
45
|
+
name: string;
|
|
46
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Decimal, safeDiv, sumDecimals, Tuple, zero } from '@telostat/prelude';
|
|
2
|
+
import { Just, Maybe, Nothing } from 'purify-ts';
|
|
3
|
+
import { List } from 'purify-ts/List';
|
|
4
|
+
import { ValuationReportHolding, ValuationReportHoldingClassification } from '../-valuation-report-shared';
|
|
5
|
+
import { ValuationReportHoldingsTreeNode, ValuationReportHoldingsTreeNodeValue } from './-types';
|
|
6
|
+
import { compareStringArrays } from './-utils';
|
|
7
|
+
|
|
8
|
+
export function makeValuationReportHoldingsTreeNodeValue(): ValuationReportHoldingsTreeNodeValue {
|
|
9
|
+
return {
|
|
10
|
+
investment: zero,
|
|
11
|
+
accrued: Nothing,
|
|
12
|
+
netValue: zero,
|
|
13
|
+
netValueRatio: zero,
|
|
14
|
+
absValue: zero,
|
|
15
|
+
absValueRatio: zero,
|
|
16
|
+
netExposure: zero,
|
|
17
|
+
netExposureRatio: zero,
|
|
18
|
+
absExposure: zero,
|
|
19
|
+
absExposureRatio: zero,
|
|
20
|
+
pnl: zero,
|
|
21
|
+
pnlRatio: zero,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function updateTotals(
|
|
26
|
+
nav: Decimal,
|
|
27
|
+
investment: Decimal,
|
|
28
|
+
tree: ValuationReportHoldingsTreeNode
|
|
29
|
+
): ValuationReportHoldingsTreeNodeValue {
|
|
30
|
+
const holdings = tree.holdings;
|
|
31
|
+
const children = tree.children;
|
|
32
|
+
|
|
33
|
+
const netValue = sumDecimals(holdings.map((x) => x.valuation.value.net.ref)).add(
|
|
34
|
+
sumDecimals(children.map((x) => x.totals.netValue))
|
|
35
|
+
);
|
|
36
|
+
const absValue = sumDecimals(holdings.map((x) => x.valuation.value.abs.ref)).add(
|
|
37
|
+
sumDecimals(children.map((x) => x.totals.absValue))
|
|
38
|
+
);
|
|
39
|
+
const netExposure = sumDecimals(holdings.map((x) => x.valuation.exposure.net.ref)).add(
|
|
40
|
+
sumDecimals(children.map((x) => x.totals.netExposure))
|
|
41
|
+
);
|
|
42
|
+
const absExposure = sumDecimals(holdings.map((x) => x.valuation.exposure.abs.ref)).add(
|
|
43
|
+
sumDecimals(children.map((x) => x.totals.absExposure))
|
|
44
|
+
);
|
|
45
|
+
const pnl = sumDecimals(holdings.map((x) => x.pnl)).add(sumDecimals(children.map((x) => x.totals.pnl)));
|
|
46
|
+
|
|
47
|
+
const accruedsHoldings = holdings.map((x) => x.investment.accrued.map((x) => x.ref));
|
|
48
|
+
const accruedsChildren = children.map((x) => x.totals.accrued);
|
|
49
|
+
const accrueds = Maybe.catMaybes([...accruedsHoldings, ...accruedsChildren]);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
investment: sumDecimals(holdings.map((x) => x.investment.value.ref)).add(
|
|
53
|
+
sumDecimals(children.map((x) => x.totals.investment))
|
|
54
|
+
),
|
|
55
|
+
accrued: accrueds.length === 0 ? Nothing : Just(sumDecimals(accrueds)),
|
|
56
|
+
netValue,
|
|
57
|
+
netValueRatio: safeDiv(netValue, nav).orDefault(zero),
|
|
58
|
+
absValue,
|
|
59
|
+
absValueRatio: safeDiv(absValue, nav).orDefault(zero),
|
|
60
|
+
netExposure,
|
|
61
|
+
netExposureRatio: safeDiv(netExposure, nav).orDefault(zero),
|
|
62
|
+
absExposure,
|
|
63
|
+
absExposureRatio: safeDiv(absExposure, nav).orDefault(zero),
|
|
64
|
+
pnl,
|
|
65
|
+
pnlRatio: safeDiv(pnl, investment).orDefault(zero),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function resortChildren(node: ValuationReportHoldingsTreeNode): ValuationReportHoldingsTreeNode[] {
|
|
70
|
+
return node.children.sort((t1, t2) => {
|
|
71
|
+
// Get current address segments:
|
|
72
|
+
const segment1 = List.last(t1.address);
|
|
73
|
+
const segment2 = List.last(t2.address);
|
|
74
|
+
|
|
75
|
+
// Compare and return:
|
|
76
|
+
return segment1
|
|
77
|
+
.chain((s1) => segment2.chain((s2) => Just(Tuple(s1, s2))))
|
|
78
|
+
.map((x) => x.toArray())
|
|
79
|
+
.map(([x, y]) => `${x.order}`.localeCompare(`${y.order}`))
|
|
80
|
+
.orDefaultLazy(() => (segment1.isNothing() ? -1 : 1));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function retreatTree(nav: Decimal, investment: Decimal, tree: ValuationReportHoldingsTreeNode) {
|
|
85
|
+
// First, retreat all children (recursive):
|
|
86
|
+
tree.children.forEach((x) => retreatTree(nav, investment, x));
|
|
87
|
+
|
|
88
|
+
// Recompute totals:
|
|
89
|
+
tree.totals = updateTotals(nav, investment, tree);
|
|
90
|
+
|
|
91
|
+
// Resort children:
|
|
92
|
+
tree.children = resortChildren(tree);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function makeValuationReportHoldingsTreeNode(
|
|
96
|
+
address: ValuationReportHoldingClassification
|
|
97
|
+
): ValuationReportHoldingsTreeNode {
|
|
98
|
+
return {
|
|
99
|
+
name: List.last(address)
|
|
100
|
+
.map((x) => x.name)
|
|
101
|
+
.orDefault(''),
|
|
102
|
+
address,
|
|
103
|
+
holdings: [],
|
|
104
|
+
children: [],
|
|
105
|
+
totals: makeValuationReportHoldingsTreeNodeValue(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function addValuationReportHoldingToTree(
|
|
110
|
+
tree: ValuationReportHoldingsTreeNode,
|
|
111
|
+
address: ValuationReportHoldingClassification,
|
|
112
|
+
holding: ValuationReportHolding
|
|
113
|
+
): void {
|
|
114
|
+
// Get the starting (current) node:
|
|
115
|
+
let node = tree;
|
|
116
|
+
|
|
117
|
+
// Iterate over address and traverse the tree while adding new nodes when required:
|
|
118
|
+
const sofar: string[] = [];
|
|
119
|
+
const sofarAddress: ValuationReportHoldingClassification = [];
|
|
120
|
+
|
|
121
|
+
for (const segment of address) {
|
|
122
|
+
// Append to address buffer:
|
|
123
|
+
sofar.push(segment.name);
|
|
124
|
+
sofarAddress.push(segment);
|
|
125
|
+
|
|
126
|
+
// Attempt to find the child:
|
|
127
|
+
let child = node.children.find(
|
|
128
|
+
(n) =>
|
|
129
|
+
compareStringArrays(
|
|
130
|
+
n.address.map((x) => x.name),
|
|
131
|
+
sofar
|
|
132
|
+
) === 0
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Add or use?
|
|
136
|
+
if (child === undefined) {
|
|
137
|
+
// Create the new node:
|
|
138
|
+
child = makeValuationReportHoldingsTreeNode([...sofarAddress]);
|
|
139
|
+
|
|
140
|
+
// Add the new node to the current node as a child:
|
|
141
|
+
node.children.push(child);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Set the current node to the child:
|
|
145
|
+
node = child;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Done, we append the holding to the current node and return from the procedure:
|
|
149
|
+
node.holdings.push(holding);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function makeValuationReportHoldingsTree(
|
|
153
|
+
nav: Decimal,
|
|
154
|
+
investment: Decimal,
|
|
155
|
+
holdings: ValuationReportHolding[]
|
|
156
|
+
): ValuationReportHoldingsTreeNode {
|
|
157
|
+
// Initialize the tree:
|
|
158
|
+
const tree = makeValuationReportHoldingsTreeNode([]);
|
|
159
|
+
tree.name = '« Total »';
|
|
160
|
+
|
|
161
|
+
// Iterate over the holdings and attempt to add to the tree:
|
|
162
|
+
for (const holding of holdings) {
|
|
163
|
+
addValuationReportHoldingToTree(tree, holding.classification, holding);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Retreat the tree:
|
|
167
|
+
retreatTree(nav, investment, tree);
|
|
168
|
+
|
|
169
|
+
// Done, return:
|
|
170
|
+
return tree;
|
|
171
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Decimal, Maybe } from '@telostat/prelude';
|
|
2
|
+
import { ValuationReportHolding, ValuationReportHoldingClassification } from '../-valuation-report-shared';
|
|
3
|
+
|
|
4
|
+
export interface ValuationReportHoldingsTreeNode {
|
|
5
|
+
name: string;
|
|
6
|
+
address: ValuationReportHoldingClassification;
|
|
7
|
+
holdings: ValuationReportHolding[];
|
|
8
|
+
children: ValuationReportHoldingsTreeNode[];
|
|
9
|
+
totals: ValuationReportHoldingsTreeNodeValue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ValuationReportHoldingsTreeNodeValue {
|
|
13
|
+
investment: Decimal;
|
|
14
|
+
accrued: Maybe<Decimal>;
|
|
15
|
+
netValue: Decimal;
|
|
16
|
+
netValueRatio: Decimal;
|
|
17
|
+
absValue: Decimal;
|
|
18
|
+
absValueRatio: Decimal;
|
|
19
|
+
netExposure: Decimal;
|
|
20
|
+
netExposureRatio: Decimal;
|
|
21
|
+
absExposure: Decimal;
|
|
22
|
+
absExposureRatio: Decimal;
|
|
23
|
+
pnl: Decimal;
|
|
24
|
+
pnlRatio: Decimal;
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function compareStringArrays(x: string[], y: string[]): number {
|
|
2
|
+
const xLen = x.length;
|
|
3
|
+
const yLen = y.length;
|
|
4
|
+
const minLength = Math.min(xLen, yLen);
|
|
5
|
+
|
|
6
|
+
for (let i = 0; i < minLength; i++) {
|
|
7
|
+
const comparison = (x[i] || '').localeCompare(y[i] || '');
|
|
8
|
+
|
|
9
|
+
if (comparison !== 0) {
|
|
10
|
+
return comparison;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return Math.sign(xLen - yLen);
|
|
15
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Decimal, Maybe, SDate, SDateTime } from '@telostat/prelude';
|
|
2
|
+
import {
|
|
3
|
+
ActionId,
|
|
4
|
+
CurrencyCode,
|
|
5
|
+
ExternalValuationId,
|
|
6
|
+
OhlcSeriesId,
|
|
7
|
+
PortfolioId,
|
|
8
|
+
PrincipalId,
|
|
9
|
+
ShareClassFeeScheduleId,
|
|
10
|
+
ShareClassId,
|
|
11
|
+
} from '../../commons';
|
|
12
|
+
import { BaseValuationReport, ValuationReportPortfolio } from './-valuation-report-shared';
|
|
13
|
+
|
|
14
|
+
export interface PortfolioValuationReport extends BaseValuationReport {
|
|
15
|
+
portfolio: ValuationReportPortfolio;
|
|
16
|
+
subscriptions: Decimal;
|
|
17
|
+
shareClassValues: PortfolioValuationReportShareClassValue[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PortfolioValuationReportShareClassValue {
|
|
21
|
+
shareclass: PortfolioValuationReportShareClass;
|
|
22
|
+
external: Maybe<PortfolioValuationReportExternalValue>;
|
|
23
|
+
nav: Decimal;
|
|
24
|
+
navAdjusted: Decimal;
|
|
25
|
+
navAdjustedTotal: Decimal;
|
|
26
|
+
coefficient: Decimal;
|
|
27
|
+
gavRefccy: Decimal;
|
|
28
|
+
gavClsccy: Decimal;
|
|
29
|
+
sharecountPrev: Decimal;
|
|
30
|
+
sharecountCurr: Decimal;
|
|
31
|
+
sharecountDiff: Decimal;
|
|
32
|
+
pxRefCcy: Decimal;
|
|
33
|
+
pxClsCcy: Decimal;
|
|
34
|
+
ytdExt: Maybe<Decimal>;
|
|
35
|
+
ytdInt: Maybe<Decimal>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PortfolioValuationReportShareClass {
|
|
39
|
+
id: ShareClassId;
|
|
40
|
+
created: SDateTime;
|
|
41
|
+
creator: Maybe<PrincipalId>;
|
|
42
|
+
updated: SDateTime;
|
|
43
|
+
updater: Maybe<PrincipalId>;
|
|
44
|
+
guid: string;
|
|
45
|
+
portfolio: PortfolioId;
|
|
46
|
+
name: string;
|
|
47
|
+
currency: CurrencyCode;
|
|
48
|
+
isin: Maybe<string>;
|
|
49
|
+
bbgticker: Maybe<string>;
|
|
50
|
+
liquidity: Maybe<string>;
|
|
51
|
+
jurisdiction: Maybe<string>;
|
|
52
|
+
administrator: Maybe<string>;
|
|
53
|
+
minimumInvestment: Maybe<string>;
|
|
54
|
+
subscriptionRedemptionPeriod: Maybe<string>;
|
|
55
|
+
managementFeeFrequency: Maybe<number>;
|
|
56
|
+
performanceFeeFrequency: Maybe<number>;
|
|
57
|
+
benchmark: Maybe<OhlcSeriesId>;
|
|
58
|
+
description: Maybe<string>;
|
|
59
|
+
feeScheduleIds: ShareClassFeeScheduleId[];
|
|
60
|
+
effectiveFeeScheduleId: Maybe<ShareClassFeeScheduleId>;
|
|
61
|
+
subscriptionIds: ActionId[];
|
|
62
|
+
outstanding: Maybe<Decimal>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface PortfolioValuationReportExternalValue {
|
|
66
|
+
id: ExternalValuationId;
|
|
67
|
+
created: SDateTime;
|
|
68
|
+
creator: Maybe<PrincipalId>;
|
|
69
|
+
updated: SDateTime;
|
|
70
|
+
updater: Maybe<PrincipalId>;
|
|
71
|
+
guid: string;
|
|
72
|
+
portfolio: PortfolioId;
|
|
73
|
+
shareclass: Maybe<ShareClassId>;
|
|
74
|
+
date: SDate;
|
|
75
|
+
ccy: CurrencyCode;
|
|
76
|
+
shares: Maybe<Decimal>;
|
|
77
|
+
price: Maybe<Decimal>;
|
|
78
|
+
nav: Maybe<Decimal>;
|
|
79
|
+
aum: Maybe<Decimal>;
|
|
80
|
+
hedgepnl: Maybe<Decimal>;
|
|
81
|
+
feemngt: Maybe<Decimal>;
|
|
82
|
+
feeperf: Maybe<Decimal>;
|
|
83
|
+
otheraccrued: Maybe<Decimal>;
|
|
84
|
+
totalaccrued: Maybe<Decimal>;
|
|
85
|
+
subred: Maybe<Decimal>;
|
|
86
|
+
perfdaily: Maybe<Decimal>;
|
|
87
|
+
perfweekly: Maybe<Decimal>;
|
|
88
|
+
perfmonthly: Maybe<Decimal>;
|
|
89
|
+
perfytd: Maybe<Decimal>;
|
|
90
|
+
perfstart: Maybe<Decimal>;
|
|
91
|
+
coefficient: Maybe<Decimal>;
|
|
92
|
+
}
|