Easy-Financial-Report / service /report_service.py
JC321's picture
Upload report_service.py
908d2c9 verified
"""
Report Service - 财务报告数据服务
集成 EasyFinancialAgent 的 MCP 工具,提供完整的数据查询方法
"""
from EasyFinancialAgent.chat_direct import (
analyze_company_with_llm,
chatbot_response,
search_company_direct,
get_company_info_direct,
extract_financial_metrics_direct,
get_company_filings_direct,
get_latest_financial_data_direct,
query_company_direct
)
from datetime import datetime
from typing import Optional
def get_report_data(symbol_or_name: str, years: int = 5):
"""
获取公司完整财务报告数据
Args:
symbol_or_name: 公司代码或名称 (e.g., "Apple", "AAPL", "0000320193")
years: 财务年限 (默认 5 年)
Returns:
完整的报告数据字典,包含公司信息、财务指标、最新数据等
Example:
report = get_report_data("Apple", years=5)
"""
result = {
"timestamp": datetime.now().isoformat(),
"query_input": symbol_or_name,
"status": "success",
"data": {
"company_search": None,
"company_info": None,
"latest_financial": None,
"financial_metrics": None,
"filings": None
},
"errors": []
}
try:
# 1. 搜索公司
print(f"[Report Service] 搜索公司: {symbol_or_name}")
search_result = search_company_direct(symbol_or_name)
print(f"[Report Service] 搜索结果: {search_result}")
if "error" in search_result:
result["errors"].append(f"Search failed: {search_result['error']}")
result["status"] = "error"
return result
result["data"]["company_search"] = search_result
# 从搜索结果提取 CIK
cik = None
if isinstance(search_result, dict):
cik = search_result.get("cik")
elif isinstance(search_result, (list, tuple)) and len(search_result) > 0:
try:
first = search_result[0] if isinstance(search_result, (list, tuple)) else None
if isinstance(first, dict):
cik = first.get("cik")
except (IndexError, TypeError):
pass
if not cik:
result["errors"].append("Could not extract CIK from search result")
result["status"] = "error"
return result
print(f"[Report Service] 找到公司 CIK: {cik}")
# 2. 获取公司详细信息
# print(f"[Report Service] 获取公司详细信息")
# company_info = get_company_info_direct(cik)
# if "error" not in company_info:
# result["data"]["company_info"] = company_info
# else:
# result["errors"].append(f"Failed to get company info: {company_info.get('error')}")
# 3. 获取最新财务数据
# print(f"[Report Service] 获取最新财务数据")
# latest_data = get_latest_financial_data_direct(cik)
# if "error" not in latest_data:
# result["data"]["latest_financial"] = latest_data
# else:
# result["errors"].append(f"Failed to get latest financial data: {latest_data.get('error')}")
# 4. 获取多年财务指标
print(f"[Report Service] 获取 {years} 年财务指标")
metrics = extract_financial_metrics_direct(cik, years=years)
if "error" not in metrics:
result["data"]["financial_metrics"] = metrics
else:
result["errors"].append(f"Failed to get financial metrics: {metrics.get('error')}")
# 5. 获取公司文件列表
# print(f"[Report Service] 获取公司 SEC 文件列表")
# filings = get_company_filings_direct(cik)
# if "error" not in filings:
# result["data"]["filings"] = filings
# else:
# result["errors"].append(f"Failed to get filings: {filings.get('error')}")
print(f"[Report Service] 报告数据获取完成")
except Exception as e:
result["status"] = "error"
result["errors"].append(f"Exception: {str(e)}")
import traceback
result["errors"].append(traceback.format_exc())
return result
def get_company_summary(symbol_or_name: str):
"""
获取公司摘要信息(轻量级查询)
Args:
symbol_or_name: 公司代码或名称
Returns:
公司摘要数据字典
Example:
summary = get_company_summary("Tesla")
"""
result = {
"timestamp": datetime.now().isoformat(),
"query_input": symbol_or_name,
"status": "success",
"data": {
"company_search": None,
"company_info": None,
"latest_financial": None
},
"errors": []
}
try:
# 搜索公司
search_result = search_company_direct(symbol_or_name)
if "error" in search_result:
result["errors"].append(f"Search failed: {search_result['error']}")
result["status"] = "error"
return result
result["data"]["company_search"] = search_result
# 提取 CIK
cik = None
if isinstance(search_result, dict):
cik = search_result.get("cik")
elif isinstance(search_result, (list, tuple)) and len(search_result) > 0:
try:
first = search_result[0] if isinstance(search_result, (list, tuple)) else None
if isinstance(first, dict):
cik = first.get("cik")
except (IndexError, TypeError):
pass
if not cik:
result["errors"].append("Could not extract CIK")
result["status"] = "error"
return result
# 获取公司信息
company_info = get_company_info_direct(cik)
if "error" not in company_info:
result["data"]["company_info"] = company_info
# 获取最新财务数据
latest_data = get_latest_financial_data_direct(cik)
if "error" not in latest_data:
result["data"]["latest_financial"] = latest_data
except Exception as e:
result["status"] = "error"
result["errors"].append(str(e))
return result
def get_financial_metrics(symbol_or_name: str, years: int = 5):
"""
获取财务指标趋势数据
Args:
symbol_or_name: 公司代码或名称
years: 年数(默认 5 年)
Returns:
财务指标数据字典
Example:
metrics = get_financial_metrics("Microsoft", years=10)
"""
result = {
"timestamp": datetime.now().isoformat(),
"query_input": symbol_or_name,
"years": years,
"status": "success",
"data": None,
"errors": []
}
try:
# 搜索公司
search_result = search_company_direct(symbol_or_name)
if "error" in search_result:
result["errors"].append(f"Search failed: {search_result['error']}")
result["status"] = "error"
return result
# 提取 CIK
cik = None
if isinstance(search_result, dict):
cik = search_result.get("cik")
elif isinstance(search_result, (list, tuple)) and len(search_result) > 0:
try:
first = search_result[0] if isinstance(search_result, (list, tuple)) else None
if isinstance(first, dict):
cik = first.get("cik")
except (IndexError, TypeError):
pass
if not cik:
result["errors"].append("Could not extract CIK")
result["status"] = "error"
return result
# 获取财务指标
metrics = extract_financial_metrics_direct(cik, years=years)
if "error" in metrics:
result["errors"].append(f"Failed to get metrics: {metrics['error']}")
result["status"] = "error"
else:
result["data"] = metrics
except Exception as e:
result["status"] = "error"
result["errors"].append(str(e))
return result
def get_service_health():
"""
检查财务数据服务健康状态
Returns:
服务状态字典
Example:
health = get_service_health()
"""
return {
"status": "ok",
"message": "Using direct MCP functions (no HTTP service required)"
}
def query_company_advanced(company_input: str, type: str):
"""
综合查询公司信息 (直接调用 chat_direct 的高级方法)
包括搜索、基本信息、文件列表和财务指标
Args:
company_input: 公司名称或代码
get_filings: 是否获取文件列表
get_metrics: 是否获取财务指标
Returns:
综合结果字典,包含 company_search, company_info, filings, metrics
Example:
result = query_company_advanced("Apple", get_filings=True, get_metrics=True)
"""
prompt_suggestion = f"""
Role:
You are an expert investment advisor who provides data-driven recommendations based on a company’s financials, news, and market data.
Task:
Analyze the following for {company_input}:
Financial metrics – revenue, profit, debt, cash flow, etc.
Recent news – assess risks and opportunities.
Stock data – price trend, volume, etc.
Output Restriction:
Your response must contain only the following two elements and nothing else:
The exact block titled "Investment Recommendation:" with the four specified fields filled in.
A single concluding sentence summarizing how the recommendation integrates financial, news, and market data.
Final Output Format:
Investment Recommendation:
Recommendation: [Buy / Hold / Avoid]
Entry & Exit Price: [Specify]
Stop-Loss & Take-Profit Levels: [Specify]
Holding Horizon: Short-term (<1 month) or Long-term (>1 month)
This recommendation is based on an objective synthesis of the company’s latest financial performance, material news developments, and current market price action.
Rules:
Base all advice strictly on factual, verifiable data—no speculation or opinion.
Be concise, professional, and actionable.
Always ground entry/exit and stop/take-profit levels in recent price behavior (e.g., support/resistance, volatility).
If insufficient reliable data exists, default to "Avoid".
Output must be in English only.
"""
prompt_report = f"""
Analyze the following for {company_input}:
3 Years Financial metrics – revenue, profit, debt, cash flow, etc.
Recent news – assess risks and opportunities.
Stock data – price trend, volume, etc.
Role:
You are a professional financial statement analyst specializing in deep, data-backed evaluations of public companies. Your task is to produce a comprehensive, clear, and actionable financial analysis report in English, strictly following the structure below.
Instructions:
Base all analysis on real financial data (e.g., Total Revenue, Net Income, Gross Profit Margin, Current Ratio) and current market trends.
Incorporate visual insights: Describe or reference charts for Revenue Performance and Earnings Growth in the Summary, and use clear chart-based representations of key metrics in the Financial Statements section.
If needed, simulate access to up-to-date financial databases (e.g., via Finnhub, SEC filings, or Bloomberg) to ensure data accuracy.
Be objective, concise, and professional—avoid speculation or unsupported claims.
Output Format (Markdown Only):
Markdown
# Financial Analysis Report: {company_input}
## Executive Summary
- Analyze the company’s current financial health using **Total Revenue**, **Net Income**, **Gross Profit Margin**, and **Current Ratio**.
- Include narrative + chart descriptions for **Revenue Performance** and **Earnings Growth** (e.g., YoY/QoQ trends).
- Summarize the company’s current status, historical performance, and forward-looking outlook based on data and sector dynamics.
## Financial Statements
- Present key financial metrics visually (e.g., time-series charts or comparative tables) for:
- Total Revenue
- Net Income
- Gross Profit Margin (%)
- Current Ratio
- Ensure all data is clearly labeled, accurate, and easy to interpret.
## Investment Recommendation
- **Recommendation**: [Buy / Hold / Avoid]
- **Entry Price**: $XX.XX
- **Target Exit Price**: $XX.XX
- **Stop-Loss Level**: $XX.XX
- **Take-Profit Level**: $XX.XX
- **Holding Horizon**: Short-term (<1 month) or Long-term (>1 month)
> *Disclaimer: This recommendation is based on factual financial analysis. Market conditions may change rapidly—invest at your own risk.*
## Industry Overview
### Company Snapshot
Brief overview of the company’s business model, market position, and core operations.
### Three Investment Theses
1. **Thesis 1**: [e.g., Strong revenue growth driven by product innovation]
2. **Thesis 2**: [e.g., Expanding margins due to cost optimization]
3. **Thesis 3**: [e.g., Attractive valuation relative to industry peers]
### Key Risks & Mitigation Strategies
- **Risk 1**: [e.g., Regulatory uncertainty] → *Mitigation*: [e.g., Geographic diversification]
- **Risk 2**: [e.g., Rising input costs] → *Mitigation*: [e.g., Long-term supplier contracts]
- **Risk 3**: [e.g., Intensifying competition] → *Mitigation*: [e.g., R&D investment and brand loyalty]
Ensure the final output is fully self-contained, professionally written, and ready for investor review. Do not include any content outside the specified sections.
"""
# return analyze_company_with_llm(prompt)
prompt = prompt_suggestion if type == "suggestion" else prompt_report
# return chatbot_response(prompt)
responses = list(chatbot_response(prompt))
final_response = responses[-1]
print(f"最终分析答案---------: {final_response}")
return final_response