Quant Trading for Programmers 13: Add A First Grid Search For Strategy Parameters
· 16 min read · Views --
Last updated on

Quant Trading for Programmers 13: Add A First Grid Search For Strategy Parameters

Author: Alex Xiang


Quant Trading for Programmers 13: Add A First Grid Search For Strategy Parameters

Once metrics exist, parameters can be compared.

Article 13 starts with the simplest grid search: combine short moving-average windows, long moving-average windows, and position ratios, run one backtest for each parameter group, then rank the results. It is not clever, but it is transparent and reproducible, which makes it a good baseline before adding LLM-assisted strategy research.

Cover image for article 13 in Quant Trading for Programmers

Do Not Rush To Let A Model Rewrite The Strategy

Parameter search can easily become overfitting.

The first version should therefore make the process explicit: how candidates are generated, which combinations are filtered, how scores are calculated, and how results are sorted.

Several terms are easy to mix together:

TermMeaning
ParameterA tunable number inside strategy rules, such as moving-average window, position ratio, or stop-loss threshold
Grid searchList several candidate values for each parameter, enumerate all combinations, and backtest each one
OverfittingParameters work well on this historical sample but fail on another sample
In-sampleThe data range used to choose parameters
Out-of-sampleA separate data range used to check whether chosen parameters still work

Article 13 does not yet implement out-of-sample validation, so it can only produce “candidates”. It cannot directly produce “production-ready strategies”. That boundary should be visible in both code and article.

Parameter Candidates

Chapter 13 adds app/parameter_search.py.

@dataclass(frozen=True)
class ParameterCandidate:
    short_window: int
    long_window: int
    position_ratio: float

Candidate generation filters invalid combinations:

if short_window <= 1 or long_window <= short_window:
    continue
if not 0 < position_ratio <= 1:
    continue

This prevents meaningless parameters such as a short window longer than the long window, or a position ratio of 0 or above 100%.

Every Parameter Group Runs The Same Backtest

The search function iterates through parameter candidates:

backtest = run_signal_backtest(
    symbol,
    all_bars,
    initial_cash=initial_cash,
    position_ratio=params.position_ratio,
    short_window=params.short_window,
    long_window=params.long_window,
)
metrics = compute_performance_metrics(backtest.equity_curve, backtest.trades, initial_cash, backtest.max_drawdown)

This connects the backtest from article 10 with the metrics from article 12.

Scoring Should Penalize Risk And No-Trade Results

The current scoring function is intentionally simple:

def score_search_result(result: ParameterSearchResult) -> float:
    metrics = result.metrics
    drawdown_penalty = abs(metrics.max_drawdown) * 0.5
    turnover_penalty = max(0.0, metrics.turnover - 4.0) * 0.02
    trade_penalty = 0.01 if metrics.trade_count == 0 else 0.0
    return round(metrics.total_return - drawdown_penalty - turnover_penalty - trade_penalty, 6)

It does not guarantee the best strategy, but it expresses an engineering attitude: return is not the only target. Deep drawdown, high turnover, and no-trade candidates should be penalized.

Current Mainline Integrated Run

The current mainline repository provides an executable example that covers articles 13 to 15:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
uv sync --extra dev
uv run python -m scripts.chapter_examples strategy-promotion --source sample

Article 13 corresponds to the parameter-search section:

Real run screenshot for article 13 parameter search

In this sample, the top three candidates all use a 15-day long window and 0.8 position ratio, with identical return and drawdown. This is not necessarily a bug. It is a common signal: the current data and strategy rules are too simple, so different short windows have not separated. In real research, seeing this result should lead to out-of-sample validation, not immediate promotion of the top-ranked candidate.

Chapter Update And Repository

This chapter adds:

  • app/parameter_search.py.
  • Parameter-grid generation, candidate backtests, metric calculation, risk-penalty scoring, and result payloads.
  • tests/test_parameter_search.py, covering invalid-parameter filtering, sorting, and empty-data boundaries.
  • A current-mainline scripts.chapter_examples strategy-promotion integrated example that really runs the article 13-15 code path.
  • Background notes on parameters, grid search, overfitting, in-sample data, and out-of-sample data.

Repository:

https://github.com/ax2/zi-quant-platform

Code for this chapter:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-13
uv sync --extra dev
uv run pytest tests/test_parameter_search.py

The full chapter 13 test suite passes with 179 passed, still with only the existing FastAPI deprecation warning.

Summary

Parameter search is not about squeezing out a pretty return number. It is about making the process of producing strategy candidates reviewable.

Article 13 connects parameter candidates, backtests, metrics, and ranking. The next article saves candidate results as experiment records, preparing for strategy promotion.