sec-edgar-api
Version:
Fetch and parse SEC earnings reports and other filings. Useful for financial analysis.
206 lines (205 loc) • 9.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseInsiderTransactions = void 0;
function parseTable(html) {
var rows = html.split('<tr');
return rows
.map(function (rowHtml) {
return rowHtml
.split('<td')
.map(function (cellHtml) { return cellHtml.substring(cellHtml.indexOf('>') + 1, cellHtml.lastIndexOf('</td>')); })
.slice(1);
})
.filter(function (row) { return row.length > 0; });
}
function stripHtml(html) {
return html
.replace(/<.*?>/g, '')
.replace(/ /g, ' ')
.replace(/\n/g, ' ')
.replace(/\s+/, ' ')
.trim();
}
function toNumber(value) {
return Number(value.replace(/,/g, '').trim()) || 0;
}
function parseInsiderTransactions(params) {
var _a, _b, _c, _d;
var xml = params.xml;
var ownerTableHeadingIndex = xml.indexOf('sortid=');
var transactionTableIdIndex = xml.indexOf('id="transaction-report"');
if (ownerTableHeadingIndex === -1) {
throw new Error('Owner table heading not found in XML data');
}
var ownerTableStartIndex = xml.lastIndexOf('<table', ownerTableHeadingIndex);
var ownerTableEndIndex = xml.indexOf('</table>', ownerTableHeadingIndex) + 8;
var ownerTableHtml = xml.substring(ownerTableStartIndex, ownerTableEndIndex);
var transactionTableStartIndex = xml.lastIndexOf('<table', transactionTableIdIndex);
var transactionTableEndIndex = xml.indexOf('</table>', transactionTableIdIndex) + 8;
var transactionTableHtml = xml.substring(transactionTableStartIndex, transactionTableEndIndex);
var issuerUrlIndex = xml.indexOf('cgi-bin/browse-edgar?action=getcompany');
var issuerUrlStartIndex = xml.lastIndexOf('<b>', issuerUrlIndex) + 3;
var issuerUrlEndIndex = xml.indexOf('</b>', issuerUrlIndex);
var issuerHtml = xml.substring(issuerUrlStartIndex, issuerUrlEndIndex).trim();
var issuerHtmlCikStart = issuerHtml.lastIndexOf('(') + 1;
var issuerCik = toNumber(stripHtml(issuerHtml.substring(issuerHtmlCikStart, issuerHtml.lastIndexOf(')'))));
var issuerName = issuerHtml.substring(0, issuerHtmlCikStart - 1).trim();
var headerOwner = ['owner_name', 'filings', 'transaction_date', 'type_of_owner'];
var headerTransaction = [
'acquisition_or_disposition',
'transaction_date',
'deemed_execution_date',
'reporting_owner',
'form',
'transaction_type',
'direct_or_indirect_ownership',
'num_securities_transacted',
'num_securities_following',
'line_number',
'owner_cik',
'security_title',
];
var ownerByCik = new Map();
var ownerRows = parseTable(ownerTableHtml);
var transactionRows = parseTable(transactionTableHtml);
var isSwitchedOwnerIssuer = stripHtml((_b = (_a = ownerRows[0]) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase()).includes('issuer') || false;
for (var i = 1; i < ownerRows.length; i++) {
var row = ownerRows[i];
// if (row.length === 0 || row[0].includes('Owner Name') || row[0].includes('Issuer')) continue // Skip header row
var owner = {
ownerName: '',
ownerCik: 0,
ownerPosition: null,
isDirector: false,
isOfficer: false,
isTenPercentOwner: false,
};
for (var i_1 = 0; i_1 < row.length; i_1++) {
var colName = headerOwner[i_1];
var htmlStripped = stripHtml(row[i_1]);
switch (colName) {
case 'owner_name':
owner.ownerName = htmlStripped.split('Current Name')[0];
break;
case 'filings':
owner.ownerCik = toNumber(htmlStripped);
break;
case 'type_of_owner': {
var _e = htmlStripped.split(':').map(function (s) { return s.toLowerCase().trim(); }), ownerType = _e[0], _f = _e[1], position = _f === void 0 ? null : _f;
owner.isDirector = ownerType.includes('director');
owner.isOfficer = ownerType.includes('officer');
owner.isTenPercentOwner = ownerType.includes('10 percent') || ownerType.includes('10%');
owner.ownerPosition = position;
break;
}
}
}
ownerByCik.set(owner.ownerCik, owner);
}
var transactions = [];
for (var _i = 0, transactionRows_1 = transactionRows; _i < transactionRows_1.length; _i++) {
var row = transactionRows_1[_i];
if (row.length === 0 || row[0].includes('Acquisition or Dis'))
continue; // Skip header row
var transaction = {
ownerName: '',
ownerCik: 0,
ownerPosition: null,
issuerCik: issuerCik,
issuerName: issuerName,
isDirector: false,
isOfficer: false,
accessionNumber: '',
deemedExecutionDate: '',
form: '',
/** true = buy, false = sell */
isAcquisition: false,
isDirectOwnership: false,
securityTitle: '',
transactionDate: '',
transactionCode: '',
transactionShares: 0,
sharesOwnedFollowingTransaction: 0,
lineNumber: 0,
isTenPercentOwner: false,
};
for (var i = 0; i < row.length; i++) {
var colName = headerTransaction[i];
var html = row[i];
var htmlStripped = stripHtml(html);
switch (colName) {
case 'acquisition_or_disposition':
transaction.isAcquisition = String(htmlStripped).toLowerCase() === 'a';
break;
case 'transaction_date':
transaction.transactionDate = htmlStripped;
break;
case 'deemed_execution_date':
transaction.deemedExecutionDate = htmlStripped;
break;
case 'reporting_owner':
break;
case 'form': {
var url = (_d = (_c = html.match(/href="([^"]+)"/)) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : '';
transaction.accessionNumber = url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('-'));
transaction.form = htmlStripped;
break;
}
case 'transaction_type':
transaction.transactionCode = htmlStripped.trim()[0];
break;
case 'direct_or_indirect_ownership':
transaction.isDirectOwnership = htmlStripped.toLowerCase().includes('d');
break;
case 'num_securities_transacted':
transaction.transactionShares = toNumber(htmlStripped) || 0;
break;
case 'num_securities_following':
transaction.sharesOwnedFollowingTransaction = toNumber(htmlStripped);
break;
case 'line_number':
transaction.lineNumber = toNumber(htmlStripped);
break;
case 'owner_cik': {
var owner = ownerByCik.get(toNumber(htmlStripped) || 0);
if (owner) {
transaction.ownerName = owner.ownerName;
transaction.ownerCik = owner.ownerCik;
transaction.ownerPosition = owner.ownerPosition;
transaction.isDirector = owner.isDirector;
transaction.isOfficer = owner.isOfficer;
transaction.isTenPercentOwner = owner.isTenPercentOwner;
}
break;
}
case 'security_title':
transaction.securityTitle = htmlStripped;
break;
}
}
transactions.push(transaction);
}
var owners = Array.from(ownerByCik.values());
var issuers = [{ issuerName: issuerName, issuerCik: issuerCik }];
// if searching by person, owner and issuer data will be switched
if (isSwitchedOwnerIssuer) {
issuers = owners.map(function (owner) { return ({
issuerName: owner.ownerName,
issuerCik: owner.ownerCik,
}); });
owners = [];
transactions.forEach(function (transaction) {
var issuerName = transaction.issuerName, issuerCik = transaction.issuerCik, ownerName = transaction.ownerName, ownerCik = transaction.ownerCik;
transaction.issuerCik = ownerCik;
transaction.issuerName = ownerName;
transaction.ownerCik = issuerCik;
transaction.ownerName = issuerName;
});
}
return {
transactions: transactions,
owners: Array.from(ownerByCik.values()),
issuers: issuers,
};
}
exports.parseInsiderTransactions = parseInsiderTransactions;