sec-edgar-api
Version:
Fetch and parse SEC earnings reports and other filings. Useful for financial analysis.
215 lines (214 loc) • 12.1 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var FactPeriodResolver_1 = require("./FactPeriodResolver");
var FactSplitAdjuster_1 = require("./FactSplitAdjuster");
/**
* There are many facts properties for the same period but filed at different times.
* This groups those together and resolves the period and trailing values for each group.
*/
var FactGrouper = /** @class */ (function () {
function FactGrouper() {
this.preferFirstValue = true;
}
FactGrouper.prototype.createFactGroup = function (params) {
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);
};
FactGrouper.prototype.createGroupKey = function (params) {
var fiscalYear = params.fiscalYear, quarter = params.quarter, name = params.name;
return "".concat(fiscalYear, "_").concat(quarter, "_").concat(name);
};
FactGrouper.prototype.toValue = function (value) {
return !isNaN(value) ? Number(value) : value || null;
};
/**
* Map structure { 2022_Q3: { name: ... } }. NOTE: Does not include fiscal year report key.
* All groups contain both trailing and period values, so use trailing from Q4 to get FY values.
*/
FactGrouper.prototype.buildFactGroupsByReportKey = function (params) {
var _this = this;
var _a, _b, _c, _d;
var facts = params.facts, cik = params.cik, fiscalCalculator = params.fiscalCalculator, resolvePeriodValues = params.resolvePeriodValues, _e = params.generateMissingGroups, generateMissingGroups = _e === void 0 ? false : _e, splits = params.splits;
// min and max year will be used to sort the reports
var minYear = 0;
var maxYear = 9999;
var factGroupByKey = new Map();
var periodResolver = new FactPeriodResolver_1.default({ cik: cik });
var factSplitAdjuster = new FactSplitAdjuster_1.default();
// used for groups that need to be generated without using a fact
var unitByPropertyName = new Map();
var accnByFiled = new Map();
// Create groups from facts.
for (var _i = 0, facts_1 = facts; _i < facts_1.length; _i++) {
var fact = facts_1[_i];
var _f = fiscalCalculator.getFiscalYearQuarter({ dateStr: fact.end }), quarter = _f.quarter, year = _f.year;
var _g = (_a = fiscalCalculator.getDatesByYearQuarter({ quarter: quarter, year: year })) !== null && _a !== void 0 ? _a : {}, _h = _g.end, reportEnd = _h === void 0 ? '' : _h, _j = _g.filed, reportFiled = _j === void 0 ? '' : _j;
var groupKey = this.createGroupKey({ fiscalYear: year, quarter: quarter, name: fact.name });
if (year < minYear)
minYear = year;
if (year > maxYear)
maxYear = year;
// period checks to see if the fact needs to be resolved for quarterly or trailing values
var period = periodResolver.getPeriod(fact);
var isPeriodFact = period <= 3;
var isTrailingFact = period > 3 || (isPeriodFact && quarter === 1);
var factValue = this.toValue(fact.value);
// if no group exists, create from fact
if (!factGroupByKey.has(groupKey)) {
var group_1 = this.createFactGroup({
name: fact.name,
accn: periodResolver.isOriginalFiling({ end: fact.end, filed: fact.filed }) ? fact.accn : '',
unit: fact.unit,
reportEnd: reportEnd,
reportFiled: reportFiled,
isResolverGenerated: false,
fiscalYear: year,
quarter: quarter,
filedFirst: fact.filed,
filedLast: fact.filed,
endFirst: fact.end,
endLast: fact.end,
valuePeriodFirst: isPeriodFact ? factValue : null,
valuePeriodLast: isPeriodFact ? factValue : null,
valueTrailingFirst: isTrailingFact ? factValue : null,
valueTrailingLast: isTrailingFact ? factValue : null,
values: [],
facts: [fact],
});
if (factValue !== null) {
group_1.values.push(factValue);
}
accnByFiled.set(fact.filed, (_b = fact.accn) !== null && _b !== void 0 ? _b : '');
unitByPropertyName.set(fact.name, fact.unit);
factGroupByKey.set(groupKey, group_1);
continue;
}
// if group already exists, update values
var group = factGroupByKey.get(groupKey);
group.facts.push(fact);
group.endFirst = fact.end < group.endFirst ? fact.end : group.endFirst;
group.endLast = fact.end > group.endLast ? fact.end : group.endLast;
group.filedFirst = fact.filed < group.filedFirst ? fact.filed : group.filedFirst;
group.filedLast = fact.filed > group.filedLast ? fact.filed : group.filedLast;
if (factValue !== null && !group.values.includes(factValue)) {
group.values.push(factValue);
}
if (periodResolver.isOriginalFiling({ end: fact.end, filed: fact.filed })) {
group.accn = (_d = (_c = fact.accn) !== null && _c !== void 0 ? _c : group.accn) !== null && _d !== void 0 ? _d : '';
accnByFiled.set(fact.filed, group.accn);
}
if (isPeriodFact) {
if (group.valuePeriodFirst === null) {
group.valuePeriodFirst = factValue;
}
if (factValue !== group.valuePeriodFirst && factValue !== group.valuePeriodLast) {
group.valuePeriodLast = factValue;
}
}
if (isTrailingFact) {
if (group.valueTrailingFirst === null) {
group.valueTrailingFirst = factValue;
}
if (factValue !== group.valueTrailingFirst && factValue !== group.valueTrailingLast) {
group.valueTrailingLast = factValue;
}
}
}
// adjust for splits
var factGroupsByReportKey = new Map();
if (splits) {
factSplitAdjuster.adjustForSplits({
factGroups: Array.from(factGroupByKey.values()),
splits: splits,
});
}
factGroupByKey.forEach(function (group) {
var _a, _b;
// add to the period resolver to resolve quarterly and trailing values
var preferredValuePeriod = _this.preferFirstValue ? group.valuePeriodLast : group.valuePeriodLast;
var preferredValueTrailing = _this.preferFirstValue ? group.valueTrailingFirst : group.valueTrailingLast;
var selectedFactPeriod = group.facts.find(function (fact) {
var period = FactPeriodResolver_1.default.getPeriod(fact);
return fact.value === preferredValuePeriod && period <= 3;
});
var selectedFactTrailing = group.facts.find(function (fact) {
var period = FactPeriodResolver_1.default.getPeriod(fact);
return fact.value === preferredValueTrailing && (period > 3 || period === 0);
});
var valuePeriod = _this.toValue((_a = group.valueSplitAdjustedPeriod) !== null && _a !== void 0 ? _a : preferredValuePeriod);
var valueTrailing = _this.toValue((_b = group.valueSplitAdjustedTrailing) !== null && _b !== void 0 ? _b : preferredValueTrailing);
if (selectedFactPeriod && valuePeriod !== null) {
periodResolver.add({
end: selectedFactPeriod.end,
filed: selectedFactPeriod.filed,
name: selectedFactPeriod.name,
quarter: group.quarter,
value: valuePeriod,
year: group.fiscalYear,
start: selectedFactPeriod.start,
});
}
if (selectedFactTrailing && valueTrailing !== null) {
periodResolver.add({
end: selectedFactTrailing.end,
filed: selectedFactTrailing.filed,
name: selectedFactTrailing.name,
quarter: group.quarter,
value: valueTrailing,
year: group.fiscalYear,
start: selectedFactTrailing.start,
});
}
});
// Resolve quarterly and trailing values, and if no facts present for a certain period, create a group with resolved values.
periodResolver.forEach(function (_a) {
var _b, _c, _d, _e, _f, _g;
var propertyName = _a.propertyName, quarter = _a.quarter, valueQuarter = _a.valueQuarter, valueTrailing = _a.valueTrailing, year = _a.year;
var groupKey = _this.createGroupKey({ fiscalYear: year, name: propertyName, quarter: quarter });
var group = factGroupByKey.get(groupKey);
if (!group && (!resolvePeriodValues || !generateMissingGroups))
return;
var _h = (_b = fiscalCalculator.getDatesByYearQuarter({ quarter: quarter, year: year })) !== null && _b !== void 0 ? _b : { end: '', filed: '' }, end = _h.end, filed = _h.filed;
var reportKey = "".concat(year, "_Q").concat(quarter);
var bucket = (_c = factGroupsByReportKey.get(reportKey)) !== null && _c !== void 0 ? _c : factGroupsByReportKey.set(reportKey, []).get(reportKey);
if (!group) {
group = _this.createFactGroup({
reportEnd: end,
reportFiled: filed,
endFirst: end,
endLast: end,
name: propertyName,
accn: (_d = accnByFiled.get(filed)) !== null && _d !== void 0 ? _d : '',
unit: (_e = unitByPropertyName.get(propertyName)) !== null && _e !== void 0 ? _e : '',
isResolverGenerated: true,
fiscalYear: year,
quarter: quarter,
valuePeriodResolved: valueQuarter,
valueTrailingResolved: valueTrailing,
});
factGroupByKey.set(groupKey, group);
}
else if (resolvePeriodValues) {
var shouldUseTrailingForQuarter = FactPeriodResolver_1.default.isAverageShares({ propertyName: group.name }) && group.quarter === 4;
group.valuePeriodResolved = shouldUseTrailingForQuarter ? valueTrailing : valueQuarter;
group.valueTrailingResolved = valueTrailing;
(_f = group.valuePeriodFirst) !== null && _f !== void 0 ? _f : (group.valuePeriodFirst = shouldUseTrailingForQuarter ? valueTrailing : valueQuarter);
(_g = group.valueTrailingFirst) !== null && _g !== void 0 ? _g : (group.valueTrailingFirst = valueTrailing);
}
bucket.push(group);
});
return { factGroupsByReportKey: factGroupsByReportKey, minYear: minYear, maxYear: maxYear };
};
return FactGrouper;
}());
exports.default = FactGrouper;