1. Promise
One-sentence promise
After this lecture, you can produce a complete deliverable bundle—code, config, data references, metrics, plots, assumptions, and limitations—so another quant can reproduce, audit, and challenge your model without asking for missing pieces.
End tag line
A model without artefacts is not evidence.
2. Learning objectives
After reading this lecture, you will be able to:
- Define the final deliverable as an artefact bundle, not a slide deck.
- List the minimum required artefacts: code, config, data references, metrics, plots, assumptions, limitations.
- Write assumptions and limitations in a committee-ready way.
- Create a minimal “evidence pack” folder structure.
- Produce plots that support auditability (not marketing).
3. Prerequisites and setup
Required maths and prior knowledge
- None beyond earlier lectures.
Python environment assumptions
- Python 3.9+ in a notebook or script.
Packages used
numpy,pandas,matplotlib(optional for demos)
4. Conceptual core
4.1 The key idea
A deliverable is not “the model”.
A deliverable is an evidence pack: everything needed to reproduce results and evaluate fitness for purpose.
Formally, define the modelling pipeline as: A reproducible deliverable fixes:
- the code version,
- the configuration (hyperparameters, thresholds, filters),
- the data references (what, where, when),
- the evaluation protocol,
- the outputs (metrics, plots),
- and the narrative (assumptions, limitations).
Validator sentence
If it cannot be reproduced, it cannot be validated.
4.2 Final artefacts (minimum set)
Think in six artefact classes.
(1) Code
- Training code (feature building, fitting).
- Inference code (predict, post-process, decision rule).
- Evaluation code (CV, stability, error analysis).
- Utility code (logging, seed control, version printing).
Minimum requirement: one command to rerun end-to-end.
(2) Config
A single source of truth for:
- universe definition and filters,
- horizon, target definition,
- split design (dates, folds, embargo),
- model hyperparameters,
- thresholds (classification) or sizing rules (trading),
- cost assumptions (if decision-level).
Config must be versioned and human-readable (YAML/JSON/TOML).
(3) Metrics
At least:
- Primary metric (pre-registered).
- Secondary metrics (stability / calibration / tail).
- Subperiod and regime tables.
- Worst-block metric.
Report metric with:
- units,
- sample period,
- and which split it belongs to (train/val/test).
(4) Plots
Minimum plots (choose those appropriate to the problem):
- Time-series CV fold metric plot (stability).
- Error anatomy plot: over time or reliability plot.
- Distribution plot: residuals or score distribution.
- Decision-level plot: cumulative P&L / drawdown if applicable.
Plots should be labelled, dated, and tied to config.
(5) Assumptions
Assumptions are statements you rely on.
Write them as testable claims or scope boundaries.
Examples:
- Data is point-in-time and survivorship-free.
- Transaction costs are constant and equal to X bps.
- Execution occurs at next open with no slippage beyond costs.
- Missing values are forward-filled up to N steps.
- Regime stationarity is assumed over the training window.
(6) Limitations
Limitations are known failure modes and non-claims.
Examples:
- Performance degrades in high-volatility regimes.
- Model is not calibrated; probabilities must not be used for pricing.
- Not validated for illiquid assets or corporate action days.
- Not robust to timestamp errors or delayed data feeds.
Key difference
Assumptions justify why you think it works. Limitations state where you know it may not work.
4.3 A minimal folder structure (example)
project/
README.md
config/
run.yaml
src/
build_features.py
train.py
predict.py
evaluate.py
utils.py
artefacts/
run_id_YYYYMMDD_HHMM/
config_snapshot.yaml
metrics.json
metrics_subperiod.csv
metrics_regime.csv
plots/
cv_fold_metric.png
error_over_time.png
residual_hist.png
report.md
Rule
An artefact folder is immutable once created.
4.4 Minimal reproducibility contract
A run is reproducible if you can state:
- Code hash / version tag.
- Data version identifiers (tables, snapshots, query hash).
- Config snapshot.
- Random seeds.
- Environment (Python version, package versions).
In notation:
5. Control lens
5.1 Analogue and failure mode
Control analogue
A controller design is delivered with:
- plant model assumptions,
- operating region,
- stability margins,
- constraints,
- and implementation details.
Finance analogue
A model must be delivered with:
- data and evaluation protocol,
- assumptions and limitations,
- operational constraints,
- and reproducible artefacts.
The failure is the same: “It worked in simulation” is not a deliverable.
6. Worked example (what to ship)
A simple forecasting model for a daily decision should ship:
- Code: feature build, baseline, model, evaluation.
- Config: horizon, split dates, baseline choice.
- Metrics: RMSE/MAE by fold and year; worst-year.
- Plots: fold RMSE, error over time, residual histogram.
- Assumptions: execution timing, cost assumptions if trading.
- Limitations: stress regime degradation.
7. Python lab (create a tiny evidence pack)
This code creates a local folder and writes: - config snapshot (json), - metrics (json), - one plot (png), - a short report (md).
import json
import os
from datetime import datetime
import numpy as np
import matplotlib.pyplot as plt
# -----------------------------
# Create a run id and folders
# -----------------------------
run_id = datetime.now().strftime("run_%Y%m%d_%H%M%S")
base = os.path.join("artefacts", run_id)
plots_dir = os.path.join(base, "plots")
os.makedirs(plots_dir, exist_ok=True)
# -----------------------------
# Example "config snapshot"
# -----------------------------
config = {
"problem": "toy_forecast",
"target": "y_{t+1}",
"horizon": 1,
"split": {"type": "time_holdout", "train_frac": 0.7},
"baseline": "last_value",
"model": "linear_lags",
"seed": 0,
}
with open(os.path.join(base, "config_snapshot.json"), "w") as f:
json.dump(config, f, indent=2)
# -----------------------------
# Generate a tiny dataset + metrics
# -----------------------------
rng = np.random.default_rng(config["seed"])
T = 300
t = np.arange(T)
y = 0.02 * t + 0.6 * np.sin(2*np.pi*t/20) + rng.normal(0, 0.8, T)
# Baseline: last value
y_hat = np.roll(y, 1)
y_hat[0] = np.nan
# Split
idx = np.arange(T)
valid = ~np.isnan(y_hat)
idx = idx[valid]
y_v = y[valid]
y_hat_v = y_hat[valid]
split = int(config["split"]["train_frac"] * len(idx))
test_y = y_v[split:]
test_hat = y_hat_v[split:]
rmse = float(np.sqrt(np.mean((test_y - test_hat)**2)))
mae = float(np.mean(np.abs(test_y - test_hat)))
metrics = {"test_rmse": rmse, "test_mae": mae, "n_test": int(len(test_y))}
with open(os.path.join(base, "metrics.json"), "w") as f:
json.dump(metrics, f, indent=2)
# -----------------------------
# One plot
# -----------------------------
plt.figure(figsize=(8, 4))
plt.plot(test_y[:80], label="y (test)")
plt.plot(test_hat[:80], label="baseline last value")
plt.title("Deliverable plot: baseline forecast on test window")
plt.xlabel("Time index (test)")
plt.ylabel("Value")
plt.legend()
plt.tight_layout()
plt.savefig(os.path.join(plots_dir, "baseline_test_overlay.png"), dpi=150)
plt.close()
# -----------------------------
# Short report (assumptions + limitations)
# -----------------------------
report = f"""# Evidence pack: {run_id}
## Summary
This run evaluates a toy baseline forecast for a synthetic series.
## Config
- Target: {config["target"]}
- Horizon: {config["horizon"]}
- Split: {config["split"]}
## Metrics (test)
- RMSE: {rmse:.4f}
- MAE: {mae:.4f}
- n_test: {len(test_y)}
## Assumptions
- Synthetic data is stationary enough for demonstration.
- Baseline uses y_t to predict y_(t+1).
## Limitations
- Not a trading evaluation.
- No regime stability checks included.
"""
with open(os.path.join(base, "report.md"), "w") as f:
f.write(report)
print("Created evidence pack at:", base)
print("Files:", os.listdir(base))8. Diagnostics and failure modes (deliverables)
- Metrics without config are not interpretable.
- Plots without labels and dates are not evidence.
- Results without assumptions are not auditable.
- Models without limitations are overclaims.
- If artefacts are mutable, results cannot be trusted.
9. Mini-exercises
Exercise 1
List the six artefact classes in the evidence pack.
Solution Code, config, metrics, plots, assumptions, limitations.
Exercise 2 (trap)
You have a strong plot and a strong metric. You do not have the config snapshot. Is the result valid?
Solution No. You cannot reproduce or audit without the config.
10. Summary
- Deliverables are artefact bundles, not slide decks.
- The evidence pack is the minimum standard for validation and reuse.
- Assumptions and limitations are as important as the metric.
11. Out of scope
- Full CI/CD, model registry, and production deployment pipelines.
- Enterprise data lineage systems.