File size: 14,451 Bytes
716f1cd
 
 
 
 
 
f833e71
 
716f1cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f833e71
716f1cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f833e71
908d2c9
f833e71
908d2c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f833e71
908d2c9
f833e71
908d2c9
 
 
 
 
f833e71
 
 
8f0908c
1643511
716f1cd
 
1643511
 
 
 
 
 
 
 
 
8f0908c
1643511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716f1cd
 
 
f833e71
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
"""
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