@civiq/entity-resolution 0.1.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/LICENSE +21 -0
- package/README.md +135 -0
- package/data/bioguide-fec-mapping.json +4186 -0
- package/data/sec-sic-data.json +10427 -0
- package/dist/__tests__/company-entity-resolver.test.d.ts +6 -0
- package/dist/__tests__/company-entity-resolver.test.d.ts.map +1 -0
- package/dist/__tests__/company-entity-resolver.test.js +267 -0
- package/dist/__tests__/company-entity-resolver.test.js.map +1 -0
- package/dist/__tests__/entity-resolution.test.d.ts +2 -0
- package/dist/__tests__/entity-resolution.test.d.ts.map +1 -0
- package/dist/__tests__/entity-resolution.test.js +296 -0
- package/dist/__tests__/entity-resolution.test.js.map +1 -0
- package/dist/__tests__/fec-entity-resolution.test.d.ts +2 -0
- package/dist/__tests__/fec-entity-resolution.test.d.ts.map +1 -0
- package/dist/__tests__/fec-entity-resolution.test.js +49 -0
- package/dist/__tests__/fec-entity-resolution.test.js.map +1 -0
- package/dist/bioguide-fec-mapping.d.ts +27 -0
- package/dist/bioguide-fec-mapping.d.ts.map +1 -0
- package/dist/bioguide-fec-mapping.js +57 -0
- package/dist/bioguide-fec-mapping.js.map +1 -0
- package/dist/cache.d.ts +18 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +18 -0
- package/dist/cache.js.map +1 -0
- package/dist/committee-agency-map.d.ts +58 -0
- package/dist/committee-agency-map.d.ts.map +1 -0
- package/dist/committee-agency-map.js +658 -0
- package/dist/committee-agency-map.js.map +1 -0
- package/dist/committee-alias-table.d.ts +11 -0
- package/dist/committee-alias-table.d.ts.map +1 -0
- package/dist/committee-alias-table.js +191 -0
- package/dist/committee-alias-table.js.map +1 -0
- package/dist/company-alias-table.d.ts +36 -0
- package/dist/company-alias-table.d.ts.map +1 -0
- package/dist/company-alias-table.js +1307 -0
- package/dist/company-alias-table.js.map +1 -0
- package/dist/company-entity-resolver.d.ts +94 -0
- package/dist/company-entity-resolver.d.ts.map +1 -0
- package/dist/company-entity-resolver.js +282 -0
- package/dist/company-entity-resolver.js.map +1 -0
- package/dist/configure.d.ts +15 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +19 -0
- package/dist/configure.js.map +1 -0
- package/dist/fec-entity-resolution.d.ts +88 -0
- package/dist/fec-entity-resolution.d.ts.map +1 -0
- package/dist/fec-entity-resolution.js +407 -0
- package/dist/fec-entity-resolution.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/industry-taxonomy.d.ts +90 -0
- package/dist/industry-taxonomy.d.ts.map +1 -0
- package/dist/industry-taxonomy.js +1026 -0
- package/dist/industry-taxonomy.js.map +1 -0
- package/dist/lda-issue-policy-map.d.ts +13 -0
- package/dist/lda-issue-policy-map.d.ts.map +1 -0
- package/dist/lda-issue-policy-map.js +193 -0
- package/dist/lda-issue-policy-map.js.map +1 -0
- package/dist/lobbying-committee-resolver.d.ts +23 -0
- package/dist/lobbying-committee-resolver.d.ts.map +1 -0
- package/dist/lobbying-committee-resolver.js +158 -0
- package/dist/lobbying-committee-resolver.js.map +1 -0
- package/dist/logger.d.ts +20 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +20 -0
- package/dist/logger.js.map +1 -0
- package/dist/sic-sector-map.d.ts +32 -0
- package/dist/sic-sector-map.d.ts.map +1 -0
- package/dist/sic-sector-map.js +109 -0
- package/dist/sic-sector-map.js.map +1 -0
- package/dist/ticker-industry-resolver.d.ts +22 -0
- package/dist/ticker-industry-resolver.d.ts.map +1 -0
- package/dist/ticker-industry-resolver.js +254 -0
- package/dist/ticker-industry-resolver.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019-2025 Mark Sandford
|
|
3
|
+
* Licensed under the MIT License. See LICENSE and NOTICE files.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* SIC Code to IndustrySector Mapping
|
|
7
|
+
*
|
|
8
|
+
* Maps Standard Industrial Classification (SIC) code ranges to the
|
|
9
|
+
* IndustrySector enum from src/lib/fec/industry-taxonomy.ts.
|
|
10
|
+
*
|
|
11
|
+
* SIC codes are 4-digit numbers organized into divisions:
|
|
12
|
+
* 0100-0999: Agriculture, Forestry, Fishing
|
|
13
|
+
* 1000-1499: Mining
|
|
14
|
+
* 1500-1799: Construction
|
|
15
|
+
* 2000-3999: Manufacturing
|
|
16
|
+
* 4000-4999: Transportation, Communications, Utilities
|
|
17
|
+
* 5000-5199: Wholesale Trade
|
|
18
|
+
* 5200-5999: Retail Trade
|
|
19
|
+
* 6000-6799: Finance, Insurance, Real Estate
|
|
20
|
+
* 7000-8999: Services
|
|
21
|
+
* 9100-9999: Public Administration
|
|
22
|
+
*
|
|
23
|
+
* Some ranges are further subdivided to match the OpenSecrets-style
|
|
24
|
+
* 13-sector model used across CIV.IQ.
|
|
25
|
+
*/
|
|
26
|
+
import { IndustrySector } from './industry-taxonomy';
|
|
27
|
+
/**
|
|
28
|
+
* Ordered list of SIC code ranges mapped to IndustrySector.
|
|
29
|
+
* More specific ranges precede broader ones.
|
|
30
|
+
*/
|
|
31
|
+
const SIC_RANGES = [
|
|
32
|
+
// Agriculture, Forestry, Fishing (0100-0999)
|
|
33
|
+
{ start: 100, end: 999, sector: IndustrySector.AGRIBUSINESS },
|
|
34
|
+
// Mining (1000-1499) — Energy/Natural Resources
|
|
35
|
+
{ start: 1000, end: 1499, sector: IndustrySector.ENERGY_NATURAL_RESOURCES },
|
|
36
|
+
// Construction (1500-1799)
|
|
37
|
+
{ start: 1500, end: 1799, sector: IndustrySector.CONSTRUCTION },
|
|
38
|
+
// Manufacturing — Food products (2000-2099) → Agribusiness
|
|
39
|
+
{ start: 2000, end: 2099, sector: IndustrySector.AGRIBUSINESS },
|
|
40
|
+
// Manufacturing — Tobacco, Textiles, Wood, Paper, Printing (2100-2799) → Misc Business
|
|
41
|
+
{ start: 2100, end: 2799, sector: IndustrySector.MISC_BUSINESS },
|
|
42
|
+
// Manufacturing — Chemicals, Pharmaceuticals (2800-2899) → Health
|
|
43
|
+
{ start: 2800, end: 2899, sector: IndustrySector.HEALTH },
|
|
44
|
+
// Manufacturing — Petroleum refining, Rubber, Plastics (2900-3099) → Energy
|
|
45
|
+
{ start: 2900, end: 3099, sector: IndustrySector.ENERGY_NATURAL_RESOURCES },
|
|
46
|
+
// Manufacturing — Stone, Clay, Glass, Primary Metals, Fabricated Metals (3100-3499) → Misc Business
|
|
47
|
+
{ start: 3100, end: 3499, sector: IndustrySector.MISC_BUSINESS },
|
|
48
|
+
// Manufacturing — Industrial machinery, Computers (3500-3599) → Communications/Electronics
|
|
49
|
+
{ start: 3500, end: 3599, sector: IndustrySector.COMMUNICATIONS_ELECTRONICS },
|
|
50
|
+
// Manufacturing — Electronic components, Semiconductors (3600-3699) → Communications/Electronics
|
|
51
|
+
{ start: 3600, end: 3699, sector: IndustrySector.COMMUNICATIONS_ELECTRONICS },
|
|
52
|
+
// Manufacturing — Transportation equipment (3700-3799) → Transportation
|
|
53
|
+
{ start: 3700, end: 3719, sector: IndustrySector.TRANSPORTATION },
|
|
54
|
+
// Manufacturing — Aircraft, Guided missiles, Space vehicles (3720-3799) → Defense
|
|
55
|
+
{ start: 3720, end: 3799, sector: IndustrySector.DEFENSE },
|
|
56
|
+
// Manufacturing — Instruments, Medical devices (3800-3899) → Health
|
|
57
|
+
{ start: 3800, end: 3899, sector: IndustrySector.HEALTH },
|
|
58
|
+
// Manufacturing — Misc manufacturing (3900-3999) → Misc Business
|
|
59
|
+
{ start: 3900, end: 3999, sector: IndustrySector.MISC_BUSINESS },
|
|
60
|
+
// Transportation — Railroad, Trucking, Water, Air (4000-4599) → Transportation
|
|
61
|
+
{ start: 4000, end: 4599, sector: IndustrySector.TRANSPORTATION },
|
|
62
|
+
// Transportation — Pipelines (4600-4699) → Energy
|
|
63
|
+
{ start: 4600, end: 4699, sector: IndustrySector.ENERGY_NATURAL_RESOURCES },
|
|
64
|
+
// Communications — Telephone, Radio, TV, Cable (4700-4899) → Communications/Electronics
|
|
65
|
+
{ start: 4700, end: 4899, sector: IndustrySector.COMMUNICATIONS_ELECTRONICS },
|
|
66
|
+
// Utilities — Electric, Gas, Water, Sanitary (4900-4999) → Energy
|
|
67
|
+
{ start: 4900, end: 4999, sector: IndustrySector.ENERGY_NATURAL_RESOURCES },
|
|
68
|
+
// Wholesale Trade (5000-5199) → Misc Business
|
|
69
|
+
{ start: 5000, end: 5199, sector: IndustrySector.MISC_BUSINESS },
|
|
70
|
+
// Retail Trade (5200-5999) → Misc Business
|
|
71
|
+
{ start: 5200, end: 5999, sector: IndustrySector.MISC_BUSINESS },
|
|
72
|
+
// Finance, Insurance, Real Estate (6000-6797)
|
|
73
|
+
{ start: 6000, end: 6797, sector: IndustrySector.FINANCE_INSURANCE_REAL_ESTATE },
|
|
74
|
+
// Services — Hotels, Personal services (7000-7299) → Misc Business
|
|
75
|
+
{ start: 7000, end: 7299, sector: IndustrySector.MISC_BUSINESS },
|
|
76
|
+
// Services — Business services, Computer programming (7300-7399) → Communications/Electronics
|
|
77
|
+
{ start: 7300, end: 7399, sector: IndustrySector.COMMUNICATIONS_ELECTRONICS },
|
|
78
|
+
// Services — Auto repair, Misc repair, Entertainment (7400-7999) → Misc Business
|
|
79
|
+
{ start: 7400, end: 7999, sector: IndustrySector.MISC_BUSINESS },
|
|
80
|
+
// Services — Health services (8000-8099) → Health
|
|
81
|
+
{ start: 8000, end: 8099, sector: IndustrySector.HEALTH },
|
|
82
|
+
// Services — Legal services (8100-8199) → Lawyers & Lobbyists
|
|
83
|
+
{ start: 8100, end: 8199, sector: IndustrySector.LAWYERS_LOBBYISTS },
|
|
84
|
+
// Services — Education (8200-8299) → Ideology/Single-Issue
|
|
85
|
+
{ start: 8200, end: 8299, sector: IndustrySector.IDEOLOGY_SINGLE_ISSUE },
|
|
86
|
+
// Services — Social services, Museums, Membership orgs (8300-8699) → Ideology/Single-Issue
|
|
87
|
+
{ start: 8300, end: 8699, sector: IndustrySector.IDEOLOGY_SINGLE_ISSUE },
|
|
88
|
+
// Services — Engineering, Accounting, Research, Management (8700-8999) → Misc Business
|
|
89
|
+
{ start: 8700, end: 8999, sector: IndustrySector.MISC_BUSINESS },
|
|
90
|
+
// Public Administration (9100-9999) → Other
|
|
91
|
+
{ start: 9100, end: 9999, sector: IndustrySector.OTHER },
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a 4-digit SIC code string to an IndustrySector.
|
|
95
|
+
* Returns null if the code is invalid or falls outside all known ranges.
|
|
96
|
+
*/
|
|
97
|
+
export function sicToSector(sicCode) {
|
|
98
|
+
const code = parseInt(sicCode, 10);
|
|
99
|
+
if (isNaN(code) || code < 100 || code > 9999) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
for (const range of SIC_RANGES) {
|
|
103
|
+
if (code >= range.start && code <= range.end) {
|
|
104
|
+
return range.sector;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=sic-sector-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sic-sector-map.js","sourceRoot":"","sources":["../src/sic-sector-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019-2025 Mark Sandford
|
|
3
|
+
* Licensed under the MIT License. See LICENSE and NOTICE files.
|
|
4
|
+
*/
|
|
5
|
+
import type { TickerResolution } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a stock ticker to an IndustrySector.
|
|
8
|
+
*
|
|
9
|
+
* Returns null for ETFs, mutual funds, and tickers that can't be resolved.
|
|
10
|
+
* Uses Redis caching for SEC API responses (30-day TTL).
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveTickerIndustry(ticker: string): Promise<TickerResolution | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve multiple stock tickers to IndustrySectors in parallel.
|
|
15
|
+
*
|
|
16
|
+
* Deduplicates tickers, checks cache in batch, then resolves remaining
|
|
17
|
+
* tickers concurrently (max 5 parallel SEC API requests).
|
|
18
|
+
*
|
|
19
|
+
* Returns a Map from normalized ticker to resolution (null for unresolvable).
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveTickerIndustries(tickers: string[]): Promise<Map<string, TickerResolution | null>>;
|
|
22
|
+
//# sourceMappingURL=ticker-industry-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticker-industry-resolver.d.ts","sourceRoot":"","sources":["../src/ticker-industry-resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAsDhD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiE5F;AAqCD;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAqD/C"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019-2025 Mark Sandford
|
|
3
|
+
* Licensed under the MIT License. See LICENSE and NOTICE files.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Ticker-to-Industry Resolver
|
|
7
|
+
*
|
|
8
|
+
* Resolves stock tickers from House Clerk disclosure filings to
|
|
9
|
+
* IndustrySector using SEC EDGAR data + SIC code mapping.
|
|
10
|
+
*
|
|
11
|
+
* Flow: ticker → CIK (static lookup) → SIC code (SEC API, cached) → IndustrySector
|
|
12
|
+
*
|
|
13
|
+
* ETFs, mutual funds, and unresolvable tickers return null.
|
|
14
|
+
*/
|
|
15
|
+
import { getLogger } from './logger';
|
|
16
|
+
import { getCache } from './cache';
|
|
17
|
+
import { sicToSector } from './sic-sector-map';
|
|
18
|
+
// Static ticker → CIK mapping from SEC EDGAR company_tickers.json
|
|
19
|
+
// ~10K entries, ~155KB
|
|
20
|
+
import tickerCikMap from '../data/sec-sic-data.json';
|
|
21
|
+
/** SIC code cache TTL: 30 days (SIC codes rarely change) */
|
|
22
|
+
const SIC_CACHE_TTL = 30 * 24 * 60 * 60;
|
|
23
|
+
/** SEC EDGAR submissions API base URL */
|
|
24
|
+
const SEC_SUBMISSIONS_URL = 'https://data.sec.gov/submissions';
|
|
25
|
+
/** SEC requires a User-Agent header identifying the requester */
|
|
26
|
+
const SEC_USER_AGENT = 'CIV.IQ civic-intel-hub/1.0 (civdotiq.org)';
|
|
27
|
+
/**
|
|
28
|
+
* Known ETF/fund tickers that should return null (no single sector).
|
|
29
|
+
* This is not exhaustive — the resolver also returns null for tickers
|
|
30
|
+
* not found in the SEC company data.
|
|
31
|
+
*/
|
|
32
|
+
const KNOWN_FUNDS = new Set([
|
|
33
|
+
'SPY',
|
|
34
|
+
'QQQ',
|
|
35
|
+
'IWM',
|
|
36
|
+
'DIA',
|
|
37
|
+
'VTI',
|
|
38
|
+
'VOO',
|
|
39
|
+
'VEA',
|
|
40
|
+
'VWO',
|
|
41
|
+
'EFA',
|
|
42
|
+
'AGG',
|
|
43
|
+
'BND',
|
|
44
|
+
'TLT',
|
|
45
|
+
'GLD',
|
|
46
|
+
'SLV',
|
|
47
|
+
'USO',
|
|
48
|
+
'XLF',
|
|
49
|
+
'XLE',
|
|
50
|
+
'XLK',
|
|
51
|
+
'XLV',
|
|
52
|
+
'XLI',
|
|
53
|
+
'XLP',
|
|
54
|
+
'XLY',
|
|
55
|
+
'XLB',
|
|
56
|
+
'XLU',
|
|
57
|
+
'XLRE',
|
|
58
|
+
'XLC',
|
|
59
|
+
'ARKK',
|
|
60
|
+
'ARKW',
|
|
61
|
+
'ARKG',
|
|
62
|
+
'ARKF',
|
|
63
|
+
'ARKQ',
|
|
64
|
+
]);
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a stock ticker to an IndustrySector.
|
|
67
|
+
*
|
|
68
|
+
* Returns null for ETFs, mutual funds, and tickers that can't be resolved.
|
|
69
|
+
* Uses Redis caching for SEC API responses (30-day TTL).
|
|
70
|
+
*/
|
|
71
|
+
export async function resolveTickerIndustry(ticker) {
|
|
72
|
+
const normalizedTicker = ticker.toUpperCase().trim();
|
|
73
|
+
if (!normalizedTicker) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
// Skip known funds/ETFs
|
|
77
|
+
if (KNOWN_FUNDS.has(normalizedTicker)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Check Redis cache first
|
|
81
|
+
const cacheKey = `ticker-sic:${normalizedTicker}`;
|
|
82
|
+
try {
|
|
83
|
+
const cached = await getCache().get(cacheKey);
|
|
84
|
+
if (cached === 'null') {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (cached) {
|
|
88
|
+
return cached;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Cache miss or error — continue to resolution
|
|
93
|
+
}
|
|
94
|
+
// Look up CIK from static data
|
|
95
|
+
const cik = tickerCikMap[normalizedTicker];
|
|
96
|
+
if (!cik) {
|
|
97
|
+
getLogger().debug(`[TickerResolver] No CIK found for ticker: ${normalizedTicker}`);
|
|
98
|
+
await cacheMiss(cacheKey);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
// Fetch SIC code from SEC EDGAR API
|
|
102
|
+
const sicCode = await fetchSicCode(cik);
|
|
103
|
+
if (!sicCode) {
|
|
104
|
+
await cacheMiss(cacheKey);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
// Map SIC code to IndustrySector
|
|
108
|
+
const sector = sicToSector(sicCode);
|
|
109
|
+
if (!sector) {
|
|
110
|
+
getLogger().debug(`[TickerResolver] SIC ${sicCode} has no sector mapping for ${normalizedTicker}`);
|
|
111
|
+
await cacheMiss(cacheKey);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const result = {
|
|
115
|
+
sector,
|
|
116
|
+
sicCode,
|
|
117
|
+
confidence: 1.0,
|
|
118
|
+
};
|
|
119
|
+
// Cache successful resolution
|
|
120
|
+
try {
|
|
121
|
+
await getCache().set(cacheKey, result, SIC_CACHE_TTL);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Cache write failure is non-fatal
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fetch SIC code from SEC EDGAR submissions API.
|
|
130
|
+
* The CIK is zero-padded to 10 digits per SEC convention.
|
|
131
|
+
*/
|
|
132
|
+
async function fetchSicCode(cik) {
|
|
133
|
+
const paddedCik = String(cik).padStart(10, '0');
|
|
134
|
+
const url = `${SEC_SUBMISSIONS_URL}/CIK${paddedCik}.json`;
|
|
135
|
+
try {
|
|
136
|
+
const response = await fetch(url, {
|
|
137
|
+
headers: { 'User-Agent': SEC_USER_AGENT },
|
|
138
|
+
signal: AbortSignal.timeout(10000),
|
|
139
|
+
});
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
getLogger().warn(`[TickerResolver] SEC API returned ${response.status} for CIK ${cik}`);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const data = await response.json();
|
|
145
|
+
const sic = data?.sic;
|
|
146
|
+
if (!sic) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return String(sic);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
getLogger().error('[TickerResolver] SEC API fetch failed', error, {
|
|
153
|
+
cik: String(cik),
|
|
154
|
+
});
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Resolve multiple stock tickers to IndustrySectors in parallel.
|
|
160
|
+
*
|
|
161
|
+
* Deduplicates tickers, checks cache in batch, then resolves remaining
|
|
162
|
+
* tickers concurrently (max 5 parallel SEC API requests).
|
|
163
|
+
*
|
|
164
|
+
* Returns a Map from normalized ticker to resolution (null for unresolvable).
|
|
165
|
+
*/
|
|
166
|
+
export async function resolveTickerIndustries(tickers) {
|
|
167
|
+
const results = new Map();
|
|
168
|
+
// Deduplicate and normalize
|
|
169
|
+
const uniqueTickers = [...new Set(tickers.map(t => t.toUpperCase().trim()).filter(Boolean))];
|
|
170
|
+
if (uniqueTickers.length === 0) {
|
|
171
|
+
return results;
|
|
172
|
+
}
|
|
173
|
+
// Separate known funds (instant null)
|
|
174
|
+
const resolvable = [];
|
|
175
|
+
for (const ticker of uniqueTickers) {
|
|
176
|
+
if (KNOWN_FUNDS.has(ticker)) {
|
|
177
|
+
results.set(ticker, null);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
resolvable.push(ticker);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Batch cache lookup
|
|
184
|
+
const cacheKeys = resolvable.map(t => `ticker-sic:${t}`);
|
|
185
|
+
const cached = await Promise.all(cacheKeys.map(key => getCache()
|
|
186
|
+
.get(key)
|
|
187
|
+
.catch(() => null)));
|
|
188
|
+
const uncached = [];
|
|
189
|
+
for (let i = 0; i < resolvable.length; i++) {
|
|
190
|
+
const hit = cached[i];
|
|
191
|
+
if (hit === 'null') {
|
|
192
|
+
results.set(resolvable[i], null);
|
|
193
|
+
}
|
|
194
|
+
else if (hit) {
|
|
195
|
+
results.set(resolvable[i], hit);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
uncached.push(resolvable[i]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Resolve uncached tickers with concurrency limit
|
|
202
|
+
const CONCURRENCY = 5;
|
|
203
|
+
for (let i = 0; i < uncached.length; i += CONCURRENCY) {
|
|
204
|
+
const batch = uncached.slice(i, i + CONCURRENCY);
|
|
205
|
+
const resolved = await Promise.all(batch.map(t => resolveSingle(t)));
|
|
206
|
+
for (let j = 0; j < batch.length; j++) {
|
|
207
|
+
results.set(batch[j], resolved[j]);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return results;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Resolve a single ticker (no cache check — used by batch after cache miss).
|
|
214
|
+
*/
|
|
215
|
+
async function resolveSingle(normalizedTicker) {
|
|
216
|
+
const cacheKey = `ticker-sic:${normalizedTicker}`;
|
|
217
|
+
const cik = tickerCikMap[normalizedTicker];
|
|
218
|
+
if (!cik) {
|
|
219
|
+
getLogger().debug(`[TickerResolver] No CIK found for ticker: ${normalizedTicker}`);
|
|
220
|
+
await cacheMiss(cacheKey);
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const sicCode = await fetchSicCode(cik);
|
|
224
|
+
if (!sicCode) {
|
|
225
|
+
await cacheMiss(cacheKey);
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
const sector = sicToSector(sicCode);
|
|
229
|
+
if (!sector) {
|
|
230
|
+
getLogger().debug(`[TickerResolver] SIC ${sicCode} has no sector mapping for ${normalizedTicker}`);
|
|
231
|
+
await cacheMiss(cacheKey);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
const result = { sector, sicCode, confidence: 1.0 };
|
|
235
|
+
try {
|
|
236
|
+
await getCache().set(cacheKey, result, SIC_CACHE_TTL);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// Non-fatal
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Cache a null result to avoid repeated lookups for unresolvable tickers.
|
|
245
|
+
*/
|
|
246
|
+
async function cacheMiss(cacheKey) {
|
|
247
|
+
try {
|
|
248
|
+
await getCache().set(cacheKey, 'null', SIC_CACHE_TTL);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Non-fatal
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=ticker-industry-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticker-industry-resolver.js","sourceRoot":"","sources":["../src/ticker-industry-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019-2025 Mark Sandford
|
|
3
|
+
* Licensed under the MIT License. See LICENSE and NOTICE files.
|
|
4
|
+
*/
|
|
5
|
+
import type { IndustrySector } from './industry-taxonomy';
|
|
6
|
+
/** Result of resolving a single LDA government_entities string. */
|
|
7
|
+
export interface GovernmentEntityResolution {
|
|
8
|
+
/** Original text from the LDA filing. */
|
|
9
|
+
rawText: string;
|
|
10
|
+
/** Resolution outcome. */
|
|
11
|
+
type: 'committee' | 'agency' | 'noise' | 'unresolved';
|
|
12
|
+
/** Committee code (e.g., "SSFI") if resolved to a committee. */
|
|
13
|
+
committeeCode?: string;
|
|
14
|
+
/** Committee name if resolved. */
|
|
15
|
+
committeeName?: string;
|
|
16
|
+
/** Agency slug if resolved to an agency. */
|
|
17
|
+
agencySlug?: string;
|
|
18
|
+
/** Resolution confidence: 1.0 for exact, 0.85+ for fuzzy, 0 for noise. */
|
|
19
|
+
confidence: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Result of resolving a stock ticker to an industry sector.
|
|
23
|
+
* Returns null for ETFs, mutual funds, and unresolvable tickers.
|
|
24
|
+
*/
|
|
25
|
+
export interface TickerResolution {
|
|
26
|
+
sector: IndustrySector;
|
|
27
|
+
sicCode: string;
|
|
28
|
+
confidence: number;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,mEAAmE;AACnE,MAAM,WAAW,0BAA0B;IACzC,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,CAAC;IACtD,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@civiq/entity-resolution",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Entity resolution for civic data — committee/agency alias matching, industry taxonomy, ticker-to-sector resolution, FEC entity deduplication",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./industry-taxonomy": {
|
|
14
|
+
"types": "./dist/industry-taxonomy.d.ts",
|
|
15
|
+
"import": "./dist/industry-taxonomy.js"
|
|
16
|
+
},
|
|
17
|
+
"./committee-agency-map": {
|
|
18
|
+
"types": "./dist/committee-agency-map.d.ts",
|
|
19
|
+
"import": "./dist/committee-agency-map.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"data"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"clean": "rm -rf dist"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"fuse.js": "^7.0.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "^5.8.0"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"author": "Mark Sandford",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/civiq/entity-resolution"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"entity-resolution",
|
|
45
|
+
"civic",
|
|
46
|
+
"government",
|
|
47
|
+
"committee",
|
|
48
|
+
"fec",
|
|
49
|
+
"civic-tech"
|
|
50
|
+
]
|
|
51
|
+
}
|