MCP Server live — AI agents can now query 105M+ SEC facts. Connect your agent →
ValueinValuein
quant
intermediate
10 min

Factor-Based Stock Screening

Build a multi-factor stock screen using cross-sectional percentile ranks. Filter by ROE, Piotroski F-score, FCF yield, and momentum signals.

Python SDKMCP ServerDuckDB

What Are Factor Scores?

Factor scores are cross-sectional percentile ranks computed across the full universe. A score of 1.0 means best in universe, 0.0 means worst. Valuein computes 10 factors: ROE, gross margin, operating margin, net profit margin, revenue growth YoY, FCF-to-assets, debt-to-equity, asset turnover, current ratio, and Piotroski F-score.

Screen via MCP (in Claude or Cursor)

Ask your AI agent to screen the universe directly using the screen_universe tool.

Python
# In Claude or Cursor with MCP configured:
# "Show me the top 10 Technology companies by composite factor rank"

# The MCP tool call:
# screen_universe(sector="Technology", sort_by="composite_rank", limit=10)

Screen via Python SDK

Use DuckDB to query factor_scores.parquet directly for more flexibility.

Python
from valuein_sdk import ValueinClient, ValueinError

try:
    with ValueinClient() as client:

        # Top 20 companies with strong profitability AND low debt
        results = client.run_query("""
          SELECT r.symbol, r.name, r.sector,
            fs.composite_rank,
            fs.roe_rank,
            fs.gross_margin_rank,
            fs.debt_to_equity_rank,
            fs.piotroski_f_score_rank
          FROM factor_scores fs
          JOIN references r ON fs.entity_id = r.cik
          WHERE fs.roe_rank > 0.8          -- Top 20% ROE
            AND fs.debt_to_equity_rank > 0.7 -- Low debt (high rank = low D/E)
            AND fs.piotroski_f_score_rank > 0.7
          ORDER BY fs.composite_rank DESC
          LIMIT 20
        """)
        print(results)

except ValueinError as e:
    print(f"Error: {e}")

Build a Composite Score

Combine multiple factors with custom weights instead of using the equal-weighted composite.

Python
# Continuing from above — reuse the same client context
        custom_screen = client.run_query("""
          SELECT r.symbol, r.name, r.sector,
            -- Custom weighted composite: 40% profitability, 30% quality, 30% value
            (0.4 * fs.roe_rank
             + 0.2 * fs.gross_margin_rank
             + 0.3 * fs.fcf_to_assets_rank
             + 0.1 * fs.debt_to_equity_rank) AS custom_score
          FROM factor_scores fs
          JOIN references r ON fs.entity_id = r.cik
          WHERE r.symbol IS NOT NULL
          ORDER BY custom_score DESC
          LIMIT 25
        """)
        print(custom_screen)

Up next

Point-in-Time Backtesting

Construct survivorship-bias-free factor portfolios using accepted_at timestamps and PIT universe snapshots.

Read next