Skip to main content
Glama

Stock Screening Workflow

load_screening_workflow
Read-onlyIdempotent

Load screening workflow to find, filter, scan, rank stocks, top N by.... REQUIRES get_database_schema then get_query_patterns to be called first (in that order). Call BEFORE writing SQL when the user asks to find, screen, scan, rank, or filter stocks — "find stocks that...", "top 10 by...", "best dividend stocks", value/growth screens, sector ranking, or any multi-factor selection. Can be combined with other workflow tools.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedOutput schema / (root)
      Previous value: -{
      -  "properties": {
      -    "result": {
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "result"
      -  ],
      -  "type": "object",
      -  "x-fastmcp-wrap-result": true
      -}New value: +null
  2. Changed2 schema fields changed
    • addedInput schema / additionalProperties
      Added value: +false
    • removedOutput schema / description
      Removed value: -"Generic wrapper for non-object return types."
  3. Changed1 schema field changed
    • removedInput schema / properties / _content
      Removed value: -{
      -  "default": "## Quantitative Screening Workflow\n\n### Persona\nYou are a quantitative analyst building stock screens. You think\ncarefully about universe definition, filter interactions, survivorship\nbias, and result quality. You always explain what the screen found\nAND what it excluded.\n\n### Workflow\n1. **Define universe**: Start with base filters:\n   - `g.type = 'Common Stock'` (excludes ADRs, CEFs, REITs, MLPs)\n   - Optionally add: `g.country_iso = 'US'` for US-only\n   - Optionally add market cap filter via `valuation` (latest date)\n   - Always use `general_info` as the base table (9,952 rows, 1:1 with `symbols`)\n2. **Apply filters incrementally**: Each filter reduces the universe.\n   Note the reduction at each step. Warn if <10 results remain.\n3. **Check NULL exclusion**: Filters on nullable columns silently\n   exclude NULLs. Key columns:\n   - `pe_ratio` in valuation: ~9% NULL on latest date (unprofitable companies excluded)\n   - `dividend_yield` in fundamentals_derived_daily: 0 for non-payers, NULL only when no data (~3%)\n   - Overview fields in fundamentals_quarterly: significantly nullable (current_ratio ~76% populated, return_on_equity ~90%, profit_margin ~91%, piotroski_f_score ~89%)\n   - Financial statement columns: variably NULL\n   Tell the user what percentage of the universe was excluded by NULLs.\n4. **Apply ranking/sorting**: Use ORDER BY with the primary criterion.\n5. **Validate results**: Check for ADRs, data anomalies, stale data.\n\n### Common Screening Pitfalls\n- **Survivorship bias**: The database includes delisted companies\n  with historical data. Screens on current metrics naturally\n  exclude failed companies. Note this limitation.\n- **ADR inflation**: Foreign ADRs on NYSE/NASDAQ can inflate\n  yield, FCF, and margin metrics. Filter with `g.type = 'Common Stock'`\n  to exclude them.\n- **NULL interaction**: `WHERE pe_ratio < 15 AND current_ratio > 1.5`\n  silently drops ~9% (no P/E) + ~24% (no current_ratio). Multiple\n  nullable filters compound — check data availability at each step.\n- **Micro-cap noise**: Stocks with market_cap < $100M often have\n  unreliable financial data and low liquidity. Default to\n  market_cap > $500M unless user specifies otherwise.\n\n### Output Format\n- **Screen Summary**: What you searched for, universe size, result count\n- **Results Table**: Inline markdown, sorted by primary criterion\n- **Exclusion Note**: What filters removed and approximate % excluded\n- **Caveats**: Any data quality concerns with the results\n\n### Advanced Query Patterns\n\n#### S1: Multi-factor value screen\n```sql\nWITH latest_val AS (\n  SELECT symbol, pe_ratio, price_to_book, 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),\nlatest_q AS (\n  SELECT symbol, return_on_equity, profit_margin,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '6 months'\n),\nlatest_dd AS (\n  SELECT symbol, dividend_yield, ev_ebitda,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_derived_daily WHERE date >= CURRENT_DATE - INTERVAL '7 days'\n)\nSELECT g.symbol, g.name, g.gics_sector, g.gics_industry,\n  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  ROUND(v.pe_ratio, 2) AS pe,\n  ROUND(dd.ev_ebitda, 2) AS ev_ebitda,\n  ROUND(v.price_to_book, 2) AS pb,\n  ROUND(f.return_on_equity * 100, 1) AS roe_pct,\n  ROUND(f.profit_margin * 100, 1) AS margin_pct,\n  ROUND(dd.dividend_yield * 100, 2) AS div_yield_pct\nFROM shibui.general_info g\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nINNER JOIN latest_q f ON g.symbol = f.symbol AND f.rn = 1\nLEFT JOIN latest_dd dd ON g.symbol = dd.symbol AND dd.rn = 1\nWHERE g.type = 'Common Stock'\n  AND v.market_cap > 500e6\n  AND v.pe_ratio BETWEEN 5 AND 20\n  AND f.return_on_equity > 0.12\n  AND f.profit_margin > 0.08\nORDER BY v.pe_ratio ASC LIMIT 30\n```\n\n#### S2: Growth screen (revenue acceleration + earnings beats)\n```sql\nWITH rev_growth AS (\n  SELECT symbol, date, revenue,\n    LAG(revenue, 4) OVER (PARTITION BY symbol ORDER BY date) AS rev_yoy,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '2 years'\n    AND revenue IS NOT NULL AND revenue > 0\n),\nlatest_rev AS (\n  SELECT symbol,\n    ROUND((revenue - rev_yoy) / NULLIF(rev_yoy, 0) * 100, 1) AS yoy_growth_pct\n  FROM rev_growth WHERE rn = 1 AND rev_yoy IS NOT NULL\n),\nrecent_beats AS (\n  SELECT symbol,\n    COUNT(*) FILTER (WHERE surprise_percent > 0) AS beats,\n    COUNT(*) AS quarters\n  FROM shibui.earnings_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '1 year'\n    AND eps_actual IS NOT NULL AND eps_estimate IS NOT NULL\n  GROUP BY symbol\n),\nlatest_val AS (\n  SELECT symbol, pe_ratio, 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  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  lr.yoy_growth_pct,\n  rb.beats || '/' || rb.quarters AS beat_rate,\n  ROUND(v.pe_ratio, 2) AS pe\nFROM latest_rev lr\nINNER JOIN shibui.general_info g ON lr.symbol = g.symbol\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nLEFT JOIN recent_beats rb ON g.symbol = rb.symbol\nWHERE g.type = 'Common Stock'\n  AND v.market_cap > 5e8\n  AND lr.yoy_growth_pct > 15\n  AND rb.beats >= 3\nORDER BY lr.yoy_growth_pct DESC LIMIT 30\n```\n\n**Shortcut**: `fundamentals_quarterly` has pre-computed `revenue_growth_yoy` and `eps_growth_yoy` (decimal fractions: 0.15 = 15%). Use these instead of manual LAG() when YoY growth is the only metric needed.\n\n#### S3: Short squeeze candidates\n```sql\nWITH latest_val AS (\n  SELECT symbol, pe_ratio, 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  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  ROUND(os.short_percent_float * 100, 2) AS short_pct_float,\n  ROUND(os.percent_institutions, 1) AS inst_pct,\n  ROUND(v.pe_ratio, 2) AS pe\nFROM shibui.general_info g\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nINNER JOIN shibui.ownership_stats os ON g.symbol = os.symbol\nWHERE g.type = 'Common Stock'\n  AND os.short_percent_float > 0.15\n  AND v.market_cap BETWEEN 3e8 AND 1e10\nORDER BY os.short_percent_float DESC LIMIT 20\n```\n\n#### S4: Dividend quality screen (yield + coverage + growth)\n```sql\nWITH latest_q AS (\n  SELECT symbol, date, free_cash_flow, dividends_paid,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '6 months'\n    AND dividends_paid IS NOT NULL AND dividends_paid != 0\n),\nlatest_dd AS (\n  SELECT symbol, dividend_yield,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_derived_daily WHERE date >= CURRENT_DATE - INTERVAL '7 days'\n),\nlatest_val AS (\n  SELECT symbol, pe_ratio, 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  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  ROUND(dd.dividend_yield * 100, 2) AS yield_pct,\n  ROUND(f.free_cash_flow / NULLIF(ABS(f.dividends_paid), 0), 2) AS fcf_coverage,\n  ROUND(v.pe_ratio, 2) AS pe\nFROM shibui.general_info g\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nINNER JOIN latest_q f ON g.symbol = f.symbol AND f.rn = 1\nINNER JOIN latest_dd dd ON g.symbol = dd.symbol AND dd.rn = 1\nWHERE g.type = 'Common Stock'\n  AND g.country_iso = 'US'\n  AND dd.dividend_yield > 0.02\n  AND f.free_cash_flow / NULLIF(ABS(f.dividends_paid), 0) > 1.2\n  AND v.market_cap > 500e6\nORDER BY dd.dividend_yield DESC LIMIT 20\n```\n",
      -  "type": "string"
      -}
  4. Changed1 schema field changed
    • changedInput schema / properties / _content / default
      Previous value: -"## Quantitative Screening Workflow\n\n### Persona\nYou are a quantitative analyst building stock screens. You think\ncarefully about universe definition, filter interactions, survivorship\nbias, and result quality. You always explain what the screen found\nAND what it excluded.\n\n### Workflow\n1. **Define universe**: Start with base filters:\n   - `g.type = 'Common Stock'` (excludes ADRs, CEFs, REITs, MLPs)\n   - Optionally add: `g.country_iso = 'US'` for US-only\n   - Optionally add: `h.market_capitalization_mln > X` for size\n   - Always use `general_info` as the base table (4,961 rows, not `symbols` with 5,201)\n2. **Apply filters incrementally**: Each filter reduces the universe.\n   Note the reduction at each step. Warn if <10 results remain.\n3. **Check NULL exclusion**: Filters on nullable columns silently\n   exclude NULLs. Key columns:\n   - `pe_ratio`: 44% NULL (unprofitable companies excluded)\n   - `dividend_yield`: 60% NULL (non-payers excluded)\n   - `peg_ratio`: heavily NULL\n   - Financial statement columns: variably NULL\n   Tell the user what percentage of the universe was excluded by NULLs.\n4. **Apply ranking/sorting**: Use ORDER BY with the primary criterion.\n5. **Validate results**: Check for ADRs, data anomalies, stale data.\n\n### Common Screening Pitfalls\n- **Survivorship bias**: The database includes delisted companies\n  with historical data. Screens on current metrics naturally\n  exclude failed companies. Note this limitation.\n- **Stale highlights**: For screens >20 symbols, some highlights\n  data may be outdated. Consider computing key metrics from\n  quarterly financial statements instead.\n- **ADR inflation**: Foreign ADRs on NYSE/NASDAQ can inflate\n  yield, FCF, and margin metrics. Filter with `g.type = 'Common Stock'`\n  to exclude them.\n- **NULL interaction**: `WHERE pe_ratio < 15 AND dividend_yield > 0.03`\n  silently drops 44% + 60% of the universe. Only ~30% of\n  companies pass both just on data availability.\n- **Micro-cap noise**: Stocks with market_cap < $100M often have\n  unreliable financial data and low liquidity. Default to\n  `market_capitalization_mln > 300` unless user specifies otherwise.\n\n### Output Format\n- **Screen Summary**: What you searched for, universe size, result count\n- **Results Table**: Inline markdown, sorted by primary criterion\n- **Exclusion Note**: What filters removed and approximate % excluded\n- **Caveats**: Any data quality concerns with the results\n\n### Advanced Query Patterns\n\n#### S1: Multi-factor value screen\n```sql\nSELECT g.symbol, g.name, g.gic_sector, g.gic_sub_industry,\n  h.market_capitalization_mln,\n  ROUND(h.pe_ratio, 2) AS pe,\n  ROUND(v.enterprise_value_ebitda, 2) AS ev_ebitda,\n  ROUND(v.price_book_mrq, 2) AS pb,\n  ROUND(h.return_on_equity_ttm * 100, 1) AS roe_pct,\n  ROUND(h.profit_margin * 100, 1) AS margin_pct,\n  ROUND(h.dividend_yield * 100, 2) AS div_yield_pct\nFROM shibui.general_info g\nINNER JOIN shibui.highlights h ON g.symbol = h.symbol\nLEFT JOIN shibui.valuation v ON g.symbol = v.symbol\nWHERE g.type = 'Common Stock'\n  AND h.market_capitalization_mln > 1000\n  AND h.pe_ratio BETWEEN 5 AND 20\n  AND h.return_on_equity_ttm > 0.12\n  AND h.profit_margin > 0.08\nORDER BY h.pe_ratio ASC LIMIT 30\n```\n\n#### S2: Growth screen (revenue acceleration + earnings beats)\n```sql\nWITH rev_growth AS (\n  SELECT symbol, date, total_revenue,\n    LAG(total_revenue, 4) OVER (PARTITION BY symbol ORDER BY date) AS rev_yoy,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.income_statement_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '2 years'\n    AND total_revenue IS NOT NULL AND total_revenue > 0\n),\nlatest_rev AS (\n  SELECT symbol,\n    ROUND((total_revenue - rev_yoy) / NULLIF(rev_yoy, 0) * 100, 1) AS yoy_growth_pct\n  FROM rev_growth WHERE rn = 1 AND rev_yoy IS NOT NULL\n),\nrecent_beats AS (\n  SELECT symbol,\n    COUNT(*) FILTER (WHERE surprise_percent > 0) AS beats,\n    COUNT(*) AS quarters\n  FROM shibui.earnings_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '1 year'\n    AND eps_actual IS NOT NULL AND eps_estimate IS NOT NULL\n  GROUP BY symbol\n)\nSELECT g.symbol, g.name, g.gic_sector,\n  h.market_capitalization_mln,\n  lr.yoy_growth_pct,\n  rb.beats || '/' || rb.quarters AS beat_rate,\n  ROUND(h.pe_ratio, 2) AS pe\nFROM latest_rev lr\nINNER JOIN shibui.general_info g ON lr.symbol = g.symbol\nINNER JOIN shibui.highlights h ON g.symbol = h.symbol\nLEFT JOIN recent_beats rb ON g.symbol = rb.symbol\nWHERE g.type = 'Common Stock'\n  AND h.market_capitalization_mln > 500\n  AND lr.yoy_growth_pct > 15\n  AND rb.beats >= 3\nORDER BY lr.yoy_growth_pct DESC LIMIT 30\n```\n\n#### S3: Short squeeze candidates\nNOTE: In share_stats, only short_percent_float is populated (decimal: 0.15 = 15%).\nshares_short, shares_short_prior_month, short_ratio, short_percent_outstanding are ALL NULL.\npercent_insiders and percent_institutions are percentages (50.0 = 50%).\n```sql\nSELECT g.symbol, g.name, g.gic_sector,\n  h.market_capitalization_mln,\n  ROUND(ss.short_percent_float * 100, 2) AS short_pct_float,\n  ROUND(ss.percent_institutions, 1) AS inst_pct,\n  ss.shares_float,\n  ROUND(h.pe_ratio, 2) AS pe\nFROM shibui.general_info g\nINNER JOIN shibui.highlights h ON g.symbol = h.symbol\nINNER JOIN shibui.share_stats ss ON g.symbol = ss.symbol\nWHERE g.type = 'Common Stock'\n  AND ss.short_percent_float > 0.15  -- decimal: 0.15 = 15%\n  AND h.market_capitalization_mln BETWEEN 300 AND 10000\nORDER BY ss.short_percent_float DESC LIMIT 20\n```\n\n#### S4: Dividend quality screen (yield + coverage + growth)\n```sql\nWITH div_coverage AS (\n  SELECT c.symbol, c.date,\n    ABS(c.dividends_paid) AS dividends,\n    c.free_cash_flow,\n    ROUND(c.free_cash_flow / NULLIF(ABS(c.dividends_paid), 0), 2) AS fcf_coverage,\n    ROW_NUMBER() OVER (PARTITION BY c.symbol ORDER BY c.date DESC) AS rn\n  FROM shibui.cash_flow_quarterly c\n  WHERE c.date >= CURRENT_DATE - INTERVAL '6 months'\n    AND c.dividends_paid IS NOT NULL AND c.dividends_paid != 0\n)\nSELECT g.symbol, g.name, g.gic_sector,\n  h.market_capitalization_mln,\n  ROUND(h.dividend_yield * 100, 2) AS yield_pct,\n  h.dividend_share,\n  dc.fcf_coverage,\n  ROUND(h.pe_ratio, 2) AS pe\nFROM shibui.general_info g\nINNER JOIN shibui.highlights h ON g.symbol = h.symbol\nINNER JOIN div_coverage dc ON g.symbol = dc.symbol AND dc.rn = 1\nWHERE g.type = 'Common Stock'\n  AND g.country_iso = 'US'\n  AND h.dividend_yield > 0.02\n  AND dc.fcf_coverage > 1.2\n  AND h.market_capitalization_mln > 1000\nORDER BY h.dividend_yield DESC LIMIT 20\n```\n"New value: +"## Quantitative Screening Workflow\n\n### Persona\nYou are a quantitative analyst building stock screens. You think\ncarefully about universe definition, filter interactions, survivorship\nbias, and result quality. You always explain what the screen found\nAND what it excluded.\n\n### Workflow\n1. **Define universe**: Start with base filters:\n   - `g.type = 'Common Stock'` (excludes ADRs, CEFs, REITs, MLPs)\n   - Optionally add: `g.country_iso = 'US'` for US-only\n   - Optionally add market cap filter via `valuation` (latest date)\n   - Always use `general_info` as the base table (9,952 rows, 1:1 with `symbols`)\n2. **Apply filters incrementally**: Each filter reduces the universe.\n   Note the reduction at each step. Warn if <10 results remain.\n3. **Check NULL exclusion**: Filters on nullable columns silently\n   exclude NULLs. Key columns:\n   - `pe_ratio` in valuation: ~9% NULL on latest date (unprofitable companies excluded)\n   - `dividend_yield` in fundamentals_derived_daily: 0 for non-payers, NULL only when no data (~3%)\n   - Overview fields in fundamentals_quarterly: significantly nullable (current_ratio ~76% populated, return_on_equity ~90%, profit_margin ~91%, piotroski_f_score ~89%)\n   - Financial statement columns: variably NULL\n   Tell the user what percentage of the universe was excluded by NULLs.\n4. **Apply ranking/sorting**: Use ORDER BY with the primary criterion.\n5. **Validate results**: Check for ADRs, data anomalies, stale data.\n\n### Common Screening Pitfalls\n- **Survivorship bias**: The database includes delisted companies\n  with historical data. Screens on current metrics naturally\n  exclude failed companies. Note this limitation.\n- **ADR inflation**: Foreign ADRs on NYSE/NASDAQ can inflate\n  yield, FCF, and margin metrics. Filter with `g.type = 'Common Stock'`\n  to exclude them.\n- **NULL interaction**: `WHERE pe_ratio < 15 AND current_ratio > 1.5`\n  silently drops ~9% (no P/E) + ~24% (no current_ratio). Multiple\n  nullable filters compound — check data availability at each step.\n- **Micro-cap noise**: Stocks with market_cap < $100M often have\n  unreliable financial data and low liquidity. Default to\n  market_cap > $500M unless user specifies otherwise.\n\n### Output Format\n- **Screen Summary**: What you searched for, universe size, result count\n- **Results Table**: Inline markdown, sorted by primary criterion\n- **Exclusion Note**: What filters removed and approximate % excluded\n- **Caveats**: Any data quality concerns with the results\n\n### Advanced Query Patterns\n\n#### S1: Multi-factor value screen\n```sql\nWITH latest_val AS (\n  SELECT symbol, pe_ratio, price_to_book, 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),\nlatest_q AS (\n  SELECT symbol, return_on_equity, profit_margin,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '6 months'\n),\nlatest_dd AS (\n  SELECT symbol, dividend_yield, ev_ebitda,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_derived_daily WHERE date >= CURRENT_DATE - INTERVAL '7 days'\n)\nSELECT g.symbol, g.name, g.gics_sector, g.gics_industry,\n  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  ROUND(v.pe_ratio, 2) AS pe,\n  ROUND(dd.ev_ebitda, 2) AS ev_ebitda,\n  ROUND(v.price_to_book, 2) AS pb,\n  ROUND(f.return_on_equity * 100, 1) AS roe_pct,\n  ROUND(f.profit_margin * 100, 1) AS margin_pct,\n  ROUND(dd.dividend_yield * 100, 2) AS div_yield_pct\nFROM shibui.general_info g\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nINNER JOIN latest_q f ON g.symbol = f.symbol AND f.rn = 1\nLEFT JOIN latest_dd dd ON g.symbol = dd.symbol AND dd.rn = 1\nWHERE g.type = 'Common Stock'\n  AND v.market_cap > 500e6\n  AND v.pe_ratio BETWEEN 5 AND 20\n  AND f.return_on_equity > 0.12\n  AND f.profit_margin > 0.08\nORDER BY v.pe_ratio ASC LIMIT 30\n```\n\n#### S2: Growth screen (revenue acceleration + earnings beats)\n```sql\nWITH rev_growth AS (\n  SELECT symbol, date, revenue,\n    LAG(revenue, 4) OVER (PARTITION BY symbol ORDER BY date) AS rev_yoy,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '2 years'\n    AND revenue IS NOT NULL AND revenue > 0\n),\nlatest_rev AS (\n  SELECT symbol,\n    ROUND((revenue - rev_yoy) / NULLIF(rev_yoy, 0) * 100, 1) AS yoy_growth_pct\n  FROM rev_growth WHERE rn = 1 AND rev_yoy IS NOT NULL\n),\nrecent_beats AS (\n  SELECT symbol,\n    COUNT(*) FILTER (WHERE surprise_percent > 0) AS beats,\n    COUNT(*) AS quarters\n  FROM shibui.earnings_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '1 year'\n    AND eps_actual IS NOT NULL AND eps_estimate IS NOT NULL\n  GROUP BY symbol\n),\nlatest_val AS (\n  SELECT symbol, pe_ratio, 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  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  lr.yoy_growth_pct,\n  rb.beats || '/' || rb.quarters AS beat_rate,\n  ROUND(v.pe_ratio, 2) AS pe\nFROM latest_rev lr\nINNER JOIN shibui.general_info g ON lr.symbol = g.symbol\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nLEFT JOIN recent_beats rb ON g.symbol = rb.symbol\nWHERE g.type = 'Common Stock'\n  AND v.market_cap > 5e8\n  AND lr.yoy_growth_pct > 15\n  AND rb.beats >= 3\nORDER BY lr.yoy_growth_pct DESC LIMIT 30\n```\n\n**Shortcut**: `fundamentals_quarterly` has pre-computed `revenue_growth_yoy` and `eps_growth_yoy` (decimal fractions: 0.15 = 15%). Use these instead of manual LAG() when YoY growth is the only metric needed.\n\n#### S3: Short squeeze candidates\n```sql\nWITH latest_val AS (\n  SELECT symbol, pe_ratio, 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  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  ROUND(os.short_percent_float * 100, 2) AS short_pct_float,\n  ROUND(os.percent_institutions, 1) AS inst_pct,\n  ROUND(v.pe_ratio, 2) AS pe\nFROM shibui.general_info g\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nINNER JOIN shibui.ownership_stats os ON g.symbol = os.symbol\nWHERE g.type = 'Common Stock'\n  AND os.short_percent_float > 0.15\n  AND v.market_cap BETWEEN 3e8 AND 1e10\nORDER BY os.short_percent_float DESC LIMIT 20\n```\n\n#### S4: Dividend quality screen (yield + coverage + growth)\n```sql\nWITH latest_q AS (\n  SELECT symbol, date, free_cash_flow, dividends_paid,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_quarterly\n  WHERE date >= CURRENT_DATE - INTERVAL '6 months'\n    AND dividends_paid IS NOT NULL AND dividends_paid != 0\n),\nlatest_dd AS (\n  SELECT symbol, dividend_yield,\n    ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date DESC) AS rn\n  FROM shibui.fundamentals_derived_daily WHERE date >= CURRENT_DATE - INTERVAL '7 days'\n),\nlatest_val AS (\n  SELECT symbol, pe_ratio, 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  ROUND(v.market_cap / 1e6, 0) AS market_cap_mln,\n  ROUND(dd.dividend_yield * 100, 2) AS yield_pct,\n  ROUND(f.free_cash_flow / NULLIF(ABS(f.dividends_paid), 0), 2) AS fcf_coverage,\n  ROUND(v.pe_ratio, 2) AS pe\nFROM shibui.general_info g\nINNER JOIN latest_val v ON g.symbol = v.symbol AND v.rn = 1\nINNER JOIN latest_q f ON g.symbol = f.symbol AND f.rn = 1\nINNER JOIN latest_dd dd ON g.symbol = dd.symbol AND dd.rn = 1\nWHERE g.type = 'Common Stock'\n  AND g.country_iso = 'US'\n  AND dd.dividend_yield > 0.02\n  AND f.free_cash_flow / NULLIF(ABS(f.dividends_paid), 0) > 1.2\n  AND v.market_cap > 500e6\nORDER BY dd.dividend_yield DESC LIMIT 20\n```\n"
  5. Changed1 schema field changed
    • addedOutput schema / description
      Added value: +"Generic wrapper for non-object return types."
  6. Added

TDQS

Score is being calculated.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources