sec-edgar-api 0.2.3 → 0.3.0
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/ReportParser/ReportParser.d.ts +6 -13
- package/build/services/ReportParser/ReportParser.js +15 -22
- 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 +81 -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 +10 -2
- package/build/services/SecEdgarApi/SecEdgarApi.js +29 -11
- package/build/types/common.type.d.ts +41 -0
- package/build/types/company-facts.type.d.ts +29 -2
- package/package.json +1 -1
- package/build/services/ReportBuilder/FactRecordBuilder.d.ts +0 -10
- package/build/services/ReportBuilder/FactSplitAdjuster.d.ts +0 -46
- package/build/services/ReportBuilder/FactSplitAdjuster.js +0 -203
- package/build/services/ReportBuilder/ReportBuilder.d.ts +0 -40
- package/build/services/ReportBuilder/ReportBuilder.js +0 -186
- 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
package/README.md
CHANGED
|
@@ -149,6 +149,7 @@ Files for mapping & resolving properties:
|
|
|
149
149
|
|
|
150
150
|
### Resources
|
|
151
151
|
|
|
152
|
+
- XBRL Taxonomies: https://xbrl.us/xbrl-taxonomy/2024-us-gaap/
|
|
152
153
|
- Validate resolved values: https://finance.yahoo.com/
|
|
153
154
|
- Financial calculations: https://www.gurufocus.com/
|
|
154
155
|
- Calculate change in working capital: https://www.oldschoolvalue.com/stock-valuation/change-in-working-capital/
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { CompanyFactListData, ReportRaw, ReportTranslated } from '../../types';
|
|
2
|
+
import ReportRawBuilder from '../ReportRawBuilder';
|
|
3
|
+
import { GetReportsRawParams } from '../SecEdgarApi';
|
|
2
4
|
import PropertyResolver from './PropertyResolver';
|
|
3
|
-
import ReportRawParser from './ReportRawParser';
|
|
4
5
|
import ReportWrapper from './ReportWrapper';
|
|
5
6
|
interface ReportParserArgs {
|
|
6
|
-
|
|
7
|
+
reportBuilder?: ReportRawBuilder;
|
|
7
8
|
propertyResolver?: PropertyResolver;
|
|
8
9
|
keyTranslator?: Record<string, string[]>;
|
|
9
10
|
}
|
|
@@ -12,28 +13,20 @@ type TranslateRawReportsCallback<T> = (report: T extends undefined ? ReportTrans
|
|
|
12
13
|
* Takes company facts data from the SEC and translates them to reports as json objects.
|
|
13
14
|
*/
|
|
14
15
|
export default class ReportParser {
|
|
15
|
-
private readonly reportRawParser;
|
|
16
16
|
private readonly keyTranslator;
|
|
17
17
|
private readonly propertyResolver;
|
|
18
|
+
private readonly reportBuilder;
|
|
18
19
|
constructor(args?: ReportParserArgs);
|
|
19
|
-
/**
|
|
20
|
-
* translates company facts to ReportTranslated. To translate to custom report, use parseReportsRaw and translateReportsRaw
|
|
21
|
-
*
|
|
22
|
-
* This includes only 10-K and 10-Q annual and quarterly reports. To include all reports, use parseReportsRaw
|
|
23
|
-
*
|
|
24
|
-
* @param companyFactListData This is the json file contents of CIK[number].json file from the SEC website. You can find these using their API or by downloading the companyfacts.zip file: https://www.sec.gov/edgar/sec-api-documentation
|
|
25
|
-
*/
|
|
26
|
-
parseReports(companyFactListData: CompanyFactListData, usePropertyResolver?: boolean): ReportWrapper[];
|
|
27
20
|
/**
|
|
28
21
|
* Same as parseReports but accepts ReportRaw[] instead of CompanyFactListData
|
|
29
22
|
*/
|
|
30
23
|
parseReportsFromRaw(reportsRaw: ReportRaw[], usePropertyResolver?: boolean): ReportWrapper[];
|
|
31
24
|
/**
|
|
32
|
-
*
|
|
25
|
+
* Parse raw reports
|
|
33
26
|
*
|
|
34
27
|
* @see https://www.sec.gov/edgar/sec-api-documentation
|
|
35
28
|
*/
|
|
36
|
-
parseReportsRaw(companyFactListData: CompanyFactListData): ReportRaw[];
|
|
29
|
+
parseReportsRaw(companyFactListData: CompanyFactListData, options?: Omit<GetReportsRawParams, 'symbol'>): ReportRaw[];
|
|
37
30
|
/**
|
|
38
31
|
* parseReportsRaw but removes meta data from the report
|
|
39
32
|
*/
|
|
@@ -1,32 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
var key_translations_1 = require("../../util/key-translations");
|
|
4
|
-
var
|
|
4
|
+
var ReportRawBuilder_1 = require("../ReportRawBuilder");
|
|
5
5
|
var PropertyResolver_1 = require("./PropertyResolver");
|
|
6
|
-
var ReportRawParser_1 = require("./ReportRawParser");
|
|
7
6
|
var ReportWrapper_1 = require("./ReportWrapper");
|
|
8
7
|
/**
|
|
9
8
|
* Takes company facts data from the SEC and translates them to reports as json objects.
|
|
10
9
|
*/
|
|
11
10
|
var ReportParser = /** @class */ (function () {
|
|
12
11
|
function ReportParser(args) {
|
|
13
|
-
var _a = args !== null && args !== void 0 ? args : {}, _b = _a.
|
|
14
|
-
this.reportRawParser = reportRawParser;
|
|
12
|
+
var _a = args !== null && args !== void 0 ? args : {}, _b = _a.propertyResolver, propertyResolver = _b === void 0 ? new PropertyResolver_1.default() : _b, _c = _a.reportBuilder, reportBuilder = _c === void 0 ? new ReportRawBuilder_1.default() : _c, _d = _a.keyTranslator, keyTranslator = _d === void 0 ? key_translations_1.default : _d;
|
|
15
13
|
this.keyTranslator = keyTranslator;
|
|
16
14
|
this.propertyResolver = propertyResolver;
|
|
15
|
+
this.reportBuilder = reportBuilder;
|
|
17
16
|
}
|
|
18
|
-
/**
|
|
19
|
-
* translates company facts to ReportTranslated. To translate to custom report, use parseReportsRaw and translateReportsRaw
|
|
20
|
-
*
|
|
21
|
-
* This includes only 10-K and 10-Q annual and quarterly reports. To include all reports, use parseReportsRaw
|
|
22
|
-
*
|
|
23
|
-
* @param companyFactListData This is the json file contents of CIK[number].json file from the SEC website. You can find these using their API or by downloading the companyfacts.zip file: https://www.sec.gov/edgar/sec-api-documentation
|
|
24
|
-
*/
|
|
25
|
-
ReportParser.prototype.parseReports = function (companyFactListData, usePropertyResolver) {
|
|
26
|
-
if (usePropertyResolver === void 0) { usePropertyResolver = true; }
|
|
27
|
-
var reportsRaw = this.reportRawParser.parseReports(companyFactListData);
|
|
28
|
-
return this.parseReportsFromRaw(reportsRaw, usePropertyResolver);
|
|
29
|
-
};
|
|
30
17
|
/**
|
|
31
18
|
* Same as parseReports but accepts ReportRaw[] instead of CompanyFactListData
|
|
32
19
|
*/
|
|
@@ -47,12 +34,19 @@ var ReportParser = /** @class */ (function () {
|
|
|
47
34
|
return reportWrappers;
|
|
48
35
|
};
|
|
49
36
|
/**
|
|
50
|
-
*
|
|
37
|
+
* Parse raw reports
|
|
51
38
|
*
|
|
52
39
|
* @see https://www.sec.gov/edgar/sec-api-documentation
|
|
53
40
|
*/
|
|
54
|
-
ReportParser.prototype.parseReportsRaw = function (companyFactListData) {
|
|
55
|
-
|
|
41
|
+
ReportParser.prototype.parseReportsRaw = function (companyFactListData, options) {
|
|
42
|
+
if (options === void 0) { options = {}; }
|
|
43
|
+
var adjustForSplits = options.adjustForSplits, resolvePeriodValues = options.resolvePeriodValues, includeNamePrefix = options.includeNamePrefix;
|
|
44
|
+
var facts = this.reportBuilder.createFacts(companyFactListData, includeNamePrefix).facts;
|
|
45
|
+
return this.reportBuilder.buildReports({
|
|
46
|
+
facts: facts,
|
|
47
|
+
adjustForSplits: adjustForSplits,
|
|
48
|
+
resolvePeriodValues: resolvePeriodValues,
|
|
49
|
+
});
|
|
56
50
|
};
|
|
57
51
|
/**
|
|
58
52
|
* parseReportsRaw but removes meta data from the report
|
|
@@ -82,14 +76,13 @@ var ReportParser = /** @class */ (function () {
|
|
|
82
76
|
var reports = [];
|
|
83
77
|
reportsRaw.forEach(function (report) {
|
|
84
78
|
var reportNew = {};
|
|
85
|
-
var reportRaw = new ReportRawResolvable_1.default(report);
|
|
86
79
|
// iterate translation keys, ensuring same order and priority
|
|
87
80
|
for (var key in keyTranslations) {
|
|
88
81
|
var keysRaw = keyTranslations[key];
|
|
89
82
|
reportNew[key] = null;
|
|
90
83
|
for (var _i = 0, keysRaw_1 = keysRaw; _i < keysRaw_1.length; _i++) {
|
|
91
84
|
var keyRaw = keysRaw_1[_i];
|
|
92
|
-
var value =
|
|
85
|
+
var value = report[keyRaw];
|
|
93
86
|
if (value === undefined)
|
|
94
87
|
continue;
|
|
95
88
|
reportNew[key] = value;
|
|
@@ -97,7 +90,7 @@ var ReportParser = /** @class */ (function () {
|
|
|
97
90
|
}
|
|
98
91
|
}
|
|
99
92
|
var reportFiltered = callback
|
|
100
|
-
? callback(reportNew,
|
|
93
|
+
? callback(reportNew, report, keyTranslations)
|
|
101
94
|
: reportNew;
|
|
102
95
|
reports.push(reportFiltered);
|
|
103
96
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FactItem, FactGroup, SplitData } from '../../types';
|
|
2
|
+
import FactFiscalCalculator from './FactFiscalCalculator';
|
|
3
|
+
/**
|
|
4
|
+
* There are many facts properties for the same period but filed at different times.
|
|
5
|
+
* This groups those together and resolves the period and trailing values for each group.
|
|
6
|
+
*/
|
|
7
|
+
export default class FactGrouper {
|
|
8
|
+
private preferFirstValue;
|
|
9
|
+
private createFactGroup;
|
|
10
|
+
private createGroupKey;
|
|
11
|
+
/**
|
|
12
|
+
* Map structure { 2022_Q3: { name: ... } }. NOTE: Does not include fiscal year report key.
|
|
13
|
+
* All groups contain both trailing and period values, so use trailing from Q4 to get FY values.
|
|
14
|
+
*/
|
|
15
|
+
buildFactGroupsByReportKey(params: {
|
|
16
|
+
facts: FactItem[];
|
|
17
|
+
splits?: SplitData[];
|
|
18
|
+
cik: number;
|
|
19
|
+
fiscalCalculator: FactFiscalCalculator;
|
|
20
|
+
resolvePeriodValues: boolean;
|
|
21
|
+
generateMissingGroups?: boolean;
|
|
22
|
+
}): {
|
|
23
|
+
factGroupsByReportKey: Map<string, FactGroup[]>;
|
|
24
|
+
minYear: number;
|
|
25
|
+
maxYear: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
var FactPeriodResolver_1 = require("./FactPeriodResolver");
|
|
15
|
+
var FactSplitAdjuster_1 = require("./FactSplitAdjuster");
|
|
16
|
+
/**
|
|
17
|
+
* There are many facts properties for the same period but filed at different times.
|
|
18
|
+
* This groups those together and resolves the period and trailing values for each group.
|
|
19
|
+
*/
|
|
20
|
+
var FactGrouper = /** @class */ (function () {
|
|
21
|
+
function FactGrouper() {
|
|
22
|
+
this.preferFirstValue = true;
|
|
23
|
+
}
|
|
24
|
+
FactGrouper.prototype.createFactGroup = function (params) {
|
|
25
|
+
return __assign({ name: '', unit: '', reportEnd: '', accn: '', reportFiled: '', isResolverGenerated: true, fiscalYear: 0, quarter: 0, filedFirst: '', filedLast: '', endFirst: '', endLast: '', valuePeriodFirst: null, valuePeriodLast: null, valueTrailingFirst: null, valueTrailingLast: null, valuePeriodResolved: null, valueTrailingResolved: null, valueSplitAdjustedPeriod: null, valueSplitAdjustedTrailing: null, values: [], facts: [] }, params);
|
|
26
|
+
};
|
|
27
|
+
FactGrouper.prototype.createGroupKey = function (params) {
|
|
28
|
+
var fiscalYear = params.fiscalYear, quarter = params.quarter, name = params.name;
|
|
29
|
+
return "".concat(fiscalYear, "_").concat(quarter, "_").concat(name);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Map structure { 2022_Q3: { name: ... } }. NOTE: Does not include fiscal year report key.
|
|
33
|
+
* All groups contain both trailing and period values, so use trailing from Q4 to get FY values.
|
|
34
|
+
*/
|
|
35
|
+
FactGrouper.prototype.buildFactGroupsByReportKey = function (params) {
|
|
36
|
+
var _this = this;
|
|
37
|
+
var _a, _b, _c;
|
|
38
|
+
var facts = params.facts, cik = params.cik, fiscalCalculator = params.fiscalCalculator, resolvePeriodValues = params.resolvePeriodValues, _d = params.generateMissingGroups, generateMissingGroups = _d === void 0 ? false : _d, splits = params.splits;
|
|
39
|
+
// min and max year will be used to sort the reports
|
|
40
|
+
var minYear = 0;
|
|
41
|
+
var maxYear = 9999;
|
|
42
|
+
var factGroupByKey = new Map();
|
|
43
|
+
var periodResolver = new FactPeriodResolver_1.default({ cik: cik });
|
|
44
|
+
var factSplitAdjuster = new FactSplitAdjuster_1.default();
|
|
45
|
+
// used for groups that need to be generated without using a fact
|
|
46
|
+
var unitByPropertyName = new Map();
|
|
47
|
+
var accnByFiled = new Map();
|
|
48
|
+
// Create groups from facts.
|
|
49
|
+
for (var _i = 0, facts_1 = facts; _i < facts_1.length; _i++) {
|
|
50
|
+
var fact = facts_1[_i];
|
|
51
|
+
var _e = fiscalCalculator.getFiscalYearQuarter({ dateStr: fact.end }), quarter = _e.quarter, year = _e.year;
|
|
52
|
+
var _f = (_a = fiscalCalculator.getDatesByYearQuarter({ quarter: quarter, year: year })) !== null && _a !== void 0 ? _a : {}, _g = _f.end, reportEnd = _g === void 0 ? '' : _g, _h = _f.filed, reportFiled = _h === void 0 ? '' : _h;
|
|
53
|
+
var groupKey = this.createGroupKey({ fiscalYear: year, quarter: quarter, name: fact.name });
|
|
54
|
+
if (year < minYear)
|
|
55
|
+
minYear = year;
|
|
56
|
+
if (year > maxYear)
|
|
57
|
+
maxYear = year;
|
|
58
|
+
// period checks to see if the fact needs to be resolved for quarterly or trailing values
|
|
59
|
+
var period = periodResolver.getPeriod(fact);
|
|
60
|
+
var isPeriodFact = period <= 3;
|
|
61
|
+
var isTrailingFact = period > 3 || (isPeriodFact && quarter === 1);
|
|
62
|
+
var factValue = Number(fact.value);
|
|
63
|
+
// if no group exists, create from fact
|
|
64
|
+
if (!factGroupByKey.has(groupKey)) {
|
|
65
|
+
var group_1 = this.createFactGroup({
|
|
66
|
+
name: fact.name,
|
|
67
|
+
accn: periodResolver.isOriginalFiling({ end: fact.end, filed: fact.filed }) ? fact.accn : '',
|
|
68
|
+
unit: fact.unit,
|
|
69
|
+
reportEnd: reportEnd,
|
|
70
|
+
reportFiled: reportFiled,
|
|
71
|
+
isResolverGenerated: false,
|
|
72
|
+
fiscalYear: year,
|
|
73
|
+
quarter: quarter,
|
|
74
|
+
filedFirst: fact.filed,
|
|
75
|
+
filedLast: fact.filed,
|
|
76
|
+
endFirst: fact.end,
|
|
77
|
+
endLast: fact.end,
|
|
78
|
+
valuePeriodFirst: isPeriodFact ? factValue : null,
|
|
79
|
+
valuePeriodLast: isPeriodFact ? factValue : null,
|
|
80
|
+
valueTrailingFirst: isTrailingFact ? factValue : null,
|
|
81
|
+
valueTrailingLast: isTrailingFact ? factValue : null,
|
|
82
|
+
values: [factValue],
|
|
83
|
+
facts: [fact],
|
|
84
|
+
});
|
|
85
|
+
accnByFiled.set(fact.filed, (_b = fact.accn) !== null && _b !== void 0 ? _b : '');
|
|
86
|
+
unitByPropertyName.set(fact.name, fact.unit);
|
|
87
|
+
factGroupByKey.set(groupKey, group_1);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// if group already exists, update values
|
|
91
|
+
var group = factGroupByKey.get(groupKey);
|
|
92
|
+
group.facts.push(fact);
|
|
93
|
+
group.endFirst = fact.end < group.endFirst ? fact.end : group.endFirst;
|
|
94
|
+
group.endLast = fact.end > group.endLast ? fact.end : group.endLast;
|
|
95
|
+
group.filedFirst = fact.filed < group.filedFirst ? fact.filed : group.filedFirst;
|
|
96
|
+
group.filedLast = fact.filed > group.filedLast ? fact.filed : group.filedLast;
|
|
97
|
+
if (!group.values.includes(factValue)) {
|
|
98
|
+
group.values.push(factValue);
|
|
99
|
+
}
|
|
100
|
+
if (!group.accn && periodResolver.isOriginalFiling({ end: fact.end, filed: fact.filed })) {
|
|
101
|
+
group.accn = (_c = fact.accn) !== null && _c !== void 0 ? _c : '';
|
|
102
|
+
accnByFiled.set(fact.filed, group.accn);
|
|
103
|
+
}
|
|
104
|
+
if (isPeriodFact) {
|
|
105
|
+
if (group.valuePeriodFirst === null) {
|
|
106
|
+
group.valuePeriodFirst = factValue;
|
|
107
|
+
}
|
|
108
|
+
if (factValue !== group.valuePeriodFirst && factValue !== group.valuePeriodLast) {
|
|
109
|
+
group.valuePeriodLast = factValue;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (isTrailingFact) {
|
|
113
|
+
if (group.valueTrailingFirst === null) {
|
|
114
|
+
group.valueTrailingFirst = factValue;
|
|
115
|
+
}
|
|
116
|
+
if (factValue !== group.valueTrailingFirst && factValue !== group.valueTrailingLast) {
|
|
117
|
+
group.valueTrailingLast = factValue;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// adjust for splits
|
|
122
|
+
var factGroupsByReportKey = new Map();
|
|
123
|
+
if (splits) {
|
|
124
|
+
factSplitAdjuster.adjustForSplits({
|
|
125
|
+
factGroups: Array.from(factGroupByKey.values()),
|
|
126
|
+
splits: splits,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
factGroupByKey.forEach(function (group) {
|
|
130
|
+
var _a, _b;
|
|
131
|
+
// add to the period resolver to resolve quarterly and trailing values
|
|
132
|
+
var preferredValuePeriod = _this.preferFirstValue ? group.valuePeriodLast : group.valuePeriodLast;
|
|
133
|
+
var preferredValueTrailing = _this.preferFirstValue ? group.valueTrailingFirst : group.valueTrailingLast;
|
|
134
|
+
var selectedFactPeriod = group.facts.find(function (fact) {
|
|
135
|
+
var period = FactPeriodResolver_1.default.getPeriod(fact);
|
|
136
|
+
return fact.value === preferredValuePeriod && period <= 3;
|
|
137
|
+
});
|
|
138
|
+
var selectedFactTrailing = group.facts.find(function (fact) {
|
|
139
|
+
var period = FactPeriodResolver_1.default.getPeriod(fact);
|
|
140
|
+
return fact.value === preferredValueTrailing && (period > 3 || period === 0);
|
|
141
|
+
});
|
|
142
|
+
if (selectedFactPeriod) {
|
|
143
|
+
periodResolver.add({
|
|
144
|
+
end: selectedFactPeriod.end,
|
|
145
|
+
filed: selectedFactPeriod.filed,
|
|
146
|
+
name: selectedFactPeriod.name,
|
|
147
|
+
quarter: group.quarter,
|
|
148
|
+
value: Number((_a = group.valueSplitAdjustedPeriod) !== null && _a !== void 0 ? _a : preferredValuePeriod),
|
|
149
|
+
year: group.fiscalYear,
|
|
150
|
+
start: selectedFactPeriod.start,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (selectedFactTrailing) {
|
|
154
|
+
periodResolver.add({
|
|
155
|
+
end: selectedFactTrailing.end,
|
|
156
|
+
filed: selectedFactTrailing.filed,
|
|
157
|
+
name: selectedFactTrailing.name,
|
|
158
|
+
quarter: group.quarter,
|
|
159
|
+
value: Number((_b = group.valueSplitAdjustedTrailing) !== null && _b !== void 0 ? _b : preferredValueTrailing),
|
|
160
|
+
year: group.fiscalYear,
|
|
161
|
+
start: selectedFactTrailing.start,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// Resolve quarterly and trailing values, and if no facts present for a certain period, create a group with resolved values.
|
|
166
|
+
periodResolver.forEach(function (_a) {
|
|
167
|
+
var _b, _c, _d, _e, _f, _g;
|
|
168
|
+
var propertyName = _a.propertyName, quarter = _a.quarter, valueQuarter = _a.valueQuarter, valueTrailing = _a.valueTrailing, year = _a.year;
|
|
169
|
+
var groupKey = _this.createGroupKey({ fiscalYear: year, name: propertyName, quarter: quarter });
|
|
170
|
+
var group = factGroupByKey.get(groupKey);
|
|
171
|
+
if (!group && (!resolvePeriodValues || !generateMissingGroups))
|
|
172
|
+
return;
|
|
173
|
+
var _h = (_b = fiscalCalculator.getDatesByYearQuarter({ quarter: quarter, year: year })) !== null && _b !== void 0 ? _b : { end: '', filed: '' }, end = _h.end, filed = _h.filed;
|
|
174
|
+
var reportKey = "".concat(year, "_Q").concat(quarter);
|
|
175
|
+
var bucket = (_c = factGroupsByReportKey.get(reportKey)) !== null && _c !== void 0 ? _c : factGroupsByReportKey.set(reportKey, []).get(reportKey);
|
|
176
|
+
if (!group) {
|
|
177
|
+
group = _this.createFactGroup({
|
|
178
|
+
reportEnd: end,
|
|
179
|
+
reportFiled: filed,
|
|
180
|
+
endFirst: end,
|
|
181
|
+
endLast: end,
|
|
182
|
+
name: propertyName,
|
|
183
|
+
accn: (_d = accnByFiled.get(filed)) !== null && _d !== void 0 ? _d : '',
|
|
184
|
+
unit: (_e = unitByPropertyName.get(propertyName)) !== null && _e !== void 0 ? _e : '',
|
|
185
|
+
isResolverGenerated: true,
|
|
186
|
+
fiscalYear: year,
|
|
187
|
+
quarter: quarter,
|
|
188
|
+
valuePeriodResolved: valueQuarter,
|
|
189
|
+
valueTrailingResolved: valueTrailing,
|
|
190
|
+
});
|
|
191
|
+
factGroupByKey.set(groupKey, group);
|
|
192
|
+
}
|
|
193
|
+
else if (resolvePeriodValues) {
|
|
194
|
+
var shouldUseTrailingForQuarter = FactPeriodResolver_1.default.isAverageShares({ propertyName: group.name }) && group.quarter === 4;
|
|
195
|
+
group.valuePeriodResolved = shouldUseTrailingForQuarter ? valueTrailing : valueQuarter;
|
|
196
|
+
group.valueTrailingResolved = valueTrailing;
|
|
197
|
+
(_f = group.valuePeriodFirst) !== null && _f !== void 0 ? _f : (group.valuePeriodFirst = shouldUseTrailingForQuarter ? valueTrailing : valueQuarter);
|
|
198
|
+
(_g = group.valueTrailingFirst) !== null && _g !== void 0 ? _g : (group.valueTrailingFirst = valueTrailing);
|
|
199
|
+
}
|
|
200
|
+
bucket.push(group);
|
|
201
|
+
});
|
|
202
|
+
return { factGroupsByReportKey: factGroupsByReportKey, minYear: minYear, maxYear: maxYear };
|
|
203
|
+
};
|
|
204
|
+
return FactGrouper;
|
|
205
|
+
}());
|
|
206
|
+
exports.default = FactGrouper;
|
|
@@ -17,17 +17,59 @@ export default class FactPeriodResolver {
|
|
|
17
17
|
private readonly propertiesByYear;
|
|
18
18
|
/** prevent values from being added multiple times */
|
|
19
19
|
private readonly resolvedValues;
|
|
20
|
+
private readonly unresolvedReports;
|
|
20
21
|
private readonly cik;
|
|
22
|
+
private readonly preferOriginalFilingValues;
|
|
21
23
|
constructor(args: {
|
|
22
24
|
cik: number;
|
|
25
|
+
preferOriginalFilingValues?: boolean;
|
|
23
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
|
+
static isAverageShares(params: {
|
|
37
|
+
propertyName: string;
|
|
38
|
+
}): boolean;
|
|
39
|
+
private isAverageShares;
|
|
40
|
+
/**
|
|
41
|
+
* Used to check if this should potentially overwrite a value that has already been set.
|
|
42
|
+
*/
|
|
43
|
+
private isPreferredValue;
|
|
24
44
|
private getOrSetBucketArr;
|
|
25
45
|
private addPropertyByYear;
|
|
26
46
|
resolveValues(propertyName: string, year: number): void;
|
|
27
47
|
get(propertyName: string, year: number, fiscalPeriod: FiscalPeriod): number | undefined;
|
|
28
48
|
private getPropertyBuckets;
|
|
29
|
-
|
|
49
|
+
/**
|
|
50
|
+
* 0, 3, 6, 9, or 12 month period. 0 is instantaneous data that doesn't have a time period, (ex: assets)
|
|
51
|
+
* other facts have values that are for a period of time. (like revenue over the last 6 months).
|
|
52
|
+
*
|
|
53
|
+
* Use periods 0 and 3 for quarterly reports and 0 and 12 for annual reports.
|
|
54
|
+
*/
|
|
55
|
+
static getPeriod(params: {
|
|
56
|
+
start?: string;
|
|
57
|
+
end: string;
|
|
58
|
+
}): 0 | 3 | 6 | 12 | 9;
|
|
59
|
+
getPeriod(params: {
|
|
60
|
+
start?: string;
|
|
61
|
+
end: string;
|
|
62
|
+
}): 0 | 3 | 6 | 12 | 9;
|
|
30
63
|
private getOrSetReport;
|
|
64
|
+
/**
|
|
65
|
+
* True if the filed date is within 60 days of the end date. This indicates that it is likely
|
|
66
|
+
* the original filing of the fact because filers are required to submit within 45 days of the
|
|
67
|
+
* period end, and subsequent reports are filed 90 days apart.
|
|
68
|
+
*/
|
|
69
|
+
isOriginalFiling(params: {
|
|
70
|
+
end: string;
|
|
71
|
+
filed: string;
|
|
72
|
+
}): boolean;
|
|
31
73
|
add(params: {
|
|
32
74
|
year: number;
|
|
33
75
|
quarter: number;
|
|
@@ -37,12 +79,14 @@ export default class FactPeriodResolver {
|
|
|
37
79
|
name: string;
|
|
38
80
|
filed: string;
|
|
39
81
|
}): void;
|
|
40
|
-
private readonly unresolvedReports;
|
|
41
82
|
private buildUnresolvedReports;
|
|
42
83
|
forEach(callback: (params: {
|
|
43
84
|
year: number;
|
|
44
85
|
fiscalPeriod: FiscalPeriod;
|
|
45
86
|
propertyName: string;
|
|
46
87
|
value: number | string;
|
|
88
|
+
valueQuarter: number;
|
|
89
|
+
valueTrailing: number;
|
|
90
|
+
quarter: number;
|
|
47
91
|
}) => void): void;
|
|
48
92
|
}
|
|
@@ -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,33 @@ 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('WeightedAverage') && propertyName.includes('SharesOutstanding');
|
|
39
|
+
};
|
|
40
|
+
FactPeriodResolver.prototype.isAverageShares = function (params) {
|
|
41
|
+
return FactPeriodResolver.isAverageShares(params);
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Used to check if this should potentially overwrite a value that has already been set.
|
|
45
|
+
*/
|
|
46
|
+
FactPeriodResolver.prototype.isPreferredValue = function (params) {
|
|
47
|
+
var bucket = params.bucket, end = params.end, filed = params.filed, bucketIndex = params.bucketIndex;
|
|
48
|
+
return !bucket.has(bucketIndex) || this.preferOriginalFilingValues || !this.isOriginalFiling({ end: end, filed: filed });
|
|
49
|
+
};
|
|
27
50
|
FactPeriodResolver.prototype.getOrSetBucketArr = function (map, year, propertyName) {
|
|
28
51
|
var _a, _b;
|
|
29
52
|
var propertyMap = (_a = map.get(year)) !== null && _a !== void 0 ? _a : map.set(year, new Map()).get(year);
|
|
@@ -49,8 +72,8 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
49
72
|
var reportKey = "".concat(year, "_").concat(i + 1);
|
|
50
73
|
var unresolvedReport = this.unresolvedReports.get(reportKey);
|
|
51
74
|
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
|
|
75
|
+
var sumValue = (_b = unresolvedReport === null || unresolvedReport === void 0 ? void 0 : unresolvedReport[propertyName]) !== null && _b !== void 0 ? _b : 0;
|
|
76
|
+
var prevSum = (_c = unresolvedReportPrev === null || unresolvedReportPrev === void 0 ? void 0 : unresolvedReportPrev[propertyName]) !== null && _c !== void 0 ? _c : 0;
|
|
54
77
|
if (quarterValue === undefined) {
|
|
55
78
|
var bucketQuarter_1 = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
|
|
56
79
|
bucketQuarter_1.set(i, (Number(sumValue) || 0) - (Number(prevSum) || 0));
|
|
@@ -82,7 +105,13 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
82
105
|
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
106
|
return { bucketQuarter: bucketQuarter, bucketSum: bucketSum, bucketString: bucketString };
|
|
84
107
|
};
|
|
85
|
-
|
|
108
|
+
/**
|
|
109
|
+
* 0, 3, 6, 9, or 12 month period. 0 is instantaneous data that doesn't have a time period, (ex: assets)
|
|
110
|
+
* other facts have values that are for a period of time. (like revenue over the last 6 months).
|
|
111
|
+
*
|
|
112
|
+
* Use periods 0 and 3 for quarterly reports and 0 and 12 for annual reports.
|
|
113
|
+
*/
|
|
114
|
+
FactPeriodResolver.getPeriod = function (params) {
|
|
86
115
|
var start = params.start, end = params.end;
|
|
87
116
|
if (!start || start === end)
|
|
88
117
|
return 0;
|
|
@@ -96,11 +125,14 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
96
125
|
return 9;
|
|
97
126
|
return 12;
|
|
98
127
|
};
|
|
128
|
+
FactPeriodResolver.prototype.getPeriod = function (params) {
|
|
129
|
+
return FactPeriodResolver.getPeriod(params);
|
|
130
|
+
};
|
|
99
131
|
FactPeriodResolver.prototype.getOrSetReport = function (params) {
|
|
100
132
|
var _a;
|
|
101
133
|
var year = params.year, quarter = params.quarter;
|
|
102
134
|
var key = "".concat(year, "_").concat(quarter);
|
|
103
|
-
var report = (_a = this.unresolvedReports.get(key)) !== null && _a !== void 0 ? _a :
|
|
135
|
+
var report = (_a = this.unresolvedReports.get(key)) !== null && _a !== void 0 ? _a : {
|
|
104
136
|
cik: this.cik,
|
|
105
137
|
fiscalYear: year,
|
|
106
138
|
fiscalPeriod: quarter === 4 ? 'FY' : "Q".concat(quarter),
|
|
@@ -109,35 +141,54 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
109
141
|
url: null,
|
|
110
142
|
splitDate: null,
|
|
111
143
|
splitRatio: null,
|
|
112
|
-
}
|
|
144
|
+
};
|
|
113
145
|
if (!this.unresolvedReports.has(key)) {
|
|
114
146
|
this.unresolvedReports.set(key, report);
|
|
115
147
|
}
|
|
116
148
|
return report;
|
|
117
149
|
};
|
|
150
|
+
/**
|
|
151
|
+
* True if the filed date is within 60 days of the end date. This indicates that it is likely
|
|
152
|
+
* the original filing of the fact because filers are required to submit within 45 days of the
|
|
153
|
+
* period end, and subsequent reports are filed 90 days apart.
|
|
154
|
+
*/
|
|
155
|
+
FactPeriodResolver.prototype.isOriginalFiling = function (params) {
|
|
156
|
+
var end = params.end, filed = params.filed;
|
|
157
|
+
var DAY_60_MS = 5184000000;
|
|
158
|
+
return new Date(filed).getTime() - new Date(end).getTime() < DAY_60_MS;
|
|
159
|
+
};
|
|
118
160
|
FactPeriodResolver.prototype.add = function (params) {
|
|
119
161
|
var year = params.year, value = params.value, propertyName = params.name, quarter = params.quarter, start = params.start, end = params.end, filed = params.filed;
|
|
120
|
-
var
|
|
162
|
+
var bucketIndex = quarter - 1;
|
|
163
|
+
var period = this.isAverageShares({ propertyName: propertyName }) ? 0 : this.getPeriod({ start: start, end: end });
|
|
121
164
|
this.addPropertyByYear(this.propertiesByYear, year, propertyName);
|
|
122
165
|
if (typeof value === 'string') {
|
|
123
166
|
var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYearString, year, propertyName);
|
|
124
|
-
|
|
167
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
168
|
+
bucket.set(bucketIndex, value);
|
|
169
|
+
}
|
|
125
170
|
return;
|
|
126
171
|
}
|
|
127
172
|
if (period === 0) {
|
|
128
173
|
var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
|
|
129
174
|
var bucketSum = this.getOrSetBucketArr(this.sumByQuarterByPropertyByYear, year, propertyName);
|
|
130
|
-
|
|
131
|
-
|
|
175
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
176
|
+
bucket.set(bucketIndex, value);
|
|
177
|
+
bucketSum.set(bucketIndex, value);
|
|
178
|
+
}
|
|
132
179
|
return;
|
|
133
180
|
}
|
|
134
181
|
if (period === 3) {
|
|
135
182
|
var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
|
|
136
|
-
|
|
183
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
184
|
+
bucket.set(bucketIndex, value);
|
|
185
|
+
}
|
|
137
186
|
}
|
|
138
187
|
if (quarter === 1 || period > 3) {
|
|
139
188
|
var bucket = this.getOrSetBucketArr(this.sumByQuarterByPropertyByYear, year, propertyName);
|
|
140
|
-
|
|
189
|
+
if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
|
|
190
|
+
bucket.set(bucketIndex, value);
|
|
191
|
+
}
|
|
141
192
|
}
|
|
142
193
|
this.addPropertyByYear(this.propertiesResolvableByYear, year, propertyName);
|
|
143
194
|
};
|
|
@@ -163,7 +214,7 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
163
214
|
if (value === undefined)
|
|
164
215
|
continue;
|
|
165
216
|
var report = _this.getOrSetReport({ year: year, quarter: i + 1 });
|
|
166
|
-
report
|
|
217
|
+
report[propertyName] = value;
|
|
167
218
|
}
|
|
168
219
|
});
|
|
169
220
|
});
|
|
@@ -173,14 +224,24 @@ var FactPeriodResolver = /** @class */ (function () {
|
|
|
173
224
|
this.buildUnresolvedReports();
|
|
174
225
|
this.propertiesByYear.forEach(function (properties, year) {
|
|
175
226
|
properties.forEach(function (propertyName) {
|
|
176
|
-
var _a;
|
|
227
|
+
var _a, _b;
|
|
177
228
|
_this.resolveValues(propertyName, year);
|
|
178
|
-
for (var i = 0; i <
|
|
229
|
+
for (var i = 0; i < 4; i++) {
|
|
179
230
|
var isAnnual = i === 4;
|
|
180
|
-
var
|
|
181
|
-
var
|
|
182
|
-
var
|
|
183
|
-
|
|
231
|
+
var _c = _this.getPropertyBuckets(year, propertyName), bucketQuarter = _c.bucketQuarter, bucketSum = _c.bucketSum, bucketString = _c.bucketString;
|
|
232
|
+
var valueQuarter = (_a = bucketQuarter.get(i)) !== null && _a !== void 0 ? _a : bucketString.get(i);
|
|
233
|
+
var valueTrailing = bucketSum.get(i);
|
|
234
|
+
var value = (_b = (isAnnual ? bucketSum.get(3) : bucketQuarter.get(i))) !== null && _b !== void 0 ? _b : bucketString.get(i);
|
|
235
|
+
var quarter = i + 1;
|
|
236
|
+
callback({
|
|
237
|
+
year: year,
|
|
238
|
+
fiscalPeriod: "Q".concat(quarter),
|
|
239
|
+
propertyName: propertyName,
|
|
240
|
+
value: value,
|
|
241
|
+
quarter: quarter,
|
|
242
|
+
valueQuarter: valueQuarter,
|
|
243
|
+
valueTrailing: valueTrailing,
|
|
244
|
+
});
|
|
184
245
|
}
|
|
185
246
|
});
|
|
186
247
|
});
|