Skip to main content
Glama
24mlight

A Share MCP

get_fina_indicator

Retrieve quarterly financial indicators for A-share stocks by aggregating profitability, operation, growth, solvency, cash flow, and DuPont analysis metrics from multiple data sources.

Instructions

    Aggregated financial indicators from 6 Baostock APIs into one convenient query.

    **Data is returned by QUARTER** (Q1, Q2, Q3, Q4) based on financial report dates.
    Input date range determines which quarters to fetch.

    Combines data from:
    - 盈利能力 (Profitability): roeAvg, npMargin, gpMargin, epsTTM
    - 营运能力 (Operation): NRTurnRatio, INVTurnRatio, CATurnRatio
    - 成长能力 (Growth): YOYNI, YOYEquity, YOYAsset
    - 偿债能力 (Solvency): currentRatio, quickRatio, liabilityToAsset
    - 现金流量 (Cash Flow): CFOToOR, CFOToNP, CAToAsset
    - 杜邦分析 (DuPont): dupontROE, dupontAssetTurn, dupontPnitoni

    Output columns include prefixes: profit_*, operation_*, growth_*,
    balance_*, cashflow_*, dupont_* to distinguish data sources.
    

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeYes
start_dateYes
end_dateYes
limitNo
formatNomarkdown

Implementation Reference

  • MCP tool handler for 'get_fina_indicator'. Decorated with @app.tool(), performs error handling via run_tool_with_handling, and delegates execution to the fetch_fina_indicator use case function.
    @app.tool()
    def get_fina_indicator(code: str, start_date: str, end_date: str, limit: int = 250, format: str = "markdown") -> str:
        """
        Aggregated financial indicators from 6 Baostock APIs into one convenient query.
    
        **Data is returned by QUARTER** (Q1, Q2, Q3, Q4) based on financial report dates.
        Input date range determines which quarters to fetch.
    
        Combines data from:
        - 盈利能力 (Profitability): roeAvg, npMargin, gpMargin, epsTTM
        - 营运能力 (Operation): NRTurnRatio, INVTurnRatio, CATurnRatio
        - 成长能力 (Growth): YOYNI, YOYEquity, YOYAsset
        - 偿债能力 (Solvency): currentRatio, quickRatio, liabilityToAsset
        - 现金流量 (Cash Flow): CFOToOR, CFOToNP, CAToAsset
        - 杜邦分析 (DuPont): dupontROE, dupontAssetTurn, dupontPnitoni
    
        Output columns include prefixes: profit_*, operation_*, growth_*,
        balance_*, cashflow_*, dupont_* to distinguish data sources.
        """
        return run_tool_with_handling(
            lambda: fetch_fina_indicator(
                active_data_source, code=code, start_date=start_date, end_date=end_date, limit=limit, format=format
            ),
            context=f"get_fina_indicator:{code}:{start_date}-{end_date}",
        )
  • mcp_server.py:52-52 (registration)
    Registration call in the main MCP server setup that invokes the register_financial_report_tools function, which defines and registers the get_fina_indicator tool.
    register_financial_report_tools(app, active_data_source)
  • Use case helper function that invokes the data source's get_fina_indicator method and formats the resulting DataFrame as a markdown table.
    def fetch_fina_indicator(data_source: FinancialDataSource, *, code: str, start_date: str, end_date: str, limit: int, format: str) -> str:
        """Fetch financial indicators (ROE, gross margin, net margin, etc.) within a date range."""
        validate_output_format(format)
        df = data_source.get_fina_indicator(code=code, start_date=start_date, end_date=end_date)
        meta = {"code": code, "start_date": start_date, "end_date": end_date, "dataset": "Financial Indicators"}
        return format_table_output(df, format=format, max_rows=limit, meta=meta)
  • Abstract method in FinancialDataSource interface defining the expected signature and documentation for get_fina_indicator.
    @abstractmethod
    def get_fina_indicator(self, code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """
        Fetches financial indicators (ROE, gross margin, net margin, etc.) within a date range.
    
        Args:
            code: The stock code (e.g., 'sh.600000', 'sz.000001').
            start_date: Start date in 'YYYY-MM-DD' format.
            end_date: End date in 'YYYY-MM-DD' format.
    
        Returns:
            A pandas DataFrame containing financial indicators such as:
            - roe, roe_yearly (Return on Equity)
            - netprofit_margin, grossprofit_margin (Profitability ratios)
            - expense_ratio, netprofit_ratio
            - current_ratio, quick_ratio (Liquidity ratios)
            - etc.
        """
        pass
  • Core implementation in BaostockDataSource that aggregates data from 6 Baostock financial report APIs (profit_data, operation_data, growth_data, balance_data, cash_flow_data, dupont_data) across quarters in the specified date range, prefixing columns with category names for distinction.
    def get_fina_indicator(self, code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """
        Fetches comprehensive financial indicators by aggregating multiple Baostock APIs.
    
        Aggregates data from:
        - Profitability (盈利能力)
        - Operation Capability (营运能力)
        - Growth Capability (成长能力)
        - Balance Sheet/Solvency (偿债能力)
        - Cash Flow (现金流量)
        - DuPont Analysis (杜邦分析)
        """
        logger.info(f"Fetching aggregated financial indicators for {code} ({start_date} to {end_date})")
    
        # 解析日期范围,获取年份列表
        from datetime import datetime
        try:
            start = datetime.strptime(start_date, "%Y-%m-%d")
            end = datetime.strptime(end_date, "%Y-%m-%d")
        except ValueError:
            raise ValueError(f"Invalid date format. Expected YYYY-MM-DD, got {start_date} to {end_date}")
    
        years = set(str(y) for y in range(start.year, end.year + 1))
    
        all_results = []
    
        try:
            with baostock_login_context():
                for year in years:
                    for quarter in [1, 2, 3, 4]:
                        # 检查季度是否在日期范围内
                        quarter_start_month = (quarter - 1) * 3
                        quarter_start = datetime(int(year), quarter_start_month + 1, 1)
                        if quarter_start > end:
                            continue
    
                        record = {"code": code, "year": year, "quarter": quarter}
    
                        # 1. 盈利能力
                        try:
                            rs = bs.query_profit_data(code=code, year=year, quarter=quarter)
                            if rs.error_code == '0' and rs.next():
                                row = rs.get_row_data()
                                for i, field in enumerate(rs.fields):
                                    record[f"profit_{field}"] = row[i] if i < len(row) else None
                        except Exception as e:
                            logger.debug(f"Failed to fetch profit data for {code} {year}Q{quarter}: {e}")
    
                        # 2. 营运能力
                        try:
                            rs = bs.query_operation_data(code=code, year=year, quarter=quarter)
                            if rs.error_code == '0' and rs.next():
                                row = rs.get_row_data()
                                for i, field in enumerate(rs.fields):
                                    record[f"operation_{field}"] = row[i] if i < len(row) else None
                        except Exception as e:
                            logger.debug(f"Failed to fetch operation data for {code} {year}Q{quarter}: {e}")
    
                        # 3. 成长能力
                        try:
                            rs = bs.query_growth_data(code=code, year=year, quarter=quarter)
                            if rs.error_code == '0' and rs.next():
                                row = rs.get_row_data()
                                for i, field in enumerate(rs.fields):
                                    record[f"growth_{field}"] = row[i] if i < len(row) else None
                        except Exception as e:
                            logger.debug(f"Failed to fetch growth data for {code} {year}Q{quarter}: {e}")
    
                        # 4. 偿债能力
                        try:
                            rs = bs.query_balance_data(code=code, year=year, quarter=quarter)
                            if rs.error_code == '0' and rs.next():
                                row = rs.get_row_data()
                                for i, field in enumerate(rs.fields):
                                    record[f"balance_{field}"] = row[i] if i < len(row) else None
                        except Exception as e:
                            logger.debug(f"Failed to fetch balance data for {code} {year}Q{quarter}: {e}")
    
                        # 5. 现金流量
                        try:
                            rs = bs.query_cash_flow_data(code=code, year=year, quarter=quarter)
                            if rs.error_code == '0' and rs.next():
                                row = rs.get_row_data()
                                for i, field in enumerate(rs.fields):
                                    record[f"cashflow_{field}"] = row[i] if i < len(row) else None
                        except Exception as e:
                            logger.debug(f"Failed to fetch cash flow data for {code} {year}Q{quarter}: {e}")
    
                        # 6. 杜邦分析
                        try:
                            rs = bs.query_dupont_data(code=code, year=year, quarter=quarter)
                            if rs.error_code == '0' and rs.next():
                                row = rs.get_row_data()
                                for i, field in enumerate(rs.fields):
                                    record[f"dupont_{field}"] = row[i] if i < len(row) else None
                        except Exception as e:
                            logger.debug(f"Failed to fetch dupont data for {code} {year}Q{quarter}: {e}")
    
                        # 只有当有数据时才添加记录
                        if len(record) > 3:  # code + year + quarter + at least one data field
                            all_results.append(record)
    
                if not all_results:
                    raise NoDataFoundError(
                        f"No financial indicator data found for {code} in range {start_date}-{end_date}")
    
                result_df = pd.DataFrame(all_results)
                logger.info(f"Retrieved {len(result_df)} aggregated financial indicator records for {code}.")
                return result_df
    
        except (LoginError, NoDataFoundError, DataSourceError, ValueError) as e:
            logger.warning(f"Known error fetching financial indicators for {code}: {type(e).__name__}")
            raise e
        except Exception as e:
            logger.exception(f"Unexpected error fetching financial indicators for {code}: {e}")
            raise DataSourceError(f"Unexpected error fetching financial indicators for {code}: {e}")
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains the quarterly aggregation behavior and output column naming conventions, which is valuable. However, it doesn't address important behavioral aspects like rate limits, authentication requirements, data freshness, error conditions, or whether this is a read-only operation (though implied by 'get' naming).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with clear sections: purpose statement, key behavioral detail (quarterly aggregation), data sources list, and output format explanation. Every sentence adds value with zero wasted words, and it's appropriately front-loaded with the core functionality.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 5 parameters, 0% schema coverage, no annotations, and no output schema, the description does a reasonable job explaining the aggregation behavior and output structure. However, it doesn't fully compensate for the missing parameter documentation (especially the 'code' parameter) and lacks details about return format, error handling, or performance characteristics that would be helpful given the complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage for 5 parameters, the description adds significant value by explaining that date range determines which quarters to fetch (clarifying start_date and end_date purpose). However, it doesn't explain the code parameter (stock/company identifier), limit, or format parameters. The description compensates well but doesn't fully cover all parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool aggregates financial indicators from 6 Baostock APIs into one query, specifying the exact data sources (profitability, operation, growth, solvency, cash flow, DuPont analysis). It distinguishes itself from siblings by combining data that appears to be split across multiple specialized tools (e.g., get_profit_data, get_operation_data, get_growth_data, get_dupont_data).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: when needing aggregated financial indicators by quarter, with date ranges determining which quarters to fetch. It implicitly suggests alternatives (using individual specialized tools for specific data types) but doesn't explicitly name them or state when not to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/24mlight/a_share_mcp_is_just_I_need'

If you have feedback or need assistance with the MCP directory API, please join our Discord server