Back to blog
tutorialdata

Japanese Financial Data with Python: A Practical Guide

Onkar Dahale

If you want Japanese financial data in Python today, your options are: scrape Yahoo Finance Japan and hope the HTML doesn't change, pay ¥3M/year for a Bloomberg terminal, or spend two weeks writing an XBRL parser that handles three accounting standards and Shift-JIS encoding.

Or you can do this:

from axiora import Axiora

client = Axiora(api_key="your-key")
toyota = client.companies.retrieve_financials("7203", years=1)
print(f"Revenue: ¥{toyota.data[0].revenue:,}")
# Revenue: ¥29,929,992,000,000

Toyota's audited revenue. Typed, auto-completed in your IDE, parsed from XBRL — not scraped from HTML. This tutorial shows you how to go from that first call to screening, comparing, and charting 4,125+ Japanese companies.

What You'll Need

pip install axiora

That's it. The SDK is generated by Stainless — the same tool that builds the SDKs for OpenAI, Anthropic, and Cloudflare. Typed Pydantic models for every response, automatic retries, pagination built in. No JSON wrangling.

Setup

from axiora import Axiora

client = Axiora(api_key="your-api-key")

One import, one line. The client also reads AXIORA_API_KEY from your environment if you prefer not to hardcode it. All monetary values come back as JPY integers — no floats touching the money.

Get Any Company's Financials

Securities code 7203 — the same 4-digit ticker you see on the TSE:

financials = client.companies.retrieve_financials("7203", years=5)

for f in financials.data:
    rev = f.revenue / 1_000_000_000_000
    ni = f.net_income / 1_000_000_000_000
    print(f"  {f.fiscal_year}  Rev: ¥{rev:.1f}T  NI: ¥{ni:.2f}T")
  2024  Rev: ¥29.9T  NI: ¥4.94T
  2023  Rev: ¥37.2T  NI: ¥2.45T
  2022  Rev: ¥31.4T  NI: ¥2.85T
  2021  Rev: ¥27.2T  NI: ¥2.25T
  2020  Rev: ¥29.9T  NI: ¥2.08T

Five years of Toyota's financials. Every number from an audited 有価証券報告書, parsed from XBRL and normalized across accounting standards. The response is a typed Pydantic model — f.revenue auto-completes in your IDE, no guessing field names from JSON.

The API also accepts EDINET codes (E02144). Both resolve to the same company.

Company Details

company = client.companies.retrieve("7203")
c = company.data

print(f"Name (JP): {c.name_jp}")
print(f"Name (EN): {c.name_en}")
print(f"EDINET:    {c.edinet_code}")
print(f"Ticker:    {c.securities_code}")
print(f"Sector:    {c.sector}")
Name (JP): トヨタ自動車株式会社
Name (EN): TOYOTA MOTOR CORPORATION
EDINET:    E02144
Ticker:    7203
Sector:    輸送用機器

Screen: Find What's Interesting

"Show me Japanese companies with ROE above 15% and revenue over ¥100 billion, sorted by ROE." One call:

screen = client.screen.retrieve(
    roe_min=15.0,
    revenue_min=100_000_000_000,
    sort="roe_desc",
    limit=10,
)

for r in screen.data:
    name = r.company.name_en or r.company.name_jp
    roe = r.metrics.roe
    rev_b = r.financials.revenue / 1_000_000_000
    print(f"  {name[:30]:<30}  ROE: {roe:.1f}%  Rev: ¥{rev_b:,.0f}B")

The underlying data is the same — audited EDINET filings. Bloomberg gives you a terminal with real-time prices, news, and a thousand other things. But for screening by fundamentals from annual reports, you don't need one.

Filter by roe_min, roe_max, revenue_min, revenue_max, net_income_min, roa_min, sector, and more. Sort by any metric, ascending or descending.

Compare Competitors

Toyota (7203), Honda (7267), Nissan (7201) — side by side:

codes = ["7203", "7267", "7201"]

for code in codes:
    company = client.companies.retrieve(code)
    financials = client.companies.retrieve_financials(code, years=3)

    print(f"\n{company.data.name_en}")
    for f in financials.data:
        rev = f.revenue / 1_000_000_000_000
        ni = f.net_income / 1_000_000_000
        print(f"  {f.fiscal_year}  Rev: ¥{rev:.1f}T  NI: ¥{ni:,.0f}B")

Six API calls, three companies, three years each. The numbers tell you Toyota is 2x Honda in revenue and 4x in profitability. Nissan is in a different situation entirely.

Chart: 10 Years of Revenue

Three companies, three very different growth stories. Toyota for scale, Sony for the turnaround, Keyence for compounding:

pip install axiora matplotlib
from axiora import Axiora
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker

