44
55@modelclass
66class DataPoint :
7- "An individual financial data point."
8- formula : Optional [str ] = None
7+ "Represents a single financial data point."
98 label : Optional [str ] = None
109 order : Optional [int ] = None
1110 unit : Optional [str ] = None
1211 value : Optional [float ] = None
12+ derived_from : Optional [list ] = None
13+ formula : Optional [str ] = None
14+ source : Optional [dict ] = None
1315 xpath : Optional [str ] = None
1416
1517 @staticmethod
1618 def from_dict (d ):
17- return DataPoint (** d )
19+ return DataPoint (
20+ label = d .get ("label" ),
21+ order = d .get ("order" ),
22+ unit = d .get ("unit" ),
23+ value = d .get ("value" ),
24+ derived_from = d .get ("derived_from" ),
25+ formula = d .get ("formula" ),
26+ source = d .get ("source" ),
27+ xpath = d .get ("xpath" ),
28+ )
1829
1930
2031@modelclass
@@ -286,43 +297,44 @@ def from_dict(d):
286297
287298@modelclass
288299class Financials :
289- "Contains financial data."
290- balance_sheet : Optional [Dict [str , DataPoint ]] = None
291- cash_flow_statement : Optional [CashFlowStatement ] = None
292- comprehensive_income : Optional [ComprehensiveIncome ] = None
293- income_statement : Optional [IncomeStatement ] = None
300+ """
301+ Contains data for:
302+ - balance_sheet
303+ - cash_flow_statement
304+ - comprehensive_income
305+ - income_statement
306+ Each is a dict of { 'SomeTag': DataPoint }, e.g. { 'NetIncomeLoss': DataPoint(...) }
307+ """
308+
309+ balance_sheet : Optional [dict ] = None
310+ cash_flow_statement : Optional [dict ] = None
311+ comprehensive_income : Optional [dict ] = None
312+ income_statement : Optional [dict ] = None
294313
295314 @staticmethod
296315 def from_dict (d ):
316+ def parse_statement (x ):
317+ if not x or not isinstance (x , dict ):
318+ return None
319+ return {k : DataPoint .from_dict (v ) for k , v in x .items ()}
320+
297321 return Financials (
298- balance_sheet = (
299- None
300- if "balance_sheet" not in d
301- else {
302- k : DataPoint .from_dict (v ) for (k , v ) in d ["balance_sheet" ].items ()
303- }
304- ),
305- cash_flow_statement = (
306- None
307- if "cash_flow_statement" not in d
308- else CashFlowStatement .from_dict (d ["cash_flow_statement" ])
309- ),
310- comprehensive_income = (
311- None
312- if "comprehensive_income" not in d
313- else ComprehensiveIncome .from_dict (d ["comprehensive_income" ])
314- ),
315- income_statement = (
316- None
317- if "income_statement" not in d
318- else IncomeStatement .from_dict (d ["income_statement" ])
319- ),
322+ balance_sheet = parse_statement (d .get ("balance_sheet" )),
323+ cash_flow_statement = parse_statement (d .get ("cash_flow_statement" )),
324+ comprehensive_income = parse_statement (d .get ("comprehensive_income" )),
325+ income_statement = parse_statement (d .get ("income_statement" )),
320326 )
321327
322328
323329@modelclass
324330class StockFinancial :
325- "StockFinancial contains historical financial data for a stock ticker."
331+ """
332+ StockFinancial contains historical financial data for a stock ticker.
333+ Augmented with new fields such as net_income_loss, diluted_earnings_per_share, etc.
334+ to avoid repeated dictionary lookups into 'financials' for common data.
335+ """
336+
337+ # Existing fields (unchanged):
326338 cik : Optional [str ] = None
327339 company_name : Optional [str ] = None
328340 end_date : Optional [str ] = None
@@ -333,20 +345,50 @@ class StockFinancial:
333345 source_filing_file_url : Optional [str ] = None
334346 source_filing_url : Optional [str ] = None
335347 start_date : Optional [str ] = None
348+ net_income_loss : Optional [float ] = None
349+ net_income_loss_attributable_to_parent : Optional [float ] = None
350+ diluted_earnings_per_share : Optional [float ] = None
336351
337352 @staticmethod
338353 def from_dict (d ):
339- return StockFinancial (
340- cik = d .get ("cik" , None ),
341- company_name = d .get ("company_name" , None ),
342- end_date = d .get ("end_date" , None ),
343- filing_date = d .get ("filing_date" , None ),
354+ """
355+ Create a StockFinancial, preserving all old behavior, but also pulling out
356+ a few commonly used fields from the income_statement and comprehensive_income
357+ so they can be accessed directly at the top level.
358+ """
359+ sf = StockFinancial (
360+ cik = d .get ("cik" ),
361+ company_name = d .get ("company_name" ),
362+ end_date = d .get ("end_date" ),
363+ filing_date = d .get ("filing_date" ),
344364 financials = (
345- None if "financials" not in d else Financials . from_dict ( d [ "financials" ])
365+ Financials . from_dict ( d [ "financials" ]) if "financials" in d else None
346366 ),
347- fiscal_period = d .get ("fiscal_period" , None ),
348- fiscal_year = d .get ("fiscal_year" , None ),
349- source_filing_file_url = d .get ("source_filing_file_url" , None ),
350- source_filing_url = d .get ("source_filing_url" , None ),
351- start_date = d .get ("start_date" , None ),
367+ fiscal_period = d .get ("fiscal_period" ),
368+ fiscal_year = d .get ("fiscal_year" ),
369+ source_filing_file_url = d .get ("source_filing_file_url" ),
370+ source_filing_url = d .get ("source_filing_url" ),
371+ start_date = d .get ("start_date" ),
352372 )
373+
374+ # If we have an income_statement, try to pull out new fields
375+ if sf .financials and sf .financials .income_statement :
376+ income_stmt = sf .financials .income_statement
377+ net_income_dp = income_stmt .get ("net_income_loss" )
378+ if net_income_dp and net_income_dp .value is not None :
379+ sf .net_income_loss = net_income_dp .value
380+
381+ diluted_eps_dp = income_stmt .get ("diluted_earnings_per_share" )
382+ if diluted_eps_dp and diluted_eps_dp .value is not None :
383+ sf .diluted_earnings_per_share = diluted_eps_dp .value
384+
385+ # If we have a comprehensive_income, pull out net income (parent)
386+ if sf .financials and sf .financials .comprehensive_income :
387+ comp_inc = sf .financials .comprehensive_income
388+ net_income_parent_dp = comp_inc .get (
389+ "net_income_loss_attributable_to_parent"
390+ )
391+ if net_income_parent_dp and net_income_parent_dp .value is not None :
392+ sf .net_income_loss_attributable_to_parent = net_income_parent_dp .value
393+
394+ return sf
0 commit comments