-
Notifications
You must be signed in to change notification settings - Fork 4
Corporate Financial Sanctions Intelligence Scripts
This section details the specialized Python scripts used for gathering and analyzing corporate structures, financial filings, and global sanctions lists. These tools are primarily utilized during Phase 3 (Collation & Entity Resolution) and Phase 4 (Chronological & Relational Processing) to verify identities and map financial networks.
The corporate_intel.py script provides a unified interface for cross-jurisdictional company research. It aggregates data from multiple international registries to build a comprehensive profile of legal entities.
The script implements specific wrapper classes for various global data providers:
| Provider | Class Name | Authentication | Data Scope |
|---|---|---|---|
| UK Companies House | CompaniesHouse |
API Key (CH_API_KEY) |
GB Registration, Officers, PSC |
| US SEC EDGAR | SECEdgar |
User-Agent only | US Public Filings (10-K, etc.), CIK |
| GLEIF | GLEIF |
None | Global LEI records, parent entities |
| ICIJ | ICIJOffshoreLeaks |
None | Offshore Leaks reconciliation |
The primary entry point is the CorporateIntel class, which orchestrates searches across all enabled providers.
-
Entity Search:
CorporateIntel.investigate(query)triggers parallel searches. -
Standardization: Raw responses are mapped to a
CompanyRecorddataclass. -
Deep Dive: For UK entities,
get_officersandget_psc(Persons with Significant Control) are called to resolve beneficial ownership.
This diagram maps the logical data sources to their respective Python implementation classes.
Title: Corporate Intelligence Data Flow
graph TD
subgraph "Natural_Language_Space"
A["Company Name / Query"]
B["Beneficial Ownership"]
C["Global Identifier (LEI)"]
end
subgraph "Code_Entity_Space"
D["CorporateIntel.investigate()"]
E["CompaniesHouse.search()"]
F["SECEdgar.search()"]
G["GLEIF.search()"]
H["CompanyRecord (Dataclass)"]
I["CompaniesHouse.get_psc()"]
end
A --> D
D --> E
D --> F
D --> G
E --> H
F --> H
G --> H
B --> I
I --> H
The financial_analysis.py script performs forensic accounting on US public company filings retrieved via the SEC EDGAR API. It focuses on identifying statistical anomalies and financial distress.
The script implements three primary analytical frameworks:
-
Benford's Law Test:
benfords_law_test(values)checks the distribution of the first digits in financial data. It calculates a chi-squared statistic to detect potential manual manipulation. -
Altman Z-Score:
altman_z_score(...)predicts bankruptcy risk by weighing five financial ratios (Working Capital, Retained Earnings, EBIT, Market Cap, and Revenue) against Total Assets. -
YoY Variance:
yoy_variance(values, labels)flags year-over-year changes exceeding a 20% threshold.
The FinancialAnalyser class uses get_company_facts(cik) to fetch XBRL data directly from the SEC. It then uses extract_metric_series to normalize disparate taxonomy tags (e.g., us-gaap:Revenues) into a time-series list for analysis.
The sanctions_screen.py script facilitates fuzzy matching of names against global sanctions lists, including OFAC (US) and HMT (UK).
The SanctionsScreener class employs a multi-tiered matching strategy to account for spelling variations and aliases:
-
Normalization: The
normalise_namefunction strips titles (MR, SIR, etc.) and punctuation, converting strings to uppercase. - Exact Match: Direct comparison of normalized strings.
-
Fuzzy Match: Uses Jaro-Winkler similarity (via the
jellyfishlibrary) to generate a score between 0.0 and 1.0. - Phonetic Match: Generates Soundex and Metaphone keys to identify names that sound similar but are spelled differently.
The SanctionsListManager handles the lifecycle of the data:
-
download_lists(): Fetches CSV data from official government URLs. -
load_all(): Parses OFAC SDN and UK HMT lists into memory-resident entries.
This diagram bridges the requirement for "Fuzzy Matching" to the specific implementation logic in the script.
Title: Sanctions Matching Pipeline
graph LR
subgraph "Natural_Language_Space"
Name["Subject Name"]
List["Sanctions List (CSV)"]
end
subgraph "Code_Entity_Space"
S1["normalise_name()"]
S2["SanctionsListManager.load_all()"]
S3["SanctionsScreener.screen()"]
S4["jellyfish.jaro_winkler_similarity()"]
S5["SanctionsMatch (Dataclass)"]
end
Name --> S1
List --> S2
S1 --> S3
S2 --> S3
S3 --> S4
S4 --> S5