mirror of
https://github.com/shawnkim1997/All-in-one-Financial-Analysis.git
synced 2026-08-25 08:18:05 +00:00
feat: extend SEC parser for foreign private issuer annual filings (20-F)
- sec_parser detects 20-F filings and maps Item 3D/5/15/18 to the existing risk/MD&A/controls section keys - edgar router copy reads "annual filing" instead of "10-K" so the API surface covers both 10-K and 20-F - filings page renders a foreign-issuer section tab variant when the latest annual filing is a 20-F - New test_sec_parser covers the 20-F mapping plus regression on the original 10-K paths
This commit is contained in:
@@ -18,6 +18,14 @@ const SECTIONS_SEC: FilingSectionTab[] = [
|
||||
{ key: "item9a", label: "Item 9A: Controls & Procedures", short: "Controls", anchorId: "sec-item-9a" },
|
||||
];
|
||||
|
||||
const SECTIONS_SEC_FOREIGN: FilingSectionTab[] = [
|
||||
{ key: "item1a", label: "Item 3 / 3D: Risk Factors", short: "Risk Factors", anchorId: "sec-item-1a" },
|
||||
{ key: "item3", label: "Legal / Material Proceedings", short: "Legal", anchorId: "sec-item-3" },
|
||||
{ key: "item7", label: "Item 5: Operating & Financial Review", short: "OFR", anchorId: "sec-item-7" },
|
||||
{ key: "item8", label: "Item 18: Financial Statements", short: "Financials", anchorId: "sec-item-8" },
|
||||
{ key: "item9a", label: "Item 15: Controls & Procedures", short: "Controls", anchorId: "sec-item-9a" },
|
||||
];
|
||||
|
||||
const SECTIONS_DART: FilingSectionTab[] = [
|
||||
{ key: "item1a", label: "Investment Risk (II)", short: "Risk", anchorId: "dart-item-1a" },
|
||||
{ key: "item3", label: "Litigation", short: "Legal", anchorId: "dart-item-3" },
|
||||
@@ -34,9 +42,10 @@ const SECTIONS_EDINET: FilingSectionTab[] = [
|
||||
{ key: "item9a", label: "内部統制", short: "内部統制", anchorId: "edinet-item-9a" },
|
||||
];
|
||||
|
||||
function sectionsForJurisdiction(j: FilingJurisdiction): FilingSectionTab[] {
|
||||
function sectionsForJurisdiction(j: FilingJurisdiction, secForm: string | null): FilingSectionTab[] {
|
||||
if (j === "DART") return SECTIONS_DART;
|
||||
if (j === "EDINET") return SECTIONS_EDINET;
|
||||
if (secForm && secForm !== "10-K") return SECTIONS_SEC_FOREIGN;
|
||||
return SECTIONS_SEC;
|
||||
}
|
||||
|
||||
@@ -60,6 +69,7 @@ export default function FilingsPage() {
|
||||
const [error, setError] = useState<string>("");
|
||||
const [htmlVersion, setHtmlVersion] = useState(0);
|
||||
const [filingSource, setFilingSource] = useState<FilingJurisdiction | null>(null);
|
||||
const [secFilingForm, setSecFilingForm] = useState<string | null>(null);
|
||||
const [linkMap, setLinkMap] = useState<Record<string, string> | null>(null);
|
||||
const [infoMessage, setInfoMessage] = useState<string>("");
|
||||
const [translatedText, setTranslatedText] = useState<string>("");
|
||||
@@ -68,7 +78,10 @@ export default function FilingsPage() {
|
||||
|
||||
const previewJ = inferFilingJurisdiction(ticker);
|
||||
const activeJurisdiction = filingSource ?? previewJ;
|
||||
const sectionTabs = useMemo(() => sectionsForJurisdiction(activeJurisdiction), [activeJurisdiction]);
|
||||
const sectionTabs = useMemo(
|
||||
() => sectionsForJurisdiction(activeJurisdiction, activeJurisdiction === "SEC" ? secFilingForm : null),
|
||||
[activeJurisdiction, secFilingForm],
|
||||
);
|
||||
|
||||
async function loadFiling() {
|
||||
setLoading(true);
|
||||
@@ -78,6 +91,7 @@ export default function FilingsPage() {
|
||||
setAiSummary("");
|
||||
setLinkMap(null);
|
||||
setInfoMessage("");
|
||||
setSecFilingForm(null);
|
||||
const j = inferFilingJurisdiction(ticker);
|
||||
|
||||
try {
|
||||
@@ -90,6 +104,7 @@ export default function FilingsPage() {
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
setFilingSource(mapApiSource(data.source));
|
||||
setSecFilingForm(typeof data.filing_form === "string" ? data.filing_form : "10-K");
|
||||
setSections({
|
||||
item1a: data.item1a || "",
|
||||
item3: data.item3 || "",
|
||||
@@ -101,6 +116,9 @@ export default function FilingsPage() {
|
||||
if (data.links && typeof data.links === "object") {
|
||||
setLinkMap(data.links as Record<string, string>);
|
||||
}
|
||||
if (typeof data.message === "string" && data.message) {
|
||||
setInfoMessage(data.message);
|
||||
}
|
||||
setActiveSection("item7");
|
||||
setHtmlVersion((v) => v + 1);
|
||||
setLoaded(true);
|
||||
@@ -269,8 +287,8 @@ export default function FilingsPage() {
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: "10-K Annual Report (SEC)",
|
||||
body: "Downloads the latest 10-K from SEC EDGAR. The filing is shown with original HTML tables and emphasis, restyled for the terminal dark theme. Section tabs scroll to Item 1A, MD&A, and more.",
|
||||
title: "Annual Report (SEC)",
|
||||
body: "Downloads the latest annual SEC filing from EDGAR. US issuers typically use 10-K, while ADRs and foreign issuers often use 20-F or 40-F. The filing is shown with original HTML tables and emphasis, with section tabs for risk factors, management discussion, financials, and controls.",
|
||||
};
|
||||
}, [previewJ]);
|
||||
|
||||
@@ -319,7 +337,7 @@ export default function FilingsPage() {
|
||||
{loading
|
||||
? "Loading..."
|
||||
: previewJ === "SEC"
|
||||
? "Load 10-K Filing"
|
||||
? "Load SEC Annual Filing"
|
||||
: previewJ === "DART"
|
||||
? "Load DART Report"
|
||||
: "Load EDINET filing"}
|
||||
|
||||
Reference in New Issue
Block a user