Quant Trading for Programmers 13: Add A First Grid Search For Strategy Parameters
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.

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:
| Term | Meaning |
|---|---|
| Parameter | A tunable number inside strategy rules, such as moving-average window, position ratio, or stop-loss threshold |
| Grid search | List several candidate values for each parameter, enumerate all combinations, and backtest each one |
| Overfitting | Parameters work well on this historical sample but fail on another sample |
| In-sample | The data range used to choose parameters |
| Out-of-sample | A 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:

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-promotionintegrated 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.
Follow ZiCode on WeChat
If this post was useful, you can follow later updates on WeChat as well.
X / Twitter
Follow @ax2_zicode
Faster technical notes, short thoughts, and new-post alerts are posted on X.
More in this column
- Quant Trading for Programmers 17: Generate Paper-Trading Account Snapshots
- Quant Trading for Programmers 16: Start With A Clear Paper-Trading Ledger
- Quant Trading for Programmers 15: Strategy Promotion Needs A Gate
- Quant Trading for Programmers 14: Save Strategy Candidates As Experiment Records
- Quant Trading for Programmers 12: Final Return Is Not Enough
- Quant Trading for Programmers 11: From One Stock To A Portfolio Backtest
- Quant Trading for Programmers 10: Run The First Minimal Backtest Loop
- Quant Trading for Programmers 09: From K-Lines To The First Explainable Factor Signal