Skip to content

Stock Selection Framework

Overview

Item Description
Goal Build stock selection strategies using TopNSelector and MultiFactorSelector
Prerequisite Running a Backtest

1. Stock Selection Framework

eqlib provides two stock selection frameworks — TopNSelector and MultiFactorSelector — supporting periodic rebalancing and factor-based screening.

1.1 TopNSelector: Rank-Based Selection

Selects the top N stocks by factor value ranking.

from eqlib import TopNSelector

def initialize(context):
    g.selector = TopNSelector(
        universe=['600519', '601390', '000858', '600036', '601166'],
        factor_fn=momentum_factor,  # custom factor function
        top_n=3,
        rebalance_freq='weekly',    # rebalance weekly
    )
    run_daily(rebalance, time='every_bar')

def momentum_factor(security, context):
    """Momentum factor: return over the past 20 days"""
    hist = attribute_history(security, 20, '1d', ['close'])
    if hist.empty or len(hist) < 20:
        return None
    return (hist['close'].iloc[-1] / hist['close'].iloc[0] - 1)

def rebalance(context):
    candidates = g.selector.select(context)
    if candidates:
        for sec in candidates:
            order_value(sec, context.portfolio.available_cash / len(candidates))

1.2 MultiFactorSelector: Multi-Factor Selection

Combines multiple factors for composite scoring and selection.

from eqlib import MultiFactorSelector

def initialize(context):
    g.selector = MultiFactorSelector(
        universe=['600519', '601390', '000858', '600036', '601166'],
        factors={
            'momentum': (momentum_factor, 0.4),    # 40% weight
            'volatility': (volatility_factor, 0.3), # 30% weight
            'value': (value_factor, 0.3),           # 30% weight
        },
        top_n=3,
        rebalance_freq='monthly',
    )

def volatility_factor(security, context):
    """Volatility factor (inverse): lower volatility scores higher"""
    hist = attribute_history(security, 20, '1d', ['close'])
    if hist.empty:
        return None
    returns = hist['close'].pct_change().dropna()
    return -returns.std()  # negate so low volatility scores higher

def value_factor(security, context):
    """Valuation factor: lower PE scores higher"""
    val = get_valuation(security)
    if val is None or val.get('pe_ratio') is None:
        return None
    return -val['pe_ratio']  # negate so low PE scores higher

def rebalance(context):
    candidates = g.selector.select(context)
    # rebalancing logic...

1.3 Rebalancing Frequency Configuration

Parameter Options Description
rebalance_freq 'daily' Rebalance every trading day
'weekly' Rebalance every Monday
'biweekly' Rebalance every two weeks
'monthly' Rebalance on the first trading day of each month
'quarterly' Rebalance on the first trading day of each quarter

1.4 Factor Function Specification

The factor function signature is:

def my_factor(security: str, context: Context) -> float | None:
    """
    Args:
        security: stock code
        context: strategy context

    Returns:
        Factor value (higher is better) or None (stock excluded from ranking)
    """
    pass

See the Stock Selection API Reference for full parameter documentation.