UNPKG

sec-edgar-api

Version:

Fetch and parse SEC earnings reports and other filings. Useful for financial analysis.

223 lines (222 loc) 10 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseForm4 = void 0; var XMLParserLegacy_1 = require("../XMLParserLegacy"); /** * Form 4 - Insider Transactions * * example at https://www.sec.gov/Archives/edgar/data/320193/000032019323000079/xslF345X05/wk-form4_1691533817.xml */ function parseForm4(params, xmlParser) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; if (xmlParser === void 0) { xmlParser = new XMLParserLegacy_1.default(); } var xml = params.xml; var textMap = xmlParser.getTableTextMap({ xml: xml, parentPath: 'html.body' }); var getTextBetween = function (text, before, after) { var indexBefore = text.indexOf(before); var indexAfter = after ? text.indexOf(after, indexBefore) : text.length; return text.substring(indexBefore + before.length, indexAfter).trim(); }; var relationText = (_a = textMap.get('2.1.3')) !== null && _a !== void 0 ? _a : ''; var filerNameText = (_b = textMap.get('2.1.1')) !== null && _b !== void 0 ? _b : ''; var filterNameText = getTextBetween(filerNameText, '1. Name and Address of Reporting Person*', '(Last)'); var isDirector = relationText.substring(0, relationText.indexOf('Director')).includes('X'); var isOwner10 = getTextBetween(relationText, 'Director', '10% Owner').includes('X'); var isOfficer = getTextBetween(relationText, '10% Owner', 'Officer (give title below)').includes('X'); var isOther = getTextBetween(relationText, 'Officer (give title below)', 'Other (specify below)').includes('X'); var position = getTextBetween(relationText, 'Other (specify below)'); var filerPositionTypes = []; if (isDirector) filerPositionTypes.push('Director'); if (isOwner10) filerPositionTypes.push('10% Owner'); if (isOfficer) filerPositionTypes.push('Officer'); if (isOther) filerPositionTypes.push('Other'); var codeTranslations = { P: 'Purchase', S: 'Sale', V: 'Voluntary Reporting', A: 'Grant', D: 'Sale to Issuer', F: 'Payment of Exercise Price', I: 'Discretionary Transaction', M: 'Conversion of Derivative Exempt', C: 'Conversion of Derivative', E: 'Expiration of Short Derivative Position', H: 'Expiration of Long Derivative Position', O: 'Exercise of out-of-the-money Derivative', X: 'Exercise of in-the-money Derivative', G: 'Gift', L: 'Small Acquisition', W: 'Acquisition or Disposition By Will or Laws', Z: 'Voting Trust Deposit or Withdrawal', J: 'Other Acquisition or Disposition', K: 'Equity Swap', U: 'Disposition Change in Control', }; var toDate = function (str) { if (str === '') return ''; var _a = str.split('/'), month = _a[0], day = _a[1], year = _a[2]; return [month, day, year].some(function (x) { return x === undefined; }) ? '' : "".concat(year, "-").concat(month, "-").concat(day); }; var createTransaction = function () { return ({ filerName: filterNameText, filerPosition: position, filerPositionTypes: filerPositionTypes, category: 'Non-Derivative', securityType: '', securityTypeUnderlying: null, date: '', dateExecuted: null, dateExpiration: null, dateExercisable: null, transactionType: null, transactionCode: null, transactionDescription: null, price: null, priceExcercised: null, shares: null, sharesUnderlying: null, sharesEnding: null, ownership: '', explainationByKey: {}, }); }; var getColText = function (colKey) { var _a, _b; var text = (_a = textMap.get(colKey)) === null || _a === void 0 ? void 0 : _a.replace(/\(\d+\)|\$/g, ''); return (_b = text === null || text === void 0 ? void 0 : text.trim()) !== null && _b !== void 0 ? _b : ''; }; var headingNonDerivative = [ 'securityType', 'date', 'dateExecuted', 'transactionCode', '', 'shares', 'transactionType', 'price', 'sharesEnding', 'ownership', ]; var headingDerivative = [ 'securityType', 'priceExcercised', 'date', 'dateExecuted', 'transactionCode', '', 'shares', 'shares', 'dateExercisable', 'dateExpiration', 'securityTypeUnderlying', 'sharesUnderlying', 'price', 'sharesEnding', 'ownership', ]; var maxIterations = 10000; var transactions = []; transactionsNonDerivative: for (var row = 4; row < maxIterations; row++) { var transaction = createTransaction(); transaction.category = 'Non-Derivative'; // get all non-derivative transactions for (var col = 1; col < 11; col++) { var colName = ((_c = headingNonDerivative[col - 1]) !== null && _c !== void 0 ? _c : ''); var colKey = "3.".concat(row, ".").concat(col); var text = getColText(colKey); var explanationNum = (_f = (_e = ((_d = textMap.get(colKey)) !== null && _d !== void 0 ? _d : '').match(/(?<=\()\d+(?=\))/g)) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : null; var explanationText = explanationNum ? (_g = textMap.get("5.".concat(Number(explanationNum) + 1, ".1"))) !== null && _g !== void 0 ? _g : '' : null; if (colName === '') continue; if (explanationText !== null) transaction.explainationByKey[colName] = explanationText.trim(); if (!textMap.has(colKey)) break transactionsNonDerivative; switch (colName) { case 'transactionType': transaction.transactionType = text === 'A' ? 'Acquire' : 'Dispose'; continue; case 'transactionCode': transaction.transactionDescription = (_h = codeTranslations[text]) !== null && _h !== void 0 ? _h : ''; transaction.transactionCode = text; continue; case 'date': transaction.date = toDate(text); continue; case 'dateExecuted': case 'dateExercisable': case 'dateExpiration': transaction[colName] = toDate(text) || null; continue; case 'price': case 'shares': case 'sharesEnding': { var valueNum = Number(text.replace(/,/g, '')); transaction[colName] = text === '' || isNaN(valueNum) ? null : valueNum; continue; } default: transaction[colName] = text; } } transactions.push(transaction); } transactionsDerivative: for (var row = 4; row < maxIterations; row++) { var transaction = createTransaction(); transaction.category = 'Derivative'; var textSharesAcquired = getColText("4.".concat(row, ".6")); var textSharesDisposed = getColText("4.".concat(row, ".7")); var sharesAcquired = Number(textSharesAcquired); var sharesDisposed = Number(textSharesDisposed); if (textSharesAcquired !== '' || textSharesDisposed !== '') { transaction.transactionType = sharesAcquired - sharesDisposed > 0 ? 'Acquire' : 'Dispose'; } for (var col = 1; col < 16; col++) { var colName = ((_j = headingDerivative[col - 1]) !== null && _j !== void 0 ? _j : ''); var colKey = "4.".concat(row, ".").concat(col); var text = ((_k = textMap.get(colKey)) !== null && _k !== void 0 ? _k : '').replace(/\(\d+\)|\$/g, '').trim(); var explanationNum = (_o = (_m = ((_l = textMap.get(colKey)) !== null && _l !== void 0 ? _l : '').match(/(?<=\()\d+(?=\))/g)) === null || _m === void 0 ? void 0 : _m[0]) !== null && _o !== void 0 ? _o : null; var explanationText = explanationNum ? (_p = textMap.get("5.".concat(Number(explanationNum) + 1, ".1"))) !== null && _p !== void 0 ? _p : '' : null; if (colName === '') continue; if (explanationText !== null) transaction.explainationByKey[colName] = explanationText.trim(); if (!textMap.has(colKey)) break transactionsDerivative; switch (colName) { case 'transactionType': transaction.transactionType = text === 'A' ? 'Acquire' : 'Dispose'; continue; case 'transactionCode': transaction.transactionDescription = (_q = codeTranslations[text]) !== null && _q !== void 0 ? _q : ''; transaction.transactionCode = text; continue; case 'dateExecuted': case 'dateExercisable': case 'dateExpiration': transaction[colName] = toDate(text) || null; continue; case 'price': case 'shares': case 'sharesUnderlying': case 'priceExcercised': case 'sharesEnding': { if (colName === 'shares' && transaction.shares !== null) continue; var valueNum = Number(text.replace(/,/g, '')); transaction[colName] = text === '' || isNaN(valueNum) ? null : valueNum; continue; } default: transaction[colName] = text; } } transactions.push(transaction); } return { transactions: transactions }; } exports.parseForm4 = parseForm4;