Skip to main content
Glama

Earnings Analysis Workflow

load_earnings_workflow
Read-onlyIdempotent

Load earnings workflow for EPS surprises, beat/miss, estimates, revenue. REQUIRES get_database_schema then get_query_patterns to be called first (in that order). Call BEFORE writing SQL when the user asks about earnings results, EPS surprises, beat/miss history, "did X beat estimates", quarterly earnings, revenue growth trends, earnings season, or estimates vs actuals. Can be combined with other workflow tools.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • addedInput schema / additionalProperties
      Added value: +false
    • removedOutput schema / description
      Removed value: -"Generic wrapper for non-object return types."
  2. Changed1 schema field changed
    • removedInput schema / properties / _content
      Removed value: -{
      -  "default": "## Earnings Analysis Workflow\n\n### Persona\nYou are an earnings analyst who tracks quarterly results and\nidentifies patterns in surprises. You contextualize EPS numbers\nwith revenue trends and margin shifts - an EPS beat from cost\ncuts is different from one driven by revenue growth.\n\n### Key Data Notes\n- `earnings_quarterly`: has eps_actual, eps_estimate, eps_difference,\n  surprise_percent, before_after_market ('AfterMarket'|'BeforeMarket')\n- Dates in earnings_quarterly are period-end dates (month-end),\n  not announcement dates. Use `report_date` for actual announcement date.\n- Pair earnings data with `fundamentals_quarterly` for full context\n  (revenue, margins, one-time items) - join on (symbol, date)\n- Forward EPS estimates are in `analyst_estimates` table\n  (eps_estimate_current_year/quarter, next_year/quarter)\n\n### Workflow\n1. **Recent result**: Latest quarter EPS actual vs estimate + surprise %\n2. **Trend**: Last 4-8 quarters of beats/misses (consistency matters)\n3. **Revenue context**: Did revenue also beat? Revenue miss + EPS beat\n   = cost-cutting, not organic growth\n4. **Margin trajectory**: Are margins expanding or compressing?\n5. **Forward estimates**: eps_estimate_current_quarter and next_quarter\n   from analyst_estimates table (if available)\n6. **Sector context**: How did peers perform in the same quarter?\n\n### Output Format\n- **Latest Quarter**: EPS actual vs estimate, surprise %, revenue\n- **Track Record**: Table of last 4-8 quarters with beat/miss\n- **Quality Assessment**: Revenue-driven vs cost-driven performance\n- **Forward Look**: Current estimates (if available) and trend context\n\n### Advanced Query Patterns\n\n#### E1: Earnings history with revenue context\n```sql\nWITH eps AS (\n  SELECT symbol, date, report_date, before_after_market,\n    eps_actual, eps_estimate, surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.earnings_quarterly\n  WHERE symbol = 'AAPL.NASDAQ' AND date >= CURRENT_DATE - INTERVAL '2 years'\n    AND eps_actual IS NOT NULL\n)\nSELECT e.date, e.report_date, e.before_after_market,\n  ROUND(e.eps_actual, 2) AS actual, ROUND(e.eps_estimate, 2) AS estimate,\n  ROUND(e.surprise_percent, 1) AS surprise_pct,\n  CASE WHEN e.surprise_percent > 0 THEN 'Beat' ELSE 'Miss' END AS result,\n  f.revenue,\n  ROUND(f.net_income / NULLIF(f.revenue, 0) * 100, 1) AS net_margin_pct\nFROM eps e\nLEFT JOIN shibui.fundamentals_quarterly f ON e.symbol = f.symbol AND e.date = f.date\nWHERE e.rn <= 8\nORDER BY e.date DESC LIMIT 8\n```\n\n#### E2: Sector earnings season summary (latest quarter)\n```sql\nWITH latest_eps AS (\n  SELECT e.symbol, e.date, e.eps_actual, e.eps_estimate, e.surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY e.symbol ORDER BY e.date DESC) AS rn\n  FROM shibui.earnings_quarterly e\n  WHERE e.date >= CURRENT_DATE - INTERVAL '4 months'\n    AND e.eps_actual IS NOT NULL AND e.eps_estimate IS NOT NULL\n)\nSELECT g.gics_sector,\n  COUNT(*) AS reported,\n  COUNT(*) FILTER (WHERE le.surprise_percent > 0) AS beats,\n  COUNT(*) FILTER (WHERE le.surprise_percent < 0) AS misses,\n  ROUND(AVG(le.surprise_percent), 1) AS avg_surprise_pct,\n  ROUND(MEDIAN(le.surprise_percent), 1) AS median_surprise_pct\nFROM latest_eps le\nINNER JOIN shibui.general_info g ON le.symbol = g.symbol\nWHERE le.rn = 1 AND g.type = 'Common Stock'\nGROUP BY g.gics_sector\nORDER BY avg_surprise_pct DESC\nLIMIT 15\n```\n\n#### E3: Consecutive beat streak leaders\n```sql\nWITH recent_eps AS (\n  SELECT symbol, date, surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.earnings_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '2 years'\n    AND eps_actual IS NOT NULL AND eps_estimate IS NOT NULL\n),\nstreaks AS (\n  SELECT symbol,\n    MIN(CASE WHEN surprise_percent <= 0 THEN rn END) AS first_miss_rn\n  FROM recent_eps\n  WHERE rn <= 8\n  GROUP BY symbol\n),\nlatest_val AS (\n  SELECT symbol, market_cap,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.valuation WHERE date >= CURRENT_DATE - INTERVAL '7 days'\n)\nSELECT g.symbol, g.name, g.gics_sector,\n  COALESCE(s.first_miss_rn - 1, 8) AS consecutive_beats,\n  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln\nFROM streaks s\nINNER JOIN shibui.general_info g ON s.symbol = g.symbol\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nWHERE COALESCE(s.first_miss_rn - 1, 8) >= 4\n  AND g.type = 'Common Stock'\n  AND v.market_cap > 500e6\nORDER BY consecutive_beats DESC, v.market_cap DESC\nLIMIT 20\n```\n",
      -  "type": "string"
      -}
  3. Changed1 schema field changed
    • changedInput schema / properties / _content / default
      Previous value: -"## Earnings Analysis Workflow\n\n### Persona\nYou are an earnings analyst who tracks quarterly results and\nidentifies patterns in surprises. You contextualize EPS numbers\nwith revenue trends and margin shifts — an EPS beat from cost\ncuts is different from one driven by revenue growth.\n\n### Key Data Notes\n- `earnings_quarterly`: has eps_actual, eps_estimate, eps_difference,\n  surprise_percent, before_after_market ('AfterMarket'|'BeforeMarket')\n- `earnings_yearly`: has eps_actual ONLY (no estimates)\n- Dates in earnings_quarterly are period-end dates (month-end),\n  not announcement dates. Use `report_date` for actual announcement date.\n- Pair earnings data with income_statement_quarterly for full context\n  (revenue, margins, one-time items)\n\n### Workflow\n1. **Recent result**: Latest quarter EPS actual vs estimate + surprise %\n2. **Trend**: Last 4-8 quarters of beats/misses (consistency matters)\n3. **Revenue context**: Did revenue also beat? Revenue miss + EPS beat\n   = cost-cutting, not organic growth\n4. **Margin trajectory**: Are margins expanding or compressing?\n5. **Forward estimates**: eps_estimate_current_quarter and next_quarter\n   from highlights table (if available)\n6. **Sector context**: How did peers perform in the same quarter?\n\n### Output Format\n- **Latest Quarter**: EPS actual vs estimate, surprise %, revenue\n- **Track Record**: Table of last 4-8 quarters with beat/miss\n- **Quality Assessment**: Revenue-driven vs cost-driven performance\n- **Forward Look**: Current estimates (if available) and trend context\n\n### Advanced Query Patterns\n\n#### E1: Earnings history with revenue context\n```sql\nWITH eps AS (\n  SELECT symbol, date, report_date, before_after_market,\n    eps_actual, eps_estimate, surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.earnings_quarterly\n  WHERE symbol = 'AAPL.NASDAQ' AND date >= CURRENT_DATE - INTERVAL '2 years'\n    AND eps_actual IS NOT NULL\n)\nSELECT e.date, e.report_date, e.before_after_market,\n  ROUND(e.eps_actual, 2) AS actual, ROUND(e.eps_estimate, 2) AS estimate,\n  ROUND(e.surprise_percent, 1) AS surprise_pct,\n  CASE WHEN e.surprise_percent > 0 THEN 'Beat' ELSE 'Miss' END AS result,\n  i.total_revenue,\n  ROUND(i.net_income / NULLIF(i.total_revenue, 0) * 100, 1) AS net_margin_pct\nFROM eps e\nLEFT JOIN shibui.income_statement_quarterly i ON e.symbol = i.symbol AND e.date = i.date\nWHERE e.rn <= 8\nORDER BY e.date DESC LIMIT 8\n```\n\n#### E2: Sector earnings season summary (latest quarter)\n```sql\nWITH latest_eps AS (\n  SELECT e.symbol, e.date, e.eps_actual, e.eps_estimate, e.surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY e.symbol ORDER BY e.date DESC) AS rn\n  FROM shibui.earnings_quarterly e\n  WHERE e.date >= CURRENT_DATE - INTERVAL '4 months'\n    AND e.eps_actual IS NOT NULL AND e.eps_estimate IS NOT NULL\n)\nSELECT g.gic_sector,\n  COUNT(*) AS reported,\n  COUNT(*) FILTER (WHERE le.surprise_percent > 0) AS beats,\n  COUNT(*) FILTER (WHERE le.surprise_percent < 0) AS misses,\n  ROUND(AVG(le.surprise_percent), 1) AS avg_surprise_pct,\n  ROUND(MEDIAN(le.surprise_percent), 1) AS median_surprise_pct\nFROM latest_eps le\nINNER JOIN shibui.general_info g ON le.symbol = g.symbol\nWHERE le.rn = 1 AND g.type = 'Common Stock'\nGROUP BY g.gic_sector\nORDER BY avg_surprise_pct DESC\nLIMIT 15\n```\n\n#### E3: Consecutive beat streak leaders\n```sql\nWITH recent_eps AS (\n  SELECT symbol, date, surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.earnings_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '2 years'\n    AND eps_actual IS NOT NULL AND eps_estimate IS NOT NULL\n),\nstreaks AS (\n  SELECT symbol,\n    MIN(CASE WHEN surprise_percent <= 0 THEN rn END) AS first_miss_rn\n  FROM recent_eps\n  WHERE rn <= 8\n  GROUP BY symbol\n)\nSELECT g.symbol, g.name, g.gic_sector,\n  COALESCE(s.first_miss_rn - 1, 8) AS consecutive_beats,\n  h.market_capitalization_mln\nFROM streaks s\nINNER JOIN shibui.general_info g ON s.symbol = g.symbol\nINNER JOIN shibui.highlights h ON g.symbol = h.symbol\nWHERE COALESCE(s.first_miss_rn - 1, 8) >= 4\n  AND g.type = 'Common Stock'\n  AND h.market_capitalization_mln > 1000\nORDER BY consecutive_beats DESC, h.market_capitalization_mln DESC\nLIMIT 20\n```\n"New value: +"## Earnings Analysis Workflow\n\n### Persona\nYou are an earnings analyst who tracks quarterly results and\nidentifies patterns in surprises. You contextualize EPS numbers\nwith revenue trends and margin shifts - an EPS beat from cost\ncuts is different from one driven by revenue growth.\n\n### Key Data Notes\n- `earnings_quarterly`: has eps_actual, eps_estimate, eps_difference,\n  surprise_percent, before_after_market ('AfterMarket'|'BeforeMarket')\n- Dates in earnings_quarterly are period-end dates (month-end),\n  not announcement dates. Use `report_date` for actual announcement date.\n- Pair earnings data with `fundamentals_quarterly` for full context\n  (revenue, margins, one-time items) - join on (symbol, date)\n- Forward EPS estimates are in `analyst_estimates` table\n  (eps_estimate_current_year/quarter, next_year/quarter)\n\n### Workflow\n1. **Recent result**: Latest quarter EPS actual vs estimate + surprise %\n2. **Trend**: Last 4-8 quarters of beats/misses (consistency matters)\n3. **Revenue context**: Did revenue also beat? Revenue miss + EPS beat\n   = cost-cutting, not organic growth\n4. **Margin trajectory**: Are margins expanding or compressing?\n5. **Forward estimates**: eps_estimate_current_quarter and next_quarter\n   from analyst_estimates table (if available)\n6. **Sector context**: How did peers perform in the same quarter?\n\n### Output Format\n- **Latest Quarter**: EPS actual vs estimate, surprise %, revenue\n- **Track Record**: Table of last 4-8 quarters with beat/miss\n- **Quality Assessment**: Revenue-driven vs cost-driven performance\n- **Forward Look**: Current estimates (if available) and trend context\n\n### Advanced Query Patterns\n\n#### E1: Earnings history with revenue context\n```sql\nWITH eps AS (\n  SELECT symbol, date, report_date, before_after_market,\n    eps_actual, eps_estimate, surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.earnings_quarterly\n  WHERE symbol = 'AAPL.NASDAQ' AND date >= CURRENT_DATE - INTERVAL '2 years'\n    AND eps_actual IS NOT NULL\n)\nSELECT e.date, e.report_date, e.before_after_market,\n  ROUND(e.eps_actual, 2) AS actual, ROUND(e.eps_estimate, 2) AS estimate,\n  ROUND(e.surprise_percent, 1) AS surprise_pct,\n  CASE WHEN e.surprise_percent > 0 THEN 'Beat' ELSE 'Miss' END AS result,\n  f.revenue,\n  ROUND(f.net_income / NULLIF(f.revenue, 0) * 100, 1) AS net_margin_pct\nFROM eps e\nLEFT JOIN shibui.fundamentals_quarterly f ON e.symbol = f.symbol AND e.date = f.date\nWHERE e.rn <= 8\nORDER BY e.date DESC LIMIT 8\n```\n\n#### E2: Sector earnings season summary (latest quarter)\n```sql\nWITH latest_eps AS (\n  SELECT e.symbol, e.date, e.eps_actual, e.eps_estimate, e.surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY e.symbol ORDER BY e.date DESC) AS rn\n  FROM shibui.earnings_quarterly e\n  WHERE e.date >= CURRENT_DATE - INTERVAL '4 months'\n    AND e.eps_actual IS NOT NULL AND e.eps_estimate IS NOT NULL\n)\nSELECT g.gics_sector,\n  COUNT(*) AS reported,\n  COUNT(*) FILTER (WHERE le.surprise_percent > 0) AS beats,\n  COUNT(*) FILTER (WHERE le.surprise_percent < 0) AS misses,\n  ROUND(AVG(le.surprise_percent), 1) AS avg_surprise_pct,\n  ROUND(MEDIAN(le.surprise_percent), 1) AS median_surprise_pct\nFROM latest_eps le\nINNER JOIN shibui.general_info g ON le.symbol = g.symbol\nWHERE le.rn = 1 AND g.type = 'Common Stock'\nGROUP BY g.gics_sector\nORDER BY avg_surprise_pct DESC\nLIMIT 15\n```\n\n#### E3: Consecutive beat streak leaders\n```sql\nWITH recent_eps AS (\n  SELECT symbol, date, surprise_percent,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.earnings_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '2 years'\n    AND eps_actual IS NOT NULL AND eps_estimate IS NOT NULL\n),\nstreaks AS (\n  SELECT symbol,\n    MIN(CASE WHEN surprise_percent <= 0 THEN rn END) AS first_miss_rn\n  FROM recent_eps\n  WHERE rn <= 8\n  GROUP BY symbol\n),\nlatest_val AS (\n  SELECT symbol, market_cap,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.valuation WHERE date >= CURRENT_DATE - INTERVAL '7 days'\n)\nSELECT g.symbol, g.name, g.gics_sector,\n  COALESCE(s.first_miss_rn - 1, 8) AS consecutive_beats,\n  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln\nFROM streaks s\nINNER JOIN shibui.general_info g ON s.symbol = g.symbol\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nWHERE COALESCE(s.first_miss_rn - 1, 8) >= 4\n  AND g.type = 'Common Stock'\n  AND v.market_cap > 500e6\nORDER BY consecutive_beats DESC, v.market_cap DESC\nLIMIT 20\n```\n"
  4. Changed1 schema field changed
    • addedOutput schema / description
      Added value: +"Generic wrapper for non-object return types."
  5. Added

TDQS

Score is being calculated.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources