Quant Trading for Programmers 14: Save Strategy Candidates As Experiment Records
· 14 min read · Views --
Last updated on

Quant Trading for Programmers 14: Save Strategy Candidates As Experiment Records

Author: Alex Xiang


Quant Trading for Programmers 14: Save Strategy Candidates As Experiment Records

Article 13 can produce parameter candidates. But if candidates only stay in terminal output, their context will disappear quickly.

Article 14 adds experiment records: what the candidate parameters are, which baseline they are compared with, how large the metric deltas are, and what status and decision the system produced. These should be stored in structured form so they can be reviewed later.

Cover image for article 14 in Quant Trading for Programmers

Terminal Output Is Not An Experiment Record

Strategy research often looks like this: today a candidate looks good; tomorrow the data range or parameters change, and nobody remembers why the candidate looked good.

Candidate results must be saved together with evidence.

Experiment records solve traceability. They are not just “more fields”. At minimum, a strategy candidate should answer:

  • What parameters did it use?
  • Which baseline was it compared against?
  • What were the deltas in total return, max drawdown, and trade count?
  • Why did the system mark it as passed or rejected at that time?

Without this information, reviews depend on memory. Depending on memory in strategy research makes it easy to mistake accidents for capability.

Experiment Record Object

Chapter 14 adds app/experiment_records.py.

@dataclass(frozen=True)
class ExperimentRecord:
    experiment_id: str
    name: str
    status: str
    candidate: dict[str, Any]
    baseline: dict[str, Any] | None
    decision: str
    created_at: str

It is still a pure Python object for now, but its structure is already close to the payload that can later be written into a database.

Candidates Must Be Compared With A Baseline

The comparison function is:

def compare_candidate_to_baseline(candidate: dict[str, Any], baseline: dict[str, Any] | None = None) -> dict[str, Any]:
    candidate_metrics = dict(candidate.get("metrics") or {})
    baseline_metrics = dict((baseline or {}).get("metrics") or {})
    if not baseline_metrics:
        return {"status": "no_baseline", "deltas": {}, "passed": False}

Without a baseline, the candidate does not pass automatically. It is marked as no_baseline.

With a baseline, metric deltas are calculated:

deltas = {
    "total_return": candidate_return - baseline_return,
    "max_drawdown": candidate_drawdown - baseline_drawdown,
    "trade_count": candidate_trade_count - baseline_trade_count,
}

The current pass rule is conservative: return must improve, and drawdown cannot become meaningfully worse.

Current Mainline Integrated Run

The same command generates experiment records after parameter search:

uv run python -m scripts.chapter_examples strategy-promotion --source sample

Article 14 corresponds to this output:

Real run screenshot for article 14 experiment records

This record has status=passed, meaning the candidate passed the current comparison rule relative to the baseline. In deltas, total return improved by 0.069501, max drawdown became slightly deeper by -0.000061, and trade count did not change. This output is more useful than saying “the candidate has higher return”, because it shows return improvement and risk change together.

Record Status

build_experiment_record() produces three statuses:

  • candidate: no baseline yet, waiting for comparison.
  • passed: passed relative to the baseline.
  • rejected: failed to clear the baseline.

This lets experiment records flow into the strategy promotion gate in the next chapter.

Chapter Update And Repository

This chapter adds:

  • app/experiment_records.py.
  • Candidate-baseline comparison, experiment-record construction, status decisions, and payload serialization.
  • tests/test_experiment_records.py, covering missing baseline, baseline pass, candidate rejection, and payload output.
  • A real current-mainline screenshot for experiment records.
  • Background notes on experiment records, baseline comparison, and evidence for later review.

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-14
uv sync --extra dev
uv run pytest tests/test_experiment_records.py

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

Summary

Strategy research must leave evidence behind.

Article 14 turns parameter-search results into structured experiment records. The next article moves one step forward: which experiment records can enter paper-trading observation, and which ones must be rejected.