client = Axiora()  # reads AXIORA_API_KEY from env

companies = {"7203": "Toyota", "6758": "Sony", "6861": "Keyence"}

fig, ax = plt.subplots(figsize=(10, 6))
for code, label in companies.items():
    financials = client.companies.retrieve_financials(code, years=10)

    years = [f.fiscal_year for f in reversed(financials.data)]
    rev = [f.revenue / 1e12 for f in reversed(financials.data)]
    ax.plot(years, rev, marker="o", label=label, linewidth=2)

ax.set_ylabel("Revenue (¥ Trillion)")
ax.set_title("Toyota vs Sony vs Keyence — 10 Year Revenue")
ax.legend()
ax.grid(True, alpha=0.3)
ax.yaxis.set_major_formatter(mticker.FormatStrFormatter("¥%.0fT"))
plt.tight_layout()
plt.savefig("japan_revenue.png", dpi=150)

Toyota dominates on scale. But look at the slopes. Keyence — a ¥2 trillion sensor company most people outside Japan haven't heard of — has been compounding revenue at 15%+ annually for a decade.

Growth Rates

Let's quantify that:

growth = client.companies.retrieve_growth("6861", years=10)

print("Keyence — YoY Revenue Growth")
for entry in growth.data.yoy:
    g = entry.growth.revenue
    if g is not None:
        bar = "█" * int(abs(g))
        sign = "+" if g >= 0 else ""
        print(f"  {entry.fiscal_year}  {sign}{g:>6.1f}%  {bar}")

cagr = growth.data.cagr
if cagr.api_5yr:
    print(f"\n  5-Year CAGR: {cagr.api_5yr.revenue:.1f}%")

CAGR, year-over-year, all pre-computed. Because you shouldn't need to do arithmetic on raw revenue numbers to answer "is this company growing?"

Sector Rankings

Highest ROE in electronics — Japan's most competitive sector:

ranking = client.rankings.retrieve(
    "roe",
    sector="電気機器",
    limit=10,
)

for r in ranking.data:
    name = (r.company.name_en or r.company.name_jp)[:35]
    print(f"  #{r.rank:<3} {name:<35}  ROE: {r.value:.1f}%")

Sector names are in Japanese (that's how EDINET classifies them): 電気機器 (electronics), 輸送用機器 (transport equipment), 情報・通信業 (IT/telecom), 銀行業 (banking).

Async Support

Building something concurrent? The SDK has a full async client:

import asyncio
from axiora import AsyncAxiora

async def main():
    async with AsyncAxiora() as client:
        # Fetch multiple companies in parallel
        tasks = [
            client.companies.retrieve_financials(code, years=5)
            for code in ["7203", "6758", "6861", "9984", "6501"]
        ]
        results = await asyncio.gather(*tasks)

        for result in results:
            f = result.data[0]
            print(f"  {f.edinet_code}  Rev: ¥{f.revenue/1e12:.1f}T")

asyncio.run(main())

Same typed responses, same error handling, just await everything.

Error Handling

The SDK raises typed exceptions:

from axiora import NotFoundError, RateLimitError

try:
    client.companies.retrieve("INVALID")
except NotFoundError:
    print("Company not found")
except RateLimitError as e:
    print(f"Rate limited — retry after {e.response.headers.get('Retry-After')}s")

No checking status codes. No parsing error JSON. Just catch and handle.

The Full Script

Everything above, copy-paste ready:

#!/usr/bin/env python3
"""Japanese financial data with Python — Axiora quick start."""

from axiora import Axiora

client = Axiora()  # reads AXIORA_API_KEY from env

# Toyota financials
print("=== Toyota (7203) ===")
for f in client.companies.retrieve_financials("7203", years=5).data:
    print(f"  {f.fiscal_year}  Rev: ¥{f.revenue/1e12:.1f}T  NI: ¥{f.net_income/1e12:.2f}T")

# High-ROE screen
print("\n=== ROE > 15%, Revenue > ¥100B ===")
for r in client.screen.retrieve(
    roe_min=15, revenue_min=100_000_000_000, sort="roe_desc", limit=10
).data:
    name = (r.company.name_en or r.company.name_jp)[:30]
    print(f"  {name:<30}  ROE: {r.metrics.roe:.1f}%")

# Electronics ranking
print("\n=== Electronics — Top ROE ===")
for r in client.rankings.retrieve("roe", sector="電気機器", limit=10).data:
    name = (r.company.name_en or r.company.name_jp)[:30]
    print(f"  #{r.rank:<3} {name:<30}  {r.value:.1f}%")

print("\nAll data: audited EDINET filings, XBRL-parsed.")

Keep Going

Free tier. No credit card. No "contact sales." Get your API key →