Spaces:
Runtime error
Runtime error
Upload financial_analyzer.py
Browse files- financial_analyzer.py +85 -79
financial_analyzer.py
CHANGED
|
@@ -78,102 +78,108 @@ class FinancialAnalyzer:
|
|
| 78 |
"""
|
| 79 |
financial_data = []
|
| 80 |
|
| 81 |
-
# Step 1: Get company filings to
|
| 82 |
filings_10k = self.edgar_client.get_company_filings(cik, ['10-K'])
|
| 83 |
filings_20f = self.edgar_client.get_company_filings(cik, ['20-F'])
|
| 84 |
-
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
if not all_filings:
|
| 89 |
return []
|
| 90 |
|
| 91 |
-
# Step 2:
|
| 92 |
-
|
| 93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
return []
|
| 95 |
|
| 96 |
-
# Step 3:
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
fiscal_years = set()
|
| 100 |
|
| 101 |
-
#
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
# Look for Revenue tags to map accession numbers to fiscal years
|
| 107 |
-
revenue_tags = ["Revenues", "RevenueFromContractWithCustomerExcludingAssessedTax",
|
| 108 |
-
"Revenue", "RevenueFromContractWithCustomer"]
|
| 109 |
-
|
| 110 |
-
for tag in revenue_tags:
|
| 111 |
-
if tag in source_data:
|
| 112 |
-
units = source_data[tag].get("units", {})
|
| 113 |
-
if "USD" in units:
|
| 114 |
-
for entry in units["USD"]:
|
| 115 |
-
form = entry.get("form", "")
|
| 116 |
-
fy = entry.get("fy", 0)
|
| 117 |
-
accn = entry.get("accn", "")
|
| 118 |
-
fp = entry.get("fp", "")
|
| 119 |
-
|
| 120 |
-
# Only consider annual reports for fiscal year determination
|
| 121 |
-
if form in ["10-K", "20-F"] and fy > 0 and (fp == "FY" or not fp):
|
| 122 |
-
# Store the mapping
|
| 123 |
-
if accn:
|
| 124 |
-
accession_to_fy[accn] = fy
|
| 125 |
-
fiscal_years.add(fy)
|
| 126 |
-
break
|
| 127 |
-
if fiscal_years:
|
| 128 |
-
break
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
-
# Step 5: Generate period list
|
| 154 |
periods = []
|
| 155 |
-
for
|
| 156 |
-
#
|
| 157 |
-
|
| 158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
for quarter in range(4, 0, -1):
|
| 160 |
-
periods.append(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
|
| 162 |
# Step 6: Get financial data for each period
|
| 163 |
-
for
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
year_str = period[2:] # Remove "FY" prefix
|
| 167 |
-
else:
|
| 168 |
-
year_str = period.split('Q')[0] if 'Q' in period else period
|
| 169 |
|
| 170 |
-
data = self.edgar_client.get_financial_data_for_period(cik,
|
| 171 |
|
| 172 |
-
# Add period info to result
|
| 173 |
if data and "period" in data:
|
| 174 |
-
#
|
| 175 |
-
if '
|
| 176 |
-
data["period"] = f"FY{
|
|
|
|
| 177 |
financial_data.append(data)
|
| 178 |
|
| 179 |
return financial_data
|
|
|
|
| 78 |
"""
|
| 79 |
financial_data = []
|
| 80 |
|
| 81 |
+
# Step 1: Get company filings to determine what was actually filed
|
| 82 |
filings_10k = self.edgar_client.get_company_filings(cik, ['10-K'])
|
| 83 |
filings_20f = self.edgar_client.get_company_filings(cik, ['20-F'])
|
| 84 |
+
all_annual_filings = filings_10k + filings_20f
|
| 85 |
|
| 86 |
+
if not all_annual_filings:
|
|
|
|
|
|
|
| 87 |
return []
|
| 88 |
|
| 89 |
+
# Step 2: Extract filing years from annual reports
|
| 90 |
+
# Use filing_date to determine the years we should query
|
| 91 |
+
filing_year_map = {} # Map: filing_year -> list of filings
|
| 92 |
+
|
| 93 |
+
for filing in all_annual_filings:
|
| 94 |
+
filing_date = filing.get('filing_date', '')
|
| 95 |
+
if filing_date and len(filing_date) >= 4:
|
| 96 |
+
try:
|
| 97 |
+
file_year = int(filing_date[:4])
|
| 98 |
+
if file_year not in filing_year_map:
|
| 99 |
+
filing_year_map[file_year] = []
|
| 100 |
+
filing_year_map[file_year].append(filing)
|
| 101 |
+
except ValueError:
|
| 102 |
+
continue
|
| 103 |
+
|
| 104 |
+
if not filing_year_map:
|
| 105 |
return []
|
| 106 |
|
| 107 |
+
# Step 3: Sort years in descending order and take the most recent N years
|
| 108 |
+
sorted_years = sorted(filing_year_map.keys(), reverse=True)
|
| 109 |
+
target_years = sorted_years[:years]
|
|
|
|
| 110 |
|
| 111 |
+
# Step 4: For each target year, we need to find the fiscal year from Company Facts
|
| 112 |
+
# Get company facts to map filing years to fiscal years
|
| 113 |
+
facts = self.edgar_client.get_company_facts(cik)
|
| 114 |
+
filing_to_fiscal_year = {} # Map: filing_year -> fiscal_year
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
+
if facts:
|
| 117 |
+
# Try to map filing years to fiscal years using Company Facts
|
| 118 |
+
for data_source in ["us-gaap", "ifrs-full"]:
|
| 119 |
+
if data_source in facts.get("facts", {}):
|
| 120 |
+
source_data = facts["facts"][data_source]
|
| 121 |
+
|
| 122 |
+
# Look for Revenue tag to get fiscal year mapping
|
| 123 |
+
revenue_tags = ["Revenues", "RevenueFromContractWithCustomerExcludingAssessedTax",
|
| 124 |
+
"Revenue", "RevenueFromContractWithCustomer"]
|
| 125 |
+
|
| 126 |
+
for tag in revenue_tags:
|
| 127 |
+
if tag in source_data:
|
| 128 |
+
units = source_data[tag].get("units", {})
|
| 129 |
+
if "USD" in units:
|
| 130 |
+
for entry in units["USD"]:
|
| 131 |
+
form = entry.get("form", "")
|
| 132 |
+
fy = entry.get("fy", 0)
|
| 133 |
+
filed = entry.get("filed", "") # Filing date
|
| 134 |
+
fp = entry.get("fp", "")
|
| 135 |
+
|
| 136 |
+
# Map filing year to fiscal year
|
| 137 |
+
if form in ["10-K", "20-F"] and fy > 0 and filed and (fp == "FY" or not fp):
|
| 138 |
+
if len(filed) >= 10: # Format: YYYY-MM-DD
|
| 139 |
+
try:
|
| 140 |
+
file_year = int(filed[:4])
|
| 141 |
+
# Store the mapping: filing_year -> fiscal_year
|
| 142 |
+
if file_year not in filing_to_fiscal_year:
|
| 143 |
+
filing_to_fiscal_year[file_year] = fy
|
| 144 |
+
except ValueError:
|
| 145 |
+
continue
|
| 146 |
+
break # Found revenue tag, no need to check more
|
| 147 |
|
| 148 |
+
# Step 5: Generate period list for target years
|
| 149 |
periods = []
|
| 150 |
+
for file_year in target_years:
|
| 151 |
+
# Try to get fiscal year from mapping, otherwise use filing year
|
| 152 |
+
fiscal_year = filing_to_fiscal_year.get(file_year, file_year)
|
| 153 |
+
|
| 154 |
+
# Add annual data for this fiscal year
|
| 155 |
+
periods.append({
|
| 156 |
+
'period': str(fiscal_year),
|
| 157 |
+
'type': 'annual',
|
| 158 |
+
'fiscal_year': fiscal_year,
|
| 159 |
+
'filing_year': file_year
|
| 160 |
+
})
|
| 161 |
+
|
| 162 |
+
# Add quarterly data for this fiscal year
|
| 163 |
for quarter in range(4, 0, -1):
|
| 164 |
+
periods.append({
|
| 165 |
+
'period': f"{fiscal_year}Q{quarter}",
|
| 166 |
+
'type': 'quarterly',
|
| 167 |
+
'fiscal_year': fiscal_year,
|
| 168 |
+
'filing_year': file_year
|
| 169 |
+
})
|
| 170 |
|
| 171 |
# Step 6: Get financial data for each period
|
| 172 |
+
for period_info in periods:
|
| 173 |
+
period = period_info['period']
|
| 174 |
+
fiscal_year = period_info['fiscal_year']
|
|
|
|
|
|
|
|
|
|
| 175 |
|
| 176 |
+
data = self.edgar_client.get_financial_data_for_period(cik, period)
|
| 177 |
|
|
|
|
| 178 |
if data and "period" in data:
|
| 179 |
+
# Add fiscal year prefix for annual data
|
| 180 |
+
if period_info['type'] == 'annual':
|
| 181 |
+
data["period"] = f"FY{fiscal_year}"
|
| 182 |
+
|
| 183 |
financial_data.append(data)
|
| 184 |
|
| 185 |
return financial_data
|