I wanted a system that could discover trading strategies without me hand-tuning every parameter. So I built one.
finclaw is an open-source quantitative finance engine in Python. One of its core features is an evolution engine that uses genetic algorithm principles to mutate, evaluate, and improve trading strategies automatically. After running it for 89 generations on NVDA data, here's what I learned.
The Problem With Manual Strategy Tuning
Every quant hits the same wall: you write a strategy, backtest it, tweak a parameter, backtest again. Repeat 200 times. You end up overfitting to historical data without realizing it.
I wanted something that could explore the strategy space systematically — try combinations I wouldn't think of, and discard what doesn't work through a principled selection process rather than gut feeling.
How The Evolution Engine Works
The core loop is deceptively simple:
- Seed — Start with a YAML strategy definition (entry rules, exit rules, filters)
- Evaluate — Backtest the strategy and compute a fitness score (return, Sharpe, drawdown, win rate)
- Analyze — Look at where the strategy fails (losing trade clusters, poor exits, bad market timing)
- Propose — Generate targeted mutations: tighten stop losses, adjust RSI thresholds, add volume filters
- Mutate — Apply the best proposal to create a child strategy
- Select — Keep a Pareto frontier of the top N strategies
- Repeat — Until convergence or max generations
Each strategy is a YAML file that the DSL engine compiles into executable trading rules:
name: momentum_rsi_evolved
entry:
- rsi_14 < 35
- ma_cross(5, 20) == "golden"
- volume > volume_ma_20 * 1.3
exit:
- rsi_14 > 72
- trailing_stop: 8%
filters:
- trend_adx_strength > 20
The mutator modifies these rules — widening RSI bands, swapping moving average periods, adding or removing filters — while the evaluator runs a full backtest on each variant.
Running It
# Install finclaw
pip install finclaw
# Evolve a strategy for 50 generations
finclaw evolve my_strategy.yaml --symbol NVDA --generations 50 --frontier-size 5
Or via the Python API:
from src.evolution.engine import EvolutionEngine, EvolutionConfig
from src.strategy.expression import OHLCVData
config = EvolutionConfig(
max_generations=50,
frontier_size=5,
no_improvement_limit=10,
)
engine = EvolutionEngine(config=config)
result = engine.run(seed_strategy, my_data)
print(f"Best score: {result['best_score'].composite():.4f}")
print(f"Generations: {result['generations_run']}")
What 89 Generations Found
I seeded the engine with a basic golden-cross momentum strategy on NVDA (2022-2025 daily data) and let it run.
Generation 1 (seed): Sharpe 0.42, max drawdown -28%, win rate 38%
The seed was mediocre. Lots of whipsaw trades during the 2022 drawdown.
Generation 23: Sharpe 0.91, max drawdown -19%, win rate 44%
The engine discovered that adding a volume confirmation filter (volume > 1.5x 20-day average) eliminated most false breakouts. It also tightened the trailing stop from 12% to 8%.
Generation 56: Sharpe 1.24, max drawdown -15%, win rate 48%
A mutation added an ADX trend strength filter (ADX > 25), preventing entries during choppy sideways markets. This was the single biggest improvement — cutting drawdown by 4 percentage points.
Generation 89 (final): Sharpe 1.31, max drawdown -14%, win rate 51%
The final strategy bore little resemblance to the seed. It had evolved RSI thresholds from 30/70 to 33/68, added two filters the original didn't have, and switched from a fixed stop loss to a trailing stop with an ATR multiplier.
The Anti-Overfitting Problem
Genetic algorithms are overfitting machines if you're not careful. Here's what I built to fight it:
Walk-forward validation. The evaluator doesn't just backtest on the full dataset. It uses walk-forward splits — train on 2 years, test on the next 6 months, slide forward. The fitness score is the out-of-sample performance.
Monte Carlo stress testing. Each candidate strategy also gets run through 100 Monte Carlo shuffles to check if the equity curve is robust or just lucky.
Pareto frontier. Instead of optimizing a single metric, the frontier tracks multiple objectives (return, risk, consistency). A strategy that sacrifices some return for much lower drawdown stays in the population.
# Run with walk-forward validation (built-in)
finclaw evolve strategy.yaml --symbol AAPL --generations 30 --start 2020-01-01
Architecture
The engine is built from four pluggable components:
-
Evaluator — Runs backtests and computes
FitnessScore(composite of return, Sharpe, drawdown, win rate) - Proposer — Analyzes failures and generates mutation candidates
- Mutator — Applies YAML-level mutations to strategy definitions
- Frontier — Manages the Pareto-optimal strategy set
Each component is replaceable. You can plug in your own evaluator that uses a different backtesting engine, or write a custom proposer that targets specific strategy weaknesses.
What I Learned
Volume filters matter more than entry signals. Across dozens of evolved strategies, the single most impactful mutation was always some form of volume confirmation. The market is noisy; volume tells you when the signal is real.
Stop losses evolve toward ATR-based trailing stops. Fixed percentage stops consistently get replaced by volatility-adjusted ones. Makes sense — a 5% stop is too tight for a volatile stock and too loose for a calm one.
Fewer rules beat more rules. The engine repeatedly pruned overly complex strategies. The best performers had 3-5 entry conditions, not 10. Occam's razor, enforced by selection pressure.
Try It
finclaw is open source. The evolution engine runs on any OHLCV data — US stocks, A-shares, crypto.
pip install finclaw
finclaw evolve your_strategy.yaml --symbol AAPL --generations 20
The full codebase, including 240+ technical factors, walk-forward backtesting, and paper trading:
finclaw on GitHub | Python · 240+ factors · Evolution engine · Paper trading
If you're interested in AI agent security (the other thing I work on), check out ClawGuard — an open-source AI agent security engine with 285+ threat patterns.
The evolution engine code lives in src/evolution/. PRs welcome.
Top comments (0)