Skip to content

darquantlabs/backtrader-strategy-validator

Repository files navigation

backtrader-strategy-validator

AST-based look-ahead bias and rule validation for Backtrader strategies.

It analyzes strategy source code as text — it never imports or runs backtrader, so it has zero runtime dependencies (stdlib ast only) and is safe to run anywhere, including in a strategy-generation / evolution loop before a candidate is ever backtested.

Heuristic, not a proof. This is static analysis. It flags known problematic patterns; it cannot guarantee a strategy is free of look-ahead bias. Treat a clean result as "no known red flags", not "verified correct".

What it detects

Category Examples
Look-ahead bias future bar index (close[1]), intrabar high[0]/low[0] in decisions, limit prices from current-bar data, SL/TP set before fill, higher-timeframe close[0], indicators that use high/low (ATR, Stochastic…), entry_price set in next()
Data feed limits more than 3 feeds (data0, data1, data2) — e.g. self.data3, self.datas[3]
Position management simultaneous long/short, missing if not self.position: guards, non-mutually-exclusive if/if entries
Order routing orders sent to a feed other than data0 (data1/data2 are read-only context feeds)

Install

pip install backtrader-strategy-validator

Or from source:

pip install -e ".[dev]"

Requires Python 3.9+.

Quickstart

from bt_validator import get_validation_summary

code = '''
class S(bt.Strategy):
    def next(self):
        if self.data.close[1] > self.data.close[0]:   # future bar!
            self.buy(data=self.data1)                  # order on non-data0!
'''

summary = get_validation_summary(code)
print(summary["score"])          # severity score in [0.0, 1.0]
print(summary["is_acceptable"])  # False
for issue in summary["issues"]:
    print(issue["severity"], issue["type"], "line", issue["line"])

Lower-level API

from bt_validator import LookAheadDetector, DetectionCategory, Severity

detector = LookAheadDetector()                 # all categories
issues = detector.detect(code)
for i in issues:
    print(f"{i.severity.value}: {i.message} (line {i.line})")
    print(f"  fix: {i.suggestion}")

print(detector.calculate_severity_score())     # 0.0 – 1.0
print(detector.is_acceptable(threshold=0.5))   # bool
print(detector.get_blocking_issues())          # errors + heavy warnings

# Restrict to specific categories:
LookAheadDetector(categories=[DetectionCategory.ORDER_ROUTING]).detect(code)

Convenience helpers

from bt_validator import (
    has_any_validation_errors, get_severity_score, is_strategy_acceptable,
    has_lookahead_bias, has_order_routing_errors, format_issues_for_llm,
)

format_issues_for_llm(issues) renders findings as plain text suitable for feeding back into an LLM prompt (handy in a generate → validate → regenerate loop).

Severity & scoring

Each issue carries a Severity (ERROR / WARNING / INFO) and a per-type weight. calculate_severity_score() sums weight × severity_modifier across all issues, applies a mild multi-issue penalty (the first issue does not scale), and caps the result at 1.0. is_acceptable(threshold) returns score < threshold (strict), with a default threshold of 0.5.

License

MIT.

About

AST-based look-ahead bias and rule validation for Backtrader strategies

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages