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
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/
|
|
@@ -13,5 +13,17 @@ export default class DocumentParser {
|
|
|
13
13
|
parseForm13g(params: XMLParams): import("../../types").Form13GData;
|
|
14
14
|
parseForm10k(params: XMLParams): import("../../types").Form10KData;
|
|
15
15
|
parseFormDef14a(params: XMLParams): import("../../types").FormDef14aData;
|
|
16
|
+
parseCurrentFilingsDaily(params: XMLParams): {
|
|
17
|
+
date: string;
|
|
18
|
+
matchCount: number;
|
|
19
|
+
totalCount: number;
|
|
20
|
+
entries: {
|
|
21
|
+
accessionNumber: string;
|
|
22
|
+
form: string;
|
|
23
|
+
companyCik: number;
|
|
24
|
+
companyName: string;
|
|
25
|
+
filedDate: string;
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
16
28
|
}
|
|
17
29
|
export {};
|
|
@@ -20,6 +20,9 @@ var DocumentParser = /** @class */ (function () {
|
|
|
20
20
|
DocumentParser.prototype.parseFormDef14a = function (params) {
|
|
21
21
|
return this.parsersByName.parseFormDef14a(params, this.parser);
|
|
22
22
|
};
|
|
23
|
+
DocumentParser.prototype.parseCurrentFilingsDaily = function (params) {
|
|
24
|
+
return this.parsersByName.parseCurrentFilingsDaily(params);
|
|
25
|
+
};
|
|
23
26
|
return DocumentParser;
|
|
24
27
|
}());
|
|
25
28
|
exports.default = DocumentParser;
|
|
@@ -2,10 +2,12 @@ import { parseForm4 } from './parse-form-4';
|
|
|
2
2
|
import { parseForm13g } from './parse-form-13g';
|
|
3
3
|
import { parseForm10k } from './parse-form-10k';
|
|
4
4
|
import { parseFormDef14a } from './parse-form-def14a';
|
|
5
|
+
import { parseCurrentFilingsDaily } from './parse-current-filings-daily';
|
|
5
6
|
declare const parsers: {
|
|
6
7
|
parseForm4: typeof parseForm4;
|
|
7
8
|
parseForm13g: typeof parseForm13g;
|
|
8
9
|
parseForm10k: typeof parseForm10k;
|
|
9
10
|
parseFormDef14a: typeof parseFormDef14a;
|
|
11
|
+
parseCurrentFilingsDaily: typeof parseCurrentFilingsDaily;
|
|
10
12
|
};
|
|
11
13
|
export default parsers;
|
|
@@ -4,10 +4,12 @@ var parse_form_4_1 = require("./parse-form-4");
|
|
|
4
4
|
var parse_form_13g_1 = require("./parse-form-13g");
|
|
5
5
|
var parse_form_10k_1 = require("./parse-form-10k");
|
|
6
6
|
var parse_form_def14a_1 = require("./parse-form-def14a");
|
|
7
|
+
var parse_current_filings_daily_1 = require("./parse-current-filings-daily");
|
|
7
8
|
var parsers = {
|
|
8
9
|
parseForm4: parse_form_4_1.parseForm4,
|
|
9
10
|
parseForm13g: parse_form_13g_1.parseForm13g,
|
|
10
11
|
parseForm10k: parse_form_10k_1.parseForm10k,
|
|
11
12
|
parseFormDef14a: parse_form_def14a_1.parseFormDef14a,
|
|
13
|
+
parseCurrentFilingsDaily: parse_current_filings_daily_1.parseCurrentFilingsDaily,
|
|
12
14
|
};
|
|
13
15
|
exports.default = parsers;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { XMLParams } from '../../../types';
|
|
2
|
+
export declare function parseCurrentFilingsDaily(params: XMLParams): {
|
|
3
|
+
date: string;
|
|
4
|
+
matchCount: number;
|
|
5
|
+
totalCount: number;
|
|
6
|
+
entries: {
|
|
7
|
+
accessionNumber: string;
|
|
8
|
+
form: string;
|
|
9
|
+
companyCik: number;
|
|
10
|
+
companyName: string;
|
|
11
|
+
filedDate: string;
|
|
12
|
+
}[];
|
|
13
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseCurrentFilingsDaily = void 0;
|
|
4
|
+
function parseCurrentFilingsDaily(params) {
|
|
5
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
6
|
+
var xml = params.xml;
|
|
7
|
+
var csv = (_a = xml.split('<hr>')[1]) !== null && _a !== void 0 ? _a : '';
|
|
8
|
+
var lines = csv.split('\n').slice(0, -1);
|
|
9
|
+
var _k = (_b = xml.match(/<strong>.{1,20}?<\/strong>/g)) !== null && _b !== void 0 ? _b : [], _l = _k[0], matchHtml = _l === void 0 ? '' : _l, _m = _k[1], totalHtml = _m === void 0 ? '' : _m;
|
|
10
|
+
var date = (_e = (_d = (_c = xml.split('of matches for')) === null || _c === void 0 ? void 0 : _c[1].split('is', 1)) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.trim();
|
|
11
|
+
var matchCount = Number((_g = (_f = matchHtml.split('>')[1]) === null || _f === void 0 ? void 0 : _f.split('<')[0]) === null || _g === void 0 ? void 0 : _g.trim()) || 0;
|
|
12
|
+
var totalCount = Number((_j = (_h = totalHtml.split('>')[1]) === null || _h === void 0 ? void 0 : _h.split('<')[0]) === null || _j === void 0 ? void 0 : _j.trim()) || 0;
|
|
13
|
+
var entries = lines.map(function (line) {
|
|
14
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
15
|
+
var parts = line.split('<a ');
|
|
16
|
+
var partDate = (_a = parts[0]) !== null && _a !== void 0 ? _a : '';
|
|
17
|
+
var partNameCik = (_b = parts[parts.length - 1]) !== null && _b !== void 0 ? _b : '';
|
|
18
|
+
var partAccessionForm = (_f = (_e = (_d = ((_c = parts[1]) !== null && _c !== void 0 ? _c : '').split('/Archives/edgar/data/')[1]) === null || _d === void 0 ? void 0 : _d.split('/')) === null || _e === void 0 ? void 0 : _e[1]) !== null && _f !== void 0 ? _f : '';
|
|
19
|
+
var partNameCikParts = partNameCik.split('</a>');
|
|
20
|
+
var _q = partAccessionForm === null || partAccessionForm === void 0 ? void 0 : partAccessionForm.split('>'), accession = _q[0], formUnfiltered = _q[1];
|
|
21
|
+
var accessionNumber = ((_g = accession === null || accession === void 0 ? void 0 : accession.substring(0, accession.lastIndexOf('-'))) !== null && _g !== void 0 ? _g : '').trim();
|
|
22
|
+
var form = ((_h = formUnfiltered === null || formUnfiltered === void 0 ? void 0 : formUnfiltered.replace(/</g, '')) !== null && _h !== void 0 ? _h : '').trim();
|
|
23
|
+
var companyCik = Number((_l = (_k = (_j = partNameCikParts[0]) === null || _j === void 0 ? void 0 : _j.split('>')[1]) === null || _k === void 0 ? void 0 : _k.trim()) !== null && _l !== void 0 ? _l : '');
|
|
24
|
+
var companyName = (_o = (_m = partNameCikParts[1]) === null || _m === void 0 ? void 0 : _m.trim()) !== null && _o !== void 0 ? _o : '';
|
|
25
|
+
var filedDate = (_p = partDate.trim()) !== null && _p !== void 0 ? _p : '';
|
|
26
|
+
var _r = filedDate.split('-'), month = _r[0], day = _r[1], year = _r[2];
|
|
27
|
+
return {
|
|
28
|
+
accessionNumber: accessionNumber,
|
|
29
|
+
form: form,
|
|
30
|
+
companyCik: companyCik,
|
|
31
|
+
companyName: companyName,
|
|
32
|
+
filedDate: "".concat(year, "-").concat(month, "-").concat(day),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return { date: date, matchCount: matchCount, totalCount: totalCount, entries: entries };
|
|
36
|
+
}
|
|
37
|
+
exports.parseCurrentFilingsDaily = parseCurrentFilingsDaily;
|
|
@@ -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,23 @@ 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
|
-
parseReportsFromRaw(
|
|
23
|
+
parseReportsFromRaw(params: {
|
|
24
|
+
reportsRaw: ReportRaw[];
|
|
25
|
+
usePropertyResolver?: boolean;
|
|
26
|
+
}): ReportWrapper[];
|
|
31
27
|
/**
|
|
32
|
-
*
|
|
28
|
+
* Parse raw reports
|
|
33
29
|
*
|
|
34
30
|
* @see https://www.sec.gov/edgar/sec-api-documentation
|
|
35
31
|
*/
|
|
36
|
-
parseReportsRaw(companyFactListData: CompanyFactListData): ReportRaw[];
|
|
32
|
+
parseReportsRaw(companyFactListData: CompanyFactListData, options?: Omit<GetReportsRawParams, 'symbol'>): ReportRaw[];
|
|
37
33
|
/**
|
|
38
34
|
* parseReportsRaw but removes meta data from the report
|
|
39
35
|
*/
|
|
@@ -1,37 +1,24 @@
|
|
|
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
|
*/
|
|
33
|
-
ReportParser.prototype.parseReportsFromRaw = function (
|
|
34
|
-
|
|
20
|
+
ReportParser.prototype.parseReportsFromRaw = function (params) {
|
|
21
|
+
var reportsRaw = params.reportsRaw, _a = params.usePropertyResolver, usePropertyResolver = _a === void 0 ? true : _a;
|
|
35
22
|
var reportByYearQuarter = new Map();
|
|
36
23
|
var reportsRawFiltered = reportsRaw;
|
|
37
24
|
this.translateReportsRaw(reportsRawFiltered, function (report, reportRaw) {
|
|
@@ -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
|
}
|