| name | financials |
| description | Extract structured financials from Icelandic annual report PDFs using Docling — income statement, balance sheet, cash flow, ratios. |
Financials (Annual Report Extraction)
Extract structured financial data from Icelandic annual reports (ársreikningar) using AI-powered PDF parsing.
Overview
This skill combines:
- skatturinn skill - Downloads annual report PDFs
- Docling - IBM's PDF extraction with 97.9% table accuracy
- Claude interpretation - Standardizes extracted data into structured format
Pipeline
Company kennitala
↓
skatturinn.py download (PDF)
↓
Docling (markdown + tables)
↓
Claude (structured JSON)
↓
Standardized financial data
Output Schema
interface CompanyFinancials {
company_name: string;
kennitala: string;
fiscal_year: number;
report_type: "full" | "hnappurinn" | "consolidated";
income: {
revenue: number;
operating_expenses: number;
ebitda: number;
depreciation: number;
ebit: number;
financial_income: number;
financial_expenses: number;
profit_before_tax: number;
income_tax: number;
net_profit: number;
};
balance: {
fixed_assets: number;
current_assets: number;
total_assets: number;
share_capital: number;
retained_earnings: number;
total_equity: number;
long_term_debt: number;
short_term_debt: number;
total_liabilities: number;
};
cashflow?: {
operating: number;
investing: number;
financing: number;
net_change: number;
};
ownership: Array<{
name: string;
kennitala?: string;
birth_year_month?: string;
percentage: number;
type: "direct" | "indirect";
}>;
parent_company?: {
name: string;
kennitala: string;
ownership_pct: number;
};
subsidiaries: Array<{
name: string;
kennitala: string;
ownership_pct: number;
book_value?: number;
equity_method: boolean;
}>;
associates: Array<{
name: string;
kennitala: string;
ownership_pct: number;
book_value?: number;
}>;
metrics: {
equity_ratio: number;
current_ratio?: number;
debt_to_equity?: number;
profit_margin?: number;
};
events: Array<{
type: "acquisition" | "investment" | "dividend" | "restructuring" | "other";
description: string;
amount?: number;
}>;
extraction: {
source_pdf: string;
extracted_at: string;
confidence: "high" | "medium" | "low";
notes: string[];
};
}
Bank-Specific Schema
Banks have a different financial structure than commercial companies:
interface BankFinancials {
bank_name: string;
kennitala: string;
fiscal_year: number;
report_type: "parent" | "consolidated" | "quarterly";
income: {
interest_income: number;
interest_expense: number;
net_interest_income: number;
fee_income: number;
fee_expense: number;
net_fee_income: number;
total_operating_income: number;
total_operating_expense: number;
bank_tax: number;
impairment: number;
net_profit: number;
};
balance: {
loans_to_customers: number;
deposits_from_customers: number;
total_assets: number;
total_equity: number;
};
capital: {
cet1_ratio: number;
tier1_ratio: number;
total_car: number;
rwa: number;
lcr: number;
nsfr: number;
};
metrics: {
roe: number;
nim: number;
cost_income_ratio: number;
npl_ratio: number;
dividend_total: number;
buybacks: number;
payout_ratio: number;
};
}
Icelandic Financial Terms
| Icelandic | English | Schema Field |
|---|
| Rekstrartekjur | Revenue | income.revenue |
| Rekstrargjöld | Operating expenses | income.operating_expenses |
| Afskriftir | Depreciation | income.depreciation |
| Fjármunatekjur | Financial income | income.financial_income |
| Fjármagnsgjöld | Financial expenses | income.financial_expenses |
| Tekjuskattur | Income tax | income.income_tax |
| Hagnaður ársins | Net profit | income.net_profit |
| Fastafjármunir | Fixed assets | balance.fixed_assets |
| Veltufjármunir | Current assets | balance.current_assets |
| Hlutafé | Share capital | balance.share_capital |
| Eigið fé | Equity | balance.total_equity |
| Langtímaskuldir | Long-term debt | balance.long_term_debt |
| Skammtímaskuldir | Short-term debt | balance.short_term_debt |
| Arðgreiðslur | Dividends | events (type: dividend) |
| Dótturfélög | Subsidiaries | subsidiaries[] |
| Hlutdeildarfélög | Associates (20-50%) | associates[] |
| Móðurfélag | Parent company | parent_company |
| Eignarhlutir í dótturfélögum | Shares in subsidiaries | subsidiaries[].book_value |
| Samstæða | Group/Consolidated | report_type: "consolidated" |
CLI Usage
Standard Companies
uv run python scripts/financials.py extract /path/to/report.pdf
uv run python scripts/financials.py company 5012043070 --year 2024
uv run python scripts/financials.py company 5012043070 --year 2024 --format json
Banks (Arion, Íslandsbanki, Landsbankinn)
Banks have different financial statement structures. Use the --bank flag or dedicated bank command:
uv run python scripts/financials.py extract /path/to/arion_2024.pdf --bank
uv run python scripts/financials.py bank 5810080150 --year 2024
uv run python scripts/financials.py bank 4910083880 --year 2024
uv run python scripts/financials.py bank 4710044100 --year 2024
uv run python scripts/financials.py bank-schema
Bank Kennitalas
| Bank | Kennitala |
|---|
| Arion banki hf. | 5810080150 |
| Íslandsbanki hf. | 4910083880 |
| Landsbankinn hf. | 4710044100 |
| Kvika banki hf. | 5407992500 |
Docling Integration
Setup
uv sync
Basic Extraction
from docling.document_converter import DocumentConverter
def extract_pdf(pdf_path: str) -> tuple[str, list[dict]]:
"""Extract markdown and tables from PDF."""
converter = DocumentConverter()
result = converter.convert(pdf_path)
markdown = result.document.export_to_markdown()
tables = []
for table in result.document.tables:
tables.append({
"dataframe": table.export_to_dataframe().to_dict(),
})
return markdown, tables
Table Detection
Docling's TableFormer model handles:
- Multi-row headers
- Merged cells
- Nested tables
- Currency formatting (ISK with dots: 1.234.567)
Claude Interpretation
After Docling extracts the content, use Claude to interpret and standardize:
EXTRACTION_PROMPT = '''
Extract structured financial data from this Icelandic annual report.
DOCUMENT:
{markdown}
TABLES:
{tables_json}
Return a JSON object matching this schema:
{schema}
Guidelines:
1. All amounts in ISK (Icelandic króna), no thousands separators
2. Negative values for expenses/losses (use actual signs from document)
3. Calculate metrics if raw data available
4. Note any unusual items in events[]
5. Set confidence based on data completeness
6. If "Hnappurinn" format, mark report_type accordingly
Return ONLY valid JSON, no markdown.
'''
Report Types
Hnappurinn (Micro-company)
- 4-page simplified format
- No detailed notes
- No ownership section in PDF
- Fields: revenue, expenses, profit, basic balance sheet
Full Ársreikningur
- Complete financial statements
- Auditor's report
- Detailed notes
- Ownership/shareholder tables
- Cash flow statement
Consolidated (Samstæðureikningur)
- Group financials
- Subsidiary breakdown
- Intercompany eliminations
Data Quality Notes
-
Currency: All figures in ISK. Watch for thousands (þús.kr.) vs millions (m.kr.) notation.
-
Fiscal Year: Most companies use calendar year, but some differ. Check "Reikningsár" field.
-
Comparatives: Reports show current year + prior year. Extract both for trend analysis.
-
Rounding: Hnappurinn reports often round to thousands. Full reports may have exact figures.
-
Negative Signs: Expenses sometimes shown as positive numbers with context, sometimes with parentheses or minus signs.
Integration with skatturinn
from scripts.skatturinn import download_annual_report, get_company_info
from scripts.financials import extract_financials
async def get_company_financials(kennitala: str, year: int):
"""Full pipeline: fetch PDF, extract, standardize."""
info = await get_company_info(kennitala)
pdf_path = await download_annual_report(kennitala, year)
financials = extract_financials(pdf_path, info)
return financials
Evidence Integration
Store extracted financials in /data/processed/financials/:
/data/processed/financials/
/{kennitala}/
/2024.json # Full extracted data
/2023.json
/summary.csv # Multi-year comparison
SQL queries in /evidence-reports/sources/financials/:
SELECT
fiscal_year,
income_revenue,
income_net_profit,
balance_total_equity,
metrics_equity_ratio
FROM read_json_auto('../data/processed/financials/5012043070/*.json')
ORDER BY fiscal_year
Corporate Structure Mapping
Data Sources
| Data | Source | Method |
|---|
| Parent company | skatturinn page | Beneficial owners with company kennitala |
| Subsidiaries | Annual report PDF | Notes section, "Eignarhlutir í dótturfélögum" |
| Associates | Annual report PDF | "Hlutdeildarfélög" section |
| Group structure | Recursive lookup | Follow kennitalas both directions |
Deriving Parent Company
From skatturinn ownership scraping, if a beneficial owner has a company kennitala (starts with 4-7), that's a parent company:
for owner in company.beneficial_owners:
if owner.is_company:
financials.parent_company = {
"name": owner.name,
"kennitala": owner.kennitala,
"ownership_pct": owner.ownership_pct
}
Extracting Subsidiaries from PDF
Look for these patterns in annual report notes:
Eignarhlutir í dótturfélögum:
| Nafn | Kennitala | Eignarhlutur | Bókfært virði |
|------|-----------|--------------|---------------|
| ABC ehf. | 1234567890 | 100% | 50.000.000 |
Also check balance sheet line "Eignarhlutir í dóttur- og hlutdeildarfélögum" - if > 0, there are subsidiaries.
Ownership Classifications
| Ownership % | Classification | Accounting |
|---|
| >50% | Dótturfélag (Subsidiary) | Full consolidation |
| 20-50% | Hlutdeildarfélag (Associate) | Equity method |
| <20% | Fjárfesting (Investment) | Cost/fair value |
Building Group Tree
async def build_group_structure(root_kennitala: str) -> dict:
"""
Build complete group structure:
- Look UP: find parent companies
- Look DOWN: find subsidiaries
"""
company = await get_company_financials(root_kennitala)
structure = {
"company": company,
"parents": [],
"subsidiaries": []
}
if company.parent_company:
parent_structure = await build_group_structure(
company.parent_company.kennitala
)
structure["parents"].append(parent_structure)
for sub in company.subsidiaries:
sub_structure = await build_group_structure(sub.kennitala)
structure["subsidiaries"].append(sub_structure)
return structure
CLI Commands
uv run python scripts/financials.py company 5012043070 --include-structure
uv run python scripts/financials.py group 5012043070 --depth 3
uv run python scripts/financials.py ultimate-parent 5012043070
Related Skills