Spaces:
Sleeping
Sleeping
| import os | |
| from textwrap import dedent | |
| from typing import Annotated | |
| from datetime import timedelta, datetime | |
| from ..data_source import YFinanceUtils, SECUtils, FMPUtils | |
| def combine_prompt(instruction, resource, table_str=None): | |
| if table_str: | |
| prompt = f"{table_str}\n\nResource: {resource}\n\nInstruction: {instruction}" | |
| else: | |
| prompt = f"Resource: {resource}\n\nInstruction: {instruction}" | |
| return prompt | |
| def save_to_file(data: str, file_path: str): | |
| os.makedirs(os.path.dirname(file_path), exist_ok=True) | |
| with open(file_path, "w") as f: | |
| f.write(data) | |
| class ReportAnalysisUtils: | |
| def analyze_income_stmt( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the income statement for the given ticker symbol with the related section of its 10-K report. | |
| Then return with an instruction on how to analyze the income statement. | |
| """ | |
| # Retrieve the income statement | |
| income_stmt = YFinanceUtils.get_income_stmt(ticker_symbol) | |
| df_string = "Income statement:\n" + income_stmt.to_string().strip() | |
| # Analysis instruction | |
| instruction = dedent( | |
| """ | |
| Conduct a comprehensive analysis of the company's income statement for the current fiscal year. | |
| Start with an overall revenue record, including Year-over-Year or Quarter-over-Quarter comparisons, | |
| and break down revenue sources to identify primary contributors and trends. Examine the Cost of | |
| Goods Sold for potential cost control issues. Review profit margins such as gross, operating, | |
| and net profit margins to evaluate cost efficiency, operational effectiveness, and overall profitability. | |
| Analyze Earnings Per Share to understand investor perspectives. Compare these metrics with historical | |
| data and industry or competitor benchmarks to identify growth patterns, profitability trends, and | |
| operational challenges. The output should be a strategic overview of the company’s financial health | |
| in a single paragraph, less than 130 words, summarizing the previous analysis into 4-5 key points under | |
| respective subheadings with specific discussion and strong data support. | |
| """ | |
| ) | |
| # Retrieve the related section from the 10-K report | |
| section_text = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| # Combine the instruction, section text, and income statement | |
| prompt = combine_prompt(instruction, section_text, df_string) | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def analyze_balance_sheet( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the balance sheet for the given ticker symbol with the related section of its 10-K report. | |
| Then return with an instruction on how to analyze the balance sheet. | |
| """ | |
| balance_sheet = YFinanceUtils.get_balance_sheet(ticker_symbol) | |
| df_string = "Balance sheet:\n" + balance_sheet.to_string().strip() | |
| instruction = dedent( | |
| """ | |
| Delve into a detailed scrutiny of the company's balance sheet for the most recent fiscal year, pinpointing | |
| the structure of assets, liabilities, and shareholders' equity to decode the firm's financial stability and | |
| operational efficiency. Focus on evaluating the liquidity through current assets versus current liabilities, | |
| the solvency via long-term debt ratios, and the equity position to gauge long-term investment potential. | |
| Contrast these metrics with previous years' data to highlight financial trends, improvements, or deteriorations. | |
| Finalize with a strategic assessment of the company's financial leverage, asset management, and capital structure, | |
| providing insights into its fiscal health and future prospects in a single paragraph. Less than 130 words. | |
| """ | |
| ) | |
| section_text = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| prompt = combine_prompt(instruction, section_text, df_string) | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def analyze_cash_flow( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the cash flow statement for the given ticker symbol with the related section of its 10-K report. | |
| Then return with an instruction on how to analyze the cash flow statement. | |
| """ | |
| cash_flow = YFinanceUtils.get_cash_flow(ticker_symbol) | |
| df_string = "Cash flow statement:\n" + cash_flow.to_string().strip() | |
| instruction = dedent( | |
| """ | |
| Dive into a comprehensive evaluation of the company's cash flow for the latest fiscal year, focusing on cash inflows | |
| and outflows across operating, investing, and financing activities. Examine the operational cash flow to assess the | |
| core business profitability, scrutinize investing activities for insights into capital expenditures and investments, | |
| and review financing activities to understand debt, equity movements, and dividend policies. Compare these cash movements | |
| to prior periods to discern trends, sustainability, and liquidity risks. Conclude with an informed analysis of the company's | |
| cash management effectiveness, liquidity position, and potential for future growth or financial challenges in a single paragraph. | |
| Less than 130 words. | |
| """ | |
| ) | |
| section_text = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| prompt = combine_prompt(instruction, section_text, df_string) | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def analyze_segment_stmt( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the income statement and the related section of its 10-K report for the given ticker symbol. | |
| Then return with an instruction on how to create a segment analysis. | |
| """ | |
| income_stmt = YFinanceUtils.get_income_stmt(ticker_symbol) | |
| df_string = ( | |
| "Income statement (Segment Analysis):\n" + income_stmt.to_string().strip() | |
| ) | |
| instruction = dedent( | |
| """ | |
| Identify the company's business segments and create a segment analysis using the Management's Discussion and Analysis | |
| and the income statement, subdivided by segment with clear headings. Address revenue and net profit with specific data, | |
| and calculate the changes. Detail strategic partnerships and their impacts, including details like the companies or organizations. | |
| Describe product innovations and their effects on income growth. Quantify market share and its changes, or state market position | |
| and its changes. Analyze market dynamics and profit challenges, noting any effects from national policy changes. Include the cost side, | |
| detailing operational costs, innovation investments, and expenses from channel expansion, etc. Support each statement with evidence, | |
| keeping each segment analysis concise and under 60 words, accurately sourcing information. For each segment, consolidate the most | |
| significant findings into one clear, concise paragraph, excluding less critical or vaguely described aspects to ensure clarity and | |
| reliance on evidence-backed information. For each segment, the output should be one single paragraph within 150 words. | |
| """ | |
| ) | |
| section_text = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| prompt = combine_prompt(instruction, section_text, df_string) | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def income_summarization( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| income_stmt_analysis: Annotated[str, "in-depth income statement analysis"], | |
| segment_analysis: Annotated[str, "in-depth segment analysis"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| With the income statement and segment analysis for the given ticker symbol. | |
| Then return with an instruction on how to synthesize these analyses into a single coherent paragraph. | |
| """ | |
| # income_stmt_analysis = analyze_income_stmt(ticker_symbol) | |
| # segment_analysis = analyze_segment_stmt(ticker_symbol) | |
| instruction = dedent( | |
| f""" | |
| Income statement analysis: {income_stmt_analysis}, | |
| Segment analysis: {segment_analysis}, | |
| Synthesize the findings from the in-depth income statement analysis and segment analysis into a single, coherent paragraph. | |
| It should be fact-based and data-driven. First, present and assess overall revenue and profit situation, noting significant | |
| trends and changes. Second, examine the performance of the various business segments, with an emphasis on their revenue and | |
| profit changes, revenue contributions and market dynamics. For information not covered in the first two areas, identify and | |
| integrate key findings related to operation, potential risks and strategic opportunities for growth and stability into the analysis. | |
| For each part, integrate historical data comparisons and provide relevant facts, metrics or data as evidence. The entire synthesis | |
| should be presented as a continuous paragraph without the use of bullet points. Use subtitles and numbering for each key point. | |
| The total output should be less than 160 words. | |
| """ | |
| ) | |
| section_text = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| prompt = combine_prompt(instruction, section_text, "") | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def get_risk_assessment( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the risk factors for the given ticker symbol with the related section of its 10-K report. | |
| Then return with an instruction on how to summarize the top 3 key risks of the company. | |
| """ | |
| company_name = YFinanceUtils.get_stock_info(ticker_symbol)["shortName"] | |
| risk_factors = SECUtils.get_10k_section(ticker_symbol, fyear, "1A") | |
| section_text = ( | |
| "Company Name: " | |
| + company_name | |
| + "\n\n" | |
| + "Risk factors:\n" | |
| + risk_factors | |
| + "\n\n" | |
| ) | |
| instruction = "According to the given information, summarize the top 3 key risks of the company. Less than 100 words." | |
| prompt = combine_prompt(instruction, section_text, "") | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def analyze_business_highlights( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the business summary and related section of its 10-K report for the given ticker symbol. | |
| Then return with an instruction on how to describe the performance highlights per business of the company. | |
| """ | |
| business_summary = SECUtils.get_10k_section(ticker_symbol, fyear, 1) | |
| section_7 = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| section_text = ( | |
| "Business summary:\n" | |
| + business_summary | |
| + "\n\n" | |
| + "Management's Discussion and Analysis of Financial Condition and Results of Operations:\n" | |
| + section_7 | |
| ) | |
| instruction = dedent( | |
| """ | |
| According to the given information, describe the performance highlights per business of the company. | |
| Each business description should contain one sentence of a summarization and one sentence of explanation. | |
| Less than 130 words. | |
| """ | |
| ) | |
| prompt = combine_prompt(instruction, section_text, "") | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def analyze_company_description( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| fyear: Annotated[str, "fiscal year of the 10-K report"], | |
| save_path: Annotated[str, "txt file path, to which the returned instruction & resources are written."] | |
| ) -> str: | |
| """ | |
| Retrieve the company description and related sections of its 10-K report for the given ticker symbol. | |
| Then return with an instruction on how to describe the company's industry, strengths, trends, and strategic initiatives. | |
| """ | |
| company_name = YFinanceUtils.get_stock_info(ticker_symbol).get( | |
| "shortName", "N/A" | |
| ) | |
| business_summary = SECUtils.get_10k_section(ticker_symbol, fyear, 1) | |
| section_7 = SECUtils.get_10k_section(ticker_symbol, fyear, 7) | |
| section_text = ( | |
| "Company Name: " | |
| + company_name | |
| + "\n\n" | |
| + "Business summary:\n" | |
| + business_summary | |
| + "\n\n" | |
| + "Management's Discussion and Analysis of Financial Condition and Results of Operations:\n" | |
| + section_7 | |
| ) | |
| instruction = dedent( | |
| """ | |
| According to the given information, | |
| 1. Briefly describe the company’s industry, | |
| 2. Highlight core strengths and competitive advantages key products or services, | |
| 3. Identify current industry trends, opportunities, and challenges that influence the company’s strategy, | |
| 4. Outline recent strategic initiatives such as product launches, acquisitions, or new partnerships, and describe the company's response to market conditions. | |
| Less than 400 words. | |
| """ | |
| ) | |
| step_prompt = combine_prompt(instruction, section_text, "") | |
| instruction2 = "Summarize the analysis, less than 130 words." | |
| prompt = combine_prompt(instruction=instruction2, resource=step_prompt) | |
| save_to_file(prompt, save_path) | |
| return f"instruction & resources saved to {save_path}" | |
| def get_key_data( | |
| ticker_symbol: Annotated[str, "ticker symbol"], | |
| filing_date: Annotated[ | |
| str | datetime, "the filing date of the financial report being analyzed" | |
| ], | |
| ) -> dict: | |
| """ | |
| return key financial data used in annual report for the given ticker symbol and filing date | |
| """ | |
| if not isinstance(filing_date, datetime): | |
| filing_date = datetime.strptime(filing_date, "%Y-%m-%d") | |
| # Fetch historical market data for the past 6 months | |
| start = (filing_date - timedelta(weeks=52)).strftime("%Y-%m-%d") | |
| end = filing_date.strftime("%Y-%m-%d") | |
| hist = YFinanceUtils.get_stock_data(ticker_symbol, start, end) | |
| # 获取其他相关信息 | |
| info = YFinanceUtils.get_stock_info(ticker_symbol) | |
| close_price = hist["Close"].iloc[-1] | |
| # Calculate the average daily trading volume | |
| six_months_start = (filing_date - timedelta(weeks=26)).strftime("%Y-%m-%d") | |
| hist_last_6_months = hist[ | |
| (hist.index >= six_months_start) & (hist.index <= end) | |
| ] | |
| # 计算这6个月的平均每日交易量 | |
| avg_daily_volume_6m = ( | |
| hist_last_6_months["Volume"].mean() | |
| if not hist_last_6_months["Volume"].empty | |
| else 0 | |
| ) | |
| fiftyTwoWeekLow = hist["High"].min() | |
| fiftyTwoWeekHigh = hist["Low"].max() | |
| # avg_daily_volume_6m = hist['Volume'].mean() | |
| # convert back to str for function calling | |
| filing_date = filing_date.strftime("%Y-%m-%d") | |
| # Print the result | |
| # print(f"Over the past 6 months, the average daily trading volume for {ticker_symbol} was: {avg_daily_volume_6m:.2f}") | |
| rating, _ = YFinanceUtils.get_analyst_recommendations(ticker_symbol) | |
| target_price = FMPUtils.get_target_price(ticker_symbol, filing_date) | |
| result = { | |
| "Rating": rating, | |
| "Target Price": target_price, | |
| f"6m avg daily vol ({info['currency']}mn)": "{:.2f}".format( | |
| avg_daily_volume_6m / 1e6 | |
| ), | |
| f"Closing Price ({info['currency']})": "{:.2f}".format(close_price), | |
| f"Market Cap ({info['currency']}mn)": "{:.2f}".format( | |
| FMPUtils.get_historical_market_cap(ticker_symbol, filing_date) / 1e6 | |
| ), | |
| f"52 Week Price Range ({info['currency']})": "{:.2f} - {:.2f}".format( | |
| fiftyTwoWeekLow, fiftyTwoWeekHigh | |
| ), | |
| f"BVPS ({info['currency']})": "{:.2f}".format( | |
| FMPUtils.get_historical_bvps(ticker_symbol, filing_date) | |
| ), | |
| } | |
| return result | |