sec-edgar-api 0.2.4 → 0.3.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/README.md +1 -0
- package/build/services/DocumentParser/DocumentParser.d.ts +12 -0
- package/build/services/DocumentParser/DocumentParser.js +3 -0
- package/build/services/DocumentParser/parsers/index.d.ts +2 -0
- package/build/services/DocumentParser/parsers/index.js +2 -0
- package/build/services/DocumentParser/parsers/parse-current-filings-daily.d.ts +13 -0
- package/build/services/DocumentParser/parsers/parse-current-filings-daily.js +37 -0
- package/build/services/ReportParser/ReportParser.d.ts +10 -14
- package/build/services/ReportParser/ReportParser.js +17 -24
- package/build/services/ReportRawBuilder/FactGrouper.d.ts +27 -0
- package/build/services/ReportRawBuilder/FactGrouper.js +206 -0
- package/build/services/{ReportBuilder → ReportRawBuilder}/FactPeriodResolver.d.ts +46 -2
- package/build/services/{ReportBuilder → ReportRawBuilder}/FactPeriodResolver.js +82 -20
- package/build/services/ReportRawBuilder/FactRecordBuilder.d.ts +9 -0
- package/build/services/{ReportBuilder → ReportRawBuilder}/FactRecordBuilder.js +6 -24
- package/build/services/ReportRawBuilder/FactSplitAdjuster.d.ts +43 -0
- package/build/services/ReportRawBuilder/FactSplitAdjuster.js +242 -0
- package/build/services/ReportRawBuilder/ReportRawBuilder.d.ts +39 -0
- package/build/services/ReportRawBuilder/ReportRawBuilder.js +158 -0
- package/build/services/ReportRawBuilder/index.d.ts +2 -0
- package/build/services/ReportRawBuilder/index.js +4 -0
- package/build/services/SecEdgarApi/SecEdgarApi.d.ts +32 -5
- package/build/services/SecEdgarApi/SecEdgarApi.js +65 -13
- package/build/types/common.type.d.ts +41 -0
- package/build/types/company-facts.type.d.ts +29 -2
- package/build/types/parsed-filings.type.d.ts +1 -0
- package/package.json +1 -1
- package/build/services/ReportBuilder/FactRecordBuilder.d.ts +0 -10
- package/build/services/ReportBuilder/FactSplitAdjuster.d.ts +0 -50
- package/build/services/ReportBuilder/FactSplitAdjuster.js +0 -214
- package/build/services/ReportBuilder/ReportBuilder.d.ts +0 -40
- package/build/services/ReportBuilder/ReportBuilder.js +0 -200
- package/build/services/ReportBuilder/ReportRawResolvable.d.ts +0 -17
- package/build/services/ReportBuilder/ReportRawResolvable.js +0 -114
- package/build/services/ReportBuilder/index.d.ts +0 -2
- package/build/services/ReportBuilder/index.js +0 -4
- package/build/services/ReportParser/ReportRawParser.d.ts +0 -5
- package/build/services/ReportParser/ReportRawParser.js +0 -14
- package/build/util/calculation-map-by-ns.d.ts +0 -6
- package/build/util/calculation-map-by-ns.js +0 -9
- /package/build/services/{ReportBuilder → ReportRawBuilder}/FactFiscalCalculator.d.ts +0 -0
- /package/build/services/{ReportBuilder → ReportRawBuilder}/FactFiscalCalculator.js +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
var ReportRawResolvable_1 = require("./ReportRawResolvable");
|
|
4
3
|
/**
|
|
5
4
|
* Resolves quarterly and annual values for a property. This is because filers provide total values for the
|
|
6
5
|
* current fiscal year, rather than values for the individual quarters
|
|
@@ -21,9 +20,34 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
21
20
|
/** prevent values from being added multiple times */
|
|
22
21
|
this.resolvedValues = new Set();
|
|
23
22
|
this.unresolvedReports = new Map();
|
|
24
|
-
var cik = args.cik;
|
|
23
|
+
var cik = args.cik, _a = args.preferOriginalFilingValues, preferOriginalFilingValues = _a === void 0 ? false : _a;
|
|
25
24
|
this.cik = cik;
|
|
25
|
+
this.preferOriginalFilingValues = preferOriginalFilingValues;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Some properties have a start and end that represent a period average, rather than a period total.
|
|
29
|
+
* These properties should be treated as instantaneous properties, meaning
|
|
30
|
+
* the value for Q4 and FY should be the same.
|
|
31
|
+
*
|
|
32
|
+
* I believe the only properties like this are share related:
|
|
33
|
+
* us-gaap:WeightedAverageNumberOfDilutedSharesOutstanding and us-gaap:WeightedAverageNumberOfSharesOutstandingBasic.
|
|
34
|
+
* May need to update this in the future if there are more
|
|
35
|
+
*/
|
|
36
|
+
FactPeriodResolver.isAverageShares = function (params) {
|
|
37
|
+
var propertyName = params.propertyName;
|
|
38
|
+
return (propertyName.includes('Average') &&
|
|
39
|
+
(propertyName.includes('SharesOutstanding') || propertyName.includes('SharesIssued')));
|
|
40
|
+
};
|
|
41
|
+
FactPeriodResolver.prototype.isAverageShares = function (params) {
|
|
42
|
+
return FactPeriodResolver.isAverageShares(params);
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Used to check if this should potentially overwrite a value that has already been set.
|
|
46
|
+
*/
|
|
47
|
+
FactPeriodResolver.prototype.isPreferredValue = function (params) {
|
|
48
|
+
var bucket = params.bucket, end = params.end, filed = params.filed, bucketIndex = params.bucketIndex;
|
|
49
|
+
return !bucket.has(bucketIndex) || this.preferOriginalFilingValues || !this.isOriginalFiling({ end: end, filed: filed });
|
|
50
|
+
};
|
|
27
51
|
FactPeriodResolver.prototype.getOrSetBucketArr = function (map, year, propertyName) {
|
|
28
52
|
var _a, _b;
|
|
29
53
|
var propertyMap = (_a = map.get(year)) !== null && _a !== void 0 ? _a : map.set(year, new Map()).get(year);
|
|
@@ -49,8 +73,8 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
49
73
|
var reportKey = "".concat(year, "_").concat(i + 1);
|
|
50
74
|
var unresolvedReport = this.unresolvedReports.get(reportKey);
|
|
51
75
|
var unresolvedReportPrev = this.unresolvedReports.get("".concat(year, "_").concat(i));
|
|
52
|
-
var sumValue = (_b = unresolvedReport === null || unresolvedReport === void 0 ? void 0 : unresolvedReport
|
|
53
|
-
var prevSum = (_c = unresolvedReportPrev === null || unresolvedReportPrev === void 0 ? void 0 : unresolvedReportPrev
|
|
76
|
+
var sumValue = (_b = unresolvedReport === null || unresolvedReport === void 0 ? void 0 : unresolvedReport[propertyName]) !== null && _b !== void 0 ? _b : 0;
|
|
77
|
+
var prevSum = (_c = unresolvedReportPrev === null || unresolvedReportPrev === void 0 ? void 0 : unresolvedReportPrev[propertyName]) !== null && _c !== void 0 ? _c : 0;
|
|
54
78
|
if (quarterValue === undefined) {
|
|
55
79
|
var bucketQuarter_1 = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
|
|
56
80
|
bucketQuarter_1.set(i, (Number(sumValue) || 0) - (Number(prevSum) || 0));
|
|
@@ -82,7 +106,13 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
82
106
|
var bucketString = (_g = (_f = this.valueByQuarterByPropertyByYearString.get(year)) === null || _f === void 0 ? void 0 : _f.get(propertyName)) !== null && _g !== void 0 ? _g : new Map();
|
|
83
107
|
return { bucketQuarter: bucketQuarter, bucketSum: bucketSum, bucketString: bucketString };
|
|
84
108
|
};
|
|
85
|
-
|
|
109
|
+
/**
|
|
110
|
+
* 0, 3, 6, 9, or 12 month period. 0 is instantaneous data that doesn't have a time period, (ex: assets)
|
|
111
|
+
* other facts have values that are for a period of time. (like revenue over the last 6 months).
|
|
112
|
+
*
|
|
113
|
+
* Use periods 0 and 3 for quarterly reports and 0 and 12 for annual reports.
|
|
114
|
+
*/
|
|
115
|
+
FactPeriodResolver.getPeriod = function (params) {
|
|
86
116
|
var start = params.start, end = params.end;
|
|
87
117
|
if (!start || start === end)
|
|
88
118
|
return 0;
|
|
@@ -96,11 +126,14 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
96
126
|
return 9;
|
|
97
127
|
return 12;
|
|
98
128
|
};
|
|
129
|
+
FactPeriodResolver.prototype.getPeriod = function (params) {
|
|
130
|
+
return FactPeriodResolver.getPeriod(params);
|
|
131
|
+
};
|
|
99
132
|
FactPeriodResolver.prototype.getOrSetReport = function (params) {
|
|
100
133
|
var _a;
|
|
101
134
|
var year = params.year, quarter = params.quarter;
|
|
102
135
|
var key = "".concat(year, "_").concat(quarter);
|
|
103
|
-
var report = (_a = this.unresolvedReports.get(key)) !== null && _a !== void 0 ? _a :
|
|
136
|
+
var report = (_a = this.unresolvedReports.get(key)) !== null && _a !== void 0 ? _a : {
|
|
104
137
|
cik: this.cik,
|
|
105
138
|
fiscalYear: year,
|
|
106
139
|
fiscalPeriod: quarter === 4 ? 'FY' : "Q".concat(quarter),
|
|
@@ -109,35 +142,54 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
109
142
|
url: null,
|
|
110
143
|
splitDate: null,
|
|
111
144
|
splitRatio: null,
|
|
112
|
-
}
|
|
145
|
+
};
|
|
113
146
|
if (!this.unresolvedReports.has(key)) {
|
|
114
147
|
this.unresolvedReports.set(key, report);
|
|
115
148
|
}
|
|
116
149
|
return report;
|
|
117
150
|
};
|
|
151
|
+
/**
|
|
152
|
+
* True if the filed date is within 60 days of the end date. This indicates that it is likely
|
|
153
|
+
* the original filing of the fact because filers are required to submit within 45 days of the
|
|
154
|
+
* period end, and subsequent reports are filed 90 days apart.
|
|
155
|
+
*/
|
|
156
|
+
FactPeriodResolver.prototype.isOriginalFiling = function (params) {
|
|
157
|
+
var end = params.end, filed = params.filed;
|
|
158
|
+
var DAY_60_MS = 5184000000;
|
|
159
|
+
return new Date(filed).getTime() - new Date(end).getTime() < DAY_60_MS;
|
|
160
|
+
};
|
|
118
161
|
FactPeriodResolver.prototype.add = function (params) {
|
|
119
162
|
var year = params.year, value = params.value, propertyName = params.name, quarter = params.quarter, start = params.start, end = params.end, filed = params.filed;
|
|
120
|
-
var
|
|
163
|
+
var bucketIndex = quarter - 1;
|
|
164
|
+
var period = this.isAverageShares({ propertyName: propertyName }) ? 0 : this.getPeriod({ start: start, end: end });
|
|
121
165
|
this.addPropertyByYear(this.propertiesByYear, year, propertyName);
|
|
122
166
|
if (typeof value === 'string') {
|
|
123
167
|
var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYearString, year, propertyName);
|
|
124
|
-
|
|
168
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
169
|
+
bucket.set(bucketIndex, value);
|
|
170
|
+
}
|
|
125
171
|
return;
|
|
126
172
|
}
|
|
127
173
|
if (period === 0) {
|
|
128
174
|
var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
|
|
129
175
|
var bucketSum = this.getOrSetBucketArr(this.sumByQuarterByPropertyByYear, year, propertyName);
|
|
130
|
-
|
|
131
|
-
|
|
176
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
177
|
+
bucket.set(bucketIndex, value);
|
|
178
|
+
bucketSum.set(bucketIndex, value);
|
|
179
|
+
}
|
|
132
180
|
return;
|
|
133
181
|
}
|
|
134
182
|
if (period === 3) {
|
|
135
183
|
var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
|
|
136
|
-
|
|
184
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
185
|
+
bucket.set(bucketIndex, value);
|
|
186
|
+
}
|
|
137
187
|
}
|
|
138
188
|
if (quarter === 1 || period > 3) {
|
|
139
189
|
var bucket = this.getOrSetBucketArr(this.sumByQuarterByPropertyByYear, year, propertyName);
|
|
140
|
-
|
|
190
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
191
|
+
bucket.set(bucketIndex, value);
|
|
192
|
+
}
|
|
141
193
|
}
|
|
142
194
|
this.addPropertyByYear(this.propertiesResolvableByYear, year, propertyName);
|
|
143
195
|
};
|
|
@@ -163,7 +215,7 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
163
215
|
if (value === undefined)
|
|
164
216
|
continue;
|
|
165
217
|
var report = _this.getOrSetReport({ year: year, quarter: i + 1 });
|
|
166
|
-
report
|
|
218
|
+
report[propertyName] = value;
|
|
167
219
|
}
|
|
168
220
|
});
|
|
169
221
|
});
|
|
@@ -173,14 +225,24 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
173
225
|
this.buildUnresolvedReports();
|
|
174
226
|
this.propertiesByYear.forEach(function (properties, year) {
|
|
175
227
|
properties.forEach(function (propertyName) {
|
|
176
|
-
var _a;
|
|
228
|
+
var _a, _b;
|
|
177
229
|
_this.resolveValues(propertyName, year);
|
|
178
|
-
for (var i = 0; i <
|
|
230
|
+
for (var i = 0; i < 4; i++) {
|
|
179
231
|
var isAnnual = i === 4;
|
|
180
|
-
var
|
|
181
|
-
var
|
|
182
|
-
var
|
|
183
|
-
|
|
232
|
+
var _c = _this.getPropertyBuckets(year, propertyName), bucketQuarter = _c.bucketQuarter, bucketSum = _c.bucketSum, bucketString = _c.bucketString;
|
|
233
|
+
var valueQuarter = (_a = bucketQuarter.get(i)) !== null && _a !== void 0 ? _a : bucketString.get(i);
|
|
234
|
+
var valueTrailing = bucketSum.get(i);
|
|
235
|
+
var value = (_b = (isAnnual ? bucketSum.get(3) : bucketQuarter.get(i))) !== null && _b !== void 0 ? _b : bucketString.get(i);
|
|
236
|
+
var quarter = i + 1;
|
|
237
|
+
callback({
|
|
238
|
+
year: year,
|
|
239
|
+
fiscalPeriod: "Q".concat(quarter),
|
|
240
|
+
propertyName: propertyName,
|
|
241
|
+
value: value,
|
|
242
|
+
quarter: quarter,
|
|
243
|
+
valueQuarter: valueQuarter,
|
|
244
|
+
valueTrailing: valueTrailing,
|
|
245
|
+
});
|
|
184
246
|
}
|
|
185
247
|
});
|
|
186
248
|
});
|
|
@@ -6,17 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
var FactRecordBuilder = /** @class */ (function () {
|
|
7
7
|
function FactRecordBuilder() {
|
|
8
8
|
}
|
|
9
|
-
FactRecordBuilder.prototype.createFacts = function (data,
|
|
10
|
-
if (
|
|
9
|
+
FactRecordBuilder.prototype.createFacts = function (data, includeNamePrefix) {
|
|
10
|
+
if (includeNamePrefix === void 0) { includeNamePrefix = true; }
|
|
11
11
|
var facts = data.facts, cik = data.cik;
|
|
12
|
-
var
|
|
13
|
-
var keyIndex = 0;
|
|
14
|
-
var createKey = function (params) {
|
|
15
|
-
if (!filterDuplicates)
|
|
16
|
-
return keyIndex++;
|
|
17
|
-
var start = params.start, end = params.end, filed = params.filed, propertyName = params.propertyName;
|
|
18
|
-
return "".concat(start !== null && start !== void 0 ? start : '', "_").concat(end, "_").concat(filed, "_").concat(propertyName);
|
|
19
|
-
};
|
|
12
|
+
var factItems = [];
|
|
20
13
|
for (var prefix in facts) {
|
|
21
14
|
var factByPropertyName = facts[prefix];
|
|
22
15
|
for (var propertyName in factByPropertyName) {
|
|
@@ -26,8 +19,7 @@ var FactRecordBuilder = /** @class */ (function () {
|
|
|
26
19
|
for (var _i = 0, factValues_1 = factValues; _i < factValues_1.length; _i++) {
|
|
27
20
|
var factValue = factValues_1[_i];
|
|
28
21
|
var end = factValue.end, start = factValue.start, val = factValue.val, filed = factValue.filed, accn = factValue.accn, form = factValue.form, fp = factValue.fp, frame = factValue.frame, fy = factValue.fy;
|
|
29
|
-
var
|
|
30
|
-
var name_1 = "".concat(prefix, ":").concat(propertyName);
|
|
22
|
+
var name_1 = includeNamePrefix ? "".concat(prefix, ":").concat(propertyName) : propertyName;
|
|
31
23
|
var item = {
|
|
32
24
|
cik: cik,
|
|
33
25
|
end: end,
|
|
@@ -49,22 +41,12 @@ var FactRecordBuilder = /** @class */ (function () {
|
|
|
49
41
|
item.frame = frame;
|
|
50
42
|
if (fy)
|
|
51
43
|
item.fy = fy;
|
|
52
|
-
|
|
53
|
-
if (!prevFact) {
|
|
54
|
-
factsByKey.set(mapKey, item);
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
// use whichever is closer to the report end date
|
|
58
|
-
var shouldPush = new Date(item.filed).getTime() - new Date(item.end).getTime() <
|
|
59
|
-
new Date(prevFact.filed).getTime() - new Date(prevFact.end).getTime();
|
|
60
|
-
if (shouldPush) {
|
|
61
|
-
factsByKey.set(mapKey, item);
|
|
62
|
-
}
|
|
44
|
+
factItems.push(item);
|
|
63
45
|
}
|
|
64
46
|
}
|
|
65
47
|
}
|
|
66
48
|
}
|
|
67
|
-
return { facts:
|
|
49
|
+
return { facts: factItems };
|
|
68
50
|
};
|
|
69
51
|
return FactRecordBuilder;
|
|
70
52
|
}());
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CompanyFactListData, FactGroup, FactItem, FactValue, SplitData } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Splits can be filed multiple times throughout different reports. There is no clear
|
|
4
|
+
* indication on when the split is executed or what facts the split has been applied to. This
|
|
5
|
+
* class tries to determine which splits have been applied and which need to be adjusted for
|
|
6
|
+
* each fact.
|
|
7
|
+
*/
|
|
8
|
+
export default class FactSplitAdjuster {
|
|
9
|
+
private readonly keySplit;
|
|
10
|
+
private preferFirstValue;
|
|
11
|
+
private getGroupValue;
|
|
12
|
+
getSplits(params: {
|
|
13
|
+
splitFacts: FactValue[] | FactItem[];
|
|
14
|
+
}): SplitData[];
|
|
15
|
+
filterSplitFacts(params: {
|
|
16
|
+
facts: FactItem[];
|
|
17
|
+
}): FactItem[];
|
|
18
|
+
extractSplitsFromCompanyFacts(params: {
|
|
19
|
+
companyFactList: Pick<CompanyFactListData, 'facts'>;
|
|
20
|
+
}): FactValue[];
|
|
21
|
+
getSplitsFromCompanyFacts(params: {
|
|
22
|
+
companyFactList: Pick<CompanyFactListData, 'facts'>;
|
|
23
|
+
}): SplitData[];
|
|
24
|
+
/**
|
|
25
|
+
* Returns true if the fact value was adjusted, false if it was not,
|
|
26
|
+
* and null if the comparison does not match the split
|
|
27
|
+
*/
|
|
28
|
+
private isAdjustedFromComparedFact;
|
|
29
|
+
/**
|
|
30
|
+
* Splits can be filed multiple times throughout different reports.
|
|
31
|
+
*/
|
|
32
|
+
didApplySplit(params: {
|
|
33
|
+
isShareRatio: boolean;
|
|
34
|
+
split: SplitData;
|
|
35
|
+
factGroup: FactGroup;
|
|
36
|
+
isTrailing: boolean;
|
|
37
|
+
useOppositePeriodFallback?: boolean;
|
|
38
|
+
}): boolean;
|
|
39
|
+
adjustForSplits(params: {
|
|
40
|
+
factGroups: FactGroup[];
|
|
41
|
+
splits: SplitData[];
|
|
42
|
+
}): void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
14
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
15
|
+
if (ar || !(i in from)) {
|
|
16
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
17
|
+
ar[i] = from[i];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
var FactPeriodResolver_1 = require("./FactPeriodResolver");
|
|
24
|
+
/**
|
|
25
|
+
* Splits can be filed multiple times throughout different reports. There is no clear
|
|
26
|
+
* indication on when the split is executed or what facts the split has been applied to. This
|
|
27
|
+
* class tries to determine which splits have been applied and which need to be adjusted for
|
|
28
|
+
* each fact.
|
|
29
|
+
*/
|
|
30
|
+
var FactSplitAdjuster = /** @class */ (function () {
|
|
31
|
+
function FactSplitAdjuster() {
|
|
32
|
+
this.keySplit = 'StockholdersEquityNoteStockSplitConversionRatio1';
|
|
33
|
+
this.preferFirstValue = true;
|
|
34
|
+
}
|
|
35
|
+
FactSplitAdjuster.prototype.getGroupValue = function (factGroup, isTrailing) {
|
|
36
|
+
if (isTrailing) {
|
|
37
|
+
return Number(this.preferFirstValue ? factGroup.valueTrailingFirst : factGroup.valueTrailingLast);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return Number(this.preferFirstValue ? factGroup.valuePeriodFirst : factGroup.valuePeriodLast);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
FactSplitAdjuster.prototype.getSplits = function (params) {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
var splitFacts = __spreadArray([], params.splitFacts, true).sort(function (a, b) { return (a.end < b.end ? -1 : 1); });
|
|
46
|
+
var YEAR_MS = 31536000000;
|
|
47
|
+
var splits = [];
|
|
48
|
+
var currentSplit = null;
|
|
49
|
+
for (var i = 0; i < splitFacts.length; i++) {
|
|
50
|
+
var prevFact = splitFacts[i - 1];
|
|
51
|
+
var fact = splitFacts[i];
|
|
52
|
+
var factValue = Number((_a = fact.value) !== null && _a !== void 0 ? _a : fact.val);
|
|
53
|
+
var factValuePrev = Number((_b = prevFact === null || prevFact === void 0 ? void 0 : prevFact.value) !== null && _b !== void 0 ? _b : prevFact === null || prevFact === void 0 ? void 0 : prevFact.val);
|
|
54
|
+
var isSameSplitLaterFiling = factValue === factValuePrev && new Date(fact.end).getTime() - new Date(prevFact.end).getTime() < YEAR_MS;
|
|
55
|
+
if (!isSameSplitLaterFiling && currentSplit) {
|
|
56
|
+
splits.push(currentSplit);
|
|
57
|
+
currentSplit = null;
|
|
58
|
+
}
|
|
59
|
+
if (!currentSplit) {
|
|
60
|
+
currentSplit = {
|
|
61
|
+
endFirst: fact.end,
|
|
62
|
+
endLast: fact.end,
|
|
63
|
+
filedFirst: fact.filed,
|
|
64
|
+
filedLast: fact.filed,
|
|
65
|
+
splitRatio: factValue,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
currentSplit.endFirst = fact.end < currentSplit.endFirst ? fact.end : currentSplit.endFirst;
|
|
70
|
+
currentSplit.endLast = fact.end > currentSplit.endLast ? fact.end : currentSplit.endLast;
|
|
71
|
+
currentSplit.filedFirst = fact.filed < currentSplit.filedFirst ? fact.filed : currentSplit.filedFirst;
|
|
72
|
+
currentSplit.filedLast = fact.filed > currentSplit.filedLast ? fact.filed : currentSplit.filedLast;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (currentSplit) {
|
|
76
|
+
splits.push(currentSplit);
|
|
77
|
+
}
|
|
78
|
+
return splits;
|
|
79
|
+
};
|
|
80
|
+
FactSplitAdjuster.prototype.filterSplitFacts = function (params) {
|
|
81
|
+
var _this = this;
|
|
82
|
+
var facts = params.facts;
|
|
83
|
+
return facts.filter(function (f) { return f.name.endsWith(_this.keySplit); });
|
|
84
|
+
};
|
|
85
|
+
FactSplitAdjuster.prototype.extractSplitsFromCompanyFacts = function (params) {
|
|
86
|
+
var _a, _b, _c;
|
|
87
|
+
var companyFactList = params.companyFactList;
|
|
88
|
+
var factsByName = (_a = companyFactList.facts['us-gaap']) !== null && _a !== void 0 ? _a : {};
|
|
89
|
+
return (_c = (_b = factsByName[this.keySplit]) === null || _b === void 0 ? void 0 : _b.units.pure) !== null && _c !== void 0 ? _c : [];
|
|
90
|
+
};
|
|
91
|
+
FactSplitAdjuster.prototype.getSplitsFromCompanyFacts = function (params) {
|
|
92
|
+
var _a, _b, _c;
|
|
93
|
+
var companyFactList = params.companyFactList;
|
|
94
|
+
var factsByName = (_a = companyFactList.facts['us-gaap']) !== null && _a !== void 0 ? _a : {};
|
|
95
|
+
var splitFacts = __spreadArray([], ((_c = (_b = factsByName[this.keySplit]) === null || _b === void 0 ? void 0 : _b.units.pure) !== null && _c !== void 0 ? _c : []), true).sort(function (a, b) { return (a.end < b.end ? -1 : 1); });
|
|
96
|
+
var YEAR_MS = 31536000000;
|
|
97
|
+
var splits = [];
|
|
98
|
+
var currentSplit = null;
|
|
99
|
+
for (var i = 0; i < splitFacts.length; i++) {
|
|
100
|
+
var prevFact = splitFacts[i - 1];
|
|
101
|
+
var fact = splitFacts[i];
|
|
102
|
+
// Assume the split is executed within the first year of the first filing...
|
|
103
|
+
// sometimes a company will file the split fact mentioning that they plan on executing it later in the fiscal year
|
|
104
|
+
// (ex: when Google did their 20:1 split in July of 2020)
|
|
105
|
+
var isSameSplitLaterFiling = fact.val === (prevFact === null || prevFact === void 0 ? void 0 : prevFact.val) && new Date(fact.end).getTime() - new Date(prevFact.end).getTime() < YEAR_MS;
|
|
106
|
+
if (!isSameSplitLaterFiling && currentSplit) {
|
|
107
|
+
splits.push(currentSplit);
|
|
108
|
+
currentSplit = null;
|
|
109
|
+
}
|
|
110
|
+
if (!currentSplit) {
|
|
111
|
+
currentSplit = {
|
|
112
|
+
endFirst: fact.end,
|
|
113
|
+
endLast: fact.end,
|
|
114
|
+
filedFirst: fact.filed,
|
|
115
|
+
filedLast: fact.filed,
|
|
116
|
+
splitRatio: Number(fact.val),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
currentSplit.endFirst = fact.end < currentSplit.endFirst ? fact.end : currentSplit.endFirst;
|
|
121
|
+
currentSplit.endLast = fact.end > currentSplit.endLast ? fact.end : currentSplit.endLast;
|
|
122
|
+
currentSplit.filedFirst = fact.filed < currentSplit.filedFirst ? fact.filed : currentSplit.filedFirst;
|
|
123
|
+
currentSplit.filedLast = fact.filed > currentSplit.filedLast ? fact.filed : currentSplit.filedLast;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (currentSplit) {
|
|
127
|
+
splits.push(currentSplit);
|
|
128
|
+
}
|
|
129
|
+
return splits;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Returns true if the fact value was adjusted, false if it was not,
|
|
133
|
+
* and null if the comparison does not match the split
|
|
134
|
+
*/
|
|
135
|
+
FactSplitAdjuster.prototype.isAdjustedFromComparedFact = function (params) {
|
|
136
|
+
var _a, _b;
|
|
137
|
+
var factCompare = params.factCompare, factValue = params.factValue, isShareRatio = params.isShareRatio, splitVal = params.splitVal;
|
|
138
|
+
var minValue = Math.min(factValue, Number((_a = factCompare === null || factCompare === void 0 ? void 0 : factCompare.value) !== null && _a !== void 0 ? _a : factValue));
|
|
139
|
+
var maxValue = Math.max(factValue, Number((_b = factCompare === null || factCompare === void 0 ? void 0 : factCompare.value) !== null && _b !== void 0 ? _b : factValue));
|
|
140
|
+
var possiblePreSplitValue = isShareRatio ? maxValue : minValue;
|
|
141
|
+
var possiblePostSplitValue = isShareRatio ? minValue : maxValue;
|
|
142
|
+
var expectedPostSplitValue = isShareRatio
|
|
143
|
+
? possiblePreSplitValue / splitVal
|
|
144
|
+
: possiblePreSplitValue * splitVal;
|
|
145
|
+
var nearnessThreshold = 0.01;
|
|
146
|
+
var isSplitAdjustment = Math.abs(expectedPostSplitValue - possiblePostSplitValue) < nearnessThreshold;
|
|
147
|
+
return isSplitAdjustment ? possiblePostSplitValue === factValue : null;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Splits can be filed multiple times throughout different reports.
|
|
151
|
+
*/
|
|
152
|
+
FactSplitAdjuster.prototype.didApplySplit = function (params) {
|
|
153
|
+
var isShareRatio = params.isShareRatio, factGroup = params.factGroup, split = params.split, isTrailing = params.isTrailing, _a = params.useOppositePeriodFallback, useOppositePeriodFallback = _a === void 0 ? true : _a;
|
|
154
|
+
var splitVal = split.splitRatio;
|
|
155
|
+
if (!splitVal)
|
|
156
|
+
return true;
|
|
157
|
+
// these first two criteria will take care of the majority of cases...
|
|
158
|
+
if (factGroup.filedFirst > split.filedLast) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
if (factGroup.filedLast < split.filedFirst) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
var resolvedFact = factGroup.facts.find(function (f) {
|
|
165
|
+
return isTrailing ? f.value === factGroup.valueTrailingFirst : f.value === factGroup.valuePeriodFirst;
|
|
166
|
+
});
|
|
167
|
+
if (!resolvedFact && useOppositePeriodFallback) {
|
|
168
|
+
return this.didApplySplit(__assign(__assign({}, params), { isTrailing: !isTrailing, useOppositePeriodFallback: false }));
|
|
169
|
+
}
|
|
170
|
+
var refiledFacts = factGroup.facts.filter(function (f) {
|
|
171
|
+
var period = FactPeriodResolver_1.default.getPeriod(f);
|
|
172
|
+
var isSamePeriod = isTrailing ? period === 0 || period > 3 : period <= 3;
|
|
173
|
+
return f !== resolvedFact && isSamePeriod;
|
|
174
|
+
});
|
|
175
|
+
// check if one of the filed facts is the split adjustment
|
|
176
|
+
for (var _i = 0, refiledFacts_1 = refiledFacts; _i < refiledFacts_1.length; _i++) {
|
|
177
|
+
var fact = refiledFacts_1[_i];
|
|
178
|
+
var isAdjusted = this.isAdjustedFromComparedFact({
|
|
179
|
+
factCompare: fact,
|
|
180
|
+
factValue: Number(resolvedFact === null || resolvedFact === void 0 ? void 0 : resolvedFact.value),
|
|
181
|
+
isShareRatio: isShareRatio,
|
|
182
|
+
splitVal: splitVal,
|
|
183
|
+
});
|
|
184
|
+
if (isAdjusted !== null) {
|
|
185
|
+
return isAdjusted;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if ((resolvedFact === null || resolvedFact === void 0 ? void 0 : resolvedFact.filed) > split.filedLast) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
if ((resolvedFact === null || resolvedFact === void 0 ? void 0 : resolvedFact.filed) < split.filedFirst) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
// // if the filed date of the fact overlaps with the filed date of the split, try comparing the end dates
|
|
195
|
+
if (factGroup.endLast < split.endFirst && factGroup.values.length === 1) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
// if we still don't know, see if the split value puts us closer to the last known value or further
|
|
199
|
+
if (factGroup.valuePeriodLast !== null) {
|
|
200
|
+
var val = this.getGroupValue(factGroup, isTrailing);
|
|
201
|
+
var valueWithSplit = isShareRatio ? val / splitVal : val * splitVal;
|
|
202
|
+
return Math.abs(factGroup.valuePeriodLast - val) < Math.abs(factGroup.valuePeriodLast - valueWithSplit);
|
|
203
|
+
}
|
|
204
|
+
if (factGroup.valueTrailingLast !== null) {
|
|
205
|
+
var val = this.getGroupValue(factGroup, isTrailing);
|
|
206
|
+
var valueWithSplit = isShareRatio ? val / splitVal : val * splitVal;
|
|
207
|
+
return Math.abs(factGroup.valueTrailingLast - val) < Math.abs(factGroup.valueTrailingLast - valueWithSplit);
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
};
|
|
211
|
+
FactSplitAdjuster.prototype.adjustForSplits = function (params) {
|
|
212
|
+
var factGroups = params.factGroups, splits = params.splits;
|
|
213
|
+
for (var _i = 0, factGroups_1 = factGroups; _i < factGroups_1.length; _i++) {
|
|
214
|
+
var factGroup = factGroups_1[_i];
|
|
215
|
+
var unitLower = factGroup.unit.toLowerCase();
|
|
216
|
+
if (!unitLower.includes('share'))
|
|
217
|
+
continue;
|
|
218
|
+
var isShareRatio = unitLower !== 'shares';
|
|
219
|
+
for (var _a = 0, splits_1 = splits; _a < splits_1.length; _a++) {
|
|
220
|
+
var split = splits_1[_a];
|
|
221
|
+
var factValuePeriod = this.getGroupValue(factGroup, false);
|
|
222
|
+
var factValueTrailing = this.getGroupValue(factGroup, true);
|
|
223
|
+
var splitValue = split.splitRatio;
|
|
224
|
+
if (!splitValue)
|
|
225
|
+
continue;
|
|
226
|
+
// ratios (like EPS) get divided by splits, share counts get multiplied (like shares outstanding).
|
|
227
|
+
if (!this.didApplySplit({ factGroup: factGroup, split: split, isShareRatio: isShareRatio, isTrailing: false })) {
|
|
228
|
+
factGroup.valueSplitAdjustedPeriod = isShareRatio
|
|
229
|
+
? factValuePeriod / splitValue
|
|
230
|
+
: factValuePeriod * splitValue;
|
|
231
|
+
}
|
|
232
|
+
if (!this.didApplySplit({ factGroup: factGroup, split: split, isShareRatio: isShareRatio, isTrailing: true })) {
|
|
233
|
+
factGroup.valueSplitAdjustedTrailing = isShareRatio
|
|
234
|
+
? factValueTrailing / splitValue
|
|
235
|
+
: factValueTrailing * splitValue;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
return FactSplitAdjuster;
|
|
241
|
+
}());
|
|
242
|
+
exports.default = FactSplitAdjuster;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CompanyFactListData, FactGroup, FactItem, ReportRaw, SplitData } from '../../types';
|
|
2
|
+
import FactFiscalCalculator, { SetReportDatesParams } from './FactFiscalCalculator';
|
|
3
|
+
interface BuildReportsParams {
|
|
4
|
+
facts: FactItem[];
|
|
5
|
+
/**
|
|
6
|
+
* for more accurate dates, add this. Otherwise, dates will be inferred
|
|
7
|
+
* using the fact periods. The filing and report dates can be found in the SubmissionList (segEdgarApi.getSubmissions)
|
|
8
|
+
*/
|
|
9
|
+
reportDates?: SetReportDatesParams[];
|
|
10
|
+
/**
|
|
11
|
+
* Splits will be extracted from facts if not provided.
|
|
12
|
+
*/
|
|
13
|
+
splits?: SplitData[];
|
|
14
|
+
resolvePeriodValues?: boolean;
|
|
15
|
+
adjustForSplits?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Builds ReportRaw objects from company facts. Adjusts for splits and resolves period values.
|
|
19
|
+
*/
|
|
20
|
+
export default class ReportRawBuilder {
|
|
21
|
+
private readonly factRecordBuilder;
|
|
22
|
+
createFacts(companyFacts: CompanyFactListData, includeNamePrefix?: boolean): {
|
|
23
|
+
facts: FactItem[];
|
|
24
|
+
};
|
|
25
|
+
private createFiscalCalculator;
|
|
26
|
+
buildReports(params: BuildReportsParams): ReportRaw[];
|
|
27
|
+
private createReportKey;
|
|
28
|
+
private createReport;
|
|
29
|
+
private round;
|
|
30
|
+
buildReportsFromGroups(params: {
|
|
31
|
+
factGroupsByReportKey: Map<string, FactGroup[]>;
|
|
32
|
+
fiscalCalculator: FactFiscalCalculator;
|
|
33
|
+
splits?: SplitData[];
|
|
34
|
+
minYear: number;
|
|
35
|
+
maxYear: number;
|
|
36
|
+
cik: number;
|
|
37
|
+
}): ReportRaw[];
|
|
38
|
+
}
|
|
39
|
+
export {};
|