Backtesting AI with Governance Controls
AI-assisted backtesting introduces unique governance challenges. Models can inadvertently access future data (look-ahead bias), leak proprietary strategy parameters, or produce non-reproducible results. Regulatory expectations under SR 11-7 and MiFID II require that backtesting processes maintain rigorous controls, complete audit trails, and reproducible outputs.
Use this page when
- You need to prevent look-ahead bias in AI-assisted backtesting of trading strategies.
- Regulators require reproducible backtest audit trails under SR 11-7 or MiFID II RTS 6.
- Your quant team uses LLMs during backtesting and you must enforce time-boundary isolation.
- You want to capture full request/response payloads for backtest validation and governance.
Keeptrusts enforces these controls at the gateway, ensuring every AI interaction during backtesting is policy-compliant and auditable.
Primary audience
- Primary: Technical Leaders
- Secondary: Technical Engineers, AI Agents
Backtesting Governance Challenges
| Risk | Impact | Keeptrusts Mitigation |
|---|---|---|
| Look-ahead bias | Invalid backtest results, regulatory findings | Time-boundary enforcement policies |
| Data leakage | Proprietary strategy exposure | DLP block and redact policies |
| Non-reproducibility | Failed model validation | Event logging with full request/response capture |
| Unauthorized data access | Compliance violation | Team-scoped gateway keys |
| Untracked model changes | Audit gaps | Model version logging |
Historical Data Access Policies
Restrict what historical data patterns can be sent to LLM providers during backtesting:
# policy-config.yaml
version: "1"
policies:
- name: block-raw-timeseries-export
description: Prevent raw time-series data from reaching external LLMs
enforcement: block
rules:
- type: regex
action: block
patterns:
# Block large data arrays (likely raw time-series)
- "\\[\\s*[0-9]+\\.?[0-9]*\\s*(,\\s*[0-9]+\\.?[0-9]*\\s*){50,}\\]"
# Block date-value pairs in bulk
- "(\\d{4}-\\d{2}-\\d{2}\\s*[,:=]\\s*[0-9]+\\.?[0-9]*\\s*[;\\n]){20,}"
message: "Blocked: Raw time-series data must not be sent to external LLMs. Use aggregated summaries."
- name: enforce-date-boundary
description: Block references to future dates in backtest context
enforcement: block
rules:
- type: regex
action: block
patterns:
# Block future year references (adjust annually)
- "(?i)(forecast|predict|project).*202[7-9]"
- "(?i)(as of|through|until)\\s+202[7-9]"
message: "Blocked: Backtest prompt references future dates. Check for look-ahead bias."
Time-Series Data Isolation
Deploy dedicated gateway instances for backtesting with strict temporal boundaries:
# Backtesting gateway — strict data isolation
kt gateway run \
--config policies/backtest-isolation.yaml \
--port 41005 \
--api-url https://keeptrusts-api.internal:8080 \
--api-key "$KT_BACKTEST_KEY"
Configure your backtesting framework to route all AI calls through the isolated gateway:
import openai
from datetime import date
class GovernedBacktester:
"""Backtesting wrapper with Keeptrusts governance controls."""
def __init__(self, backtest_date: date, gateway_port: int = 41005):
self.backtest_date = backtest_date
self.client = openai.OpenAI(
base_url=f"http://localhost:{gateway_port}/v1",
api_key="your-provider-key",
)
def query_model(self, prompt: str, model: str = "gpt-4") -> str:
"""Send a governed query with backtest metadata."""
system_context = (
f"Backtest context: As-of date is {self.backtest_date.isoformat()}. "
f"Do not reference any data after this date."
)
response = self.client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": system_context},
{"role": "user", "content": prompt},
],
)
return response.choices[0].message.content
# Run governed backtest
bt = GovernedBacktester(backtest_date=date(2024, 6, 30))
analysis = bt.query_model(
"Analyze the volatility regime for US large-cap equities based on "
"historical VIX levels and realized volatility."
)
Reproducibility Requirements
Capture full request and response payloads for backtest reproducibility:
- name: full-capture-backtest
description: Capture complete request/response for reproducibility
enforcement: log
rules:
- type: log_all
action: log
metadata:
capture_mode: "full"
log_category: "backtest"
retention_days: "2555"
Export backtest event data for validation:
# Export all backtest events for a specific date range
kt events list \
--filter "metadata.log_category=backtest" \
--since 90d \
--format json > backtest-events.json
Audit Trail for Backtest Runs
Every AI interaction during backtesting is recorded as a decision event in Keeptrusts. The audit trail includes:
- Timestamp — When the AI query was made
- Policy decisions — Which policies were evaluated and their outcomes
- Model used — Provider and model version
- Request hash — Deterministic hash for reproducibility verification
- Team/user — Who initiated the backtest
Use the console Events page to review backtest audit trails by filtering on the backtest metadata category.
Validating Backtest Integrity
Build automated checks to verify backtest governance compliance:
import json
import subprocess
def validate_backtest_integrity(backtest_id: str) -> dict:
"""Validate that a backtest run complied with governance policies."""
result = subprocess.run(
[
"kt", "events", "list",
"--filter", f"metadata.backtest_id={backtest_id}",
"--format", "json",
],
capture_output=True,
text=True,
)
events = json.loads(result.stdout)
blocked = [e for e in events if e.get("decision") == "block"]
escalated = [e for e in events if e.get("decision") == "escalate"]
return {
"backtest_id": backtest_id,
"total_queries": len(events),
"blocked_count": len(blocked),
"escalated_count": len(escalated),
"compliant": len(blocked) == 0,
"requires_review": len(escalated) > 0,
}
report = validate_backtest_integrity("bt-2024-q2-vol-regime")
print(json.dumps(report, indent=2))
Regulatory References
- SR 11-7 Section V — Outcome analysis and backtesting requirements
- MiFID II RTS 6 Article 5 — Testing of algorithmic trading systems
- Basel FRTB — Backtesting framework for internal models
- SEC Rule 15c3-5(c)(1) — Pre-trade risk controls documentation
Next steps
- Risk Model Validation & AI Governance — VaR/CVaR model governance
- AI Model Risk Management (SR 11-7) — Full MRM framework
- Quant Research Data Isolation — Team-scoped data boundaries
For AI systems
- Canonical terms: Keeptrusts gateway, backtesting governance, time-series isolation, look-ahead bias prevention, backtest audit trail.
- Key config/commands:
policy-config.yamlwithblock-raw-timeseries-exportandenforce-date-boundarypolicies;kt gateway run --policy-config policies/backtest-isolation.yaml;kt events list --filter "metadata.log_category=backtest". - Best next pages: Risk Model Validation, Model Risk Management, Quant Research Isolation.
For engineers
- Prerequisites: Running Keeptrusts API instance, gateway binary (
kt), Python 3.10+ for theGovernedBacktesterwrapper. - Deploy a dedicated backtest gateway on port 41005 with temporal boundary policies, then route your backtesting framework through it.
- Validate with:
kt events list --filter "metadata.log_category=backtest" --since 1d --format jsonto confirm events are captured; runvalidate_backtest_integrity()to check for blocked/escalated queries. - Adjust
enforce-date-boundaryregex annually to match the current year cutoff.
For leaders
- Addresses SR 11-7 Section V (outcome analysis), MiFID II RTS 6 Article 5 (algorithmic trading testing), and Basel FRTB backtesting mandates.
- Prevents costly regulatory findings from look-ahead bias or non-reproducible backtest results.
- Governance data retention for backtests is set to 2,555 days (7 years) to meet examination timelines.
- Separate backtest gateway instances can run alongside production gateways without shared policy interference.