DEV Community

Ray
Ray

Posted on • Originally published at github.com

I built an overnight strategy tournament to find the best trading algorithm while I sleep

I built TradeSight — a self-hosted Python platform for algorithmic paper trading that runs overnight strategy tournaments to evolve the best-performing configuration before market open.

Here's the part that actually surprised me: letting strategies compete and reproduce overnight produced a Sharpe ratio of 2.53 — vs 0.3–0.8 from static indicator configs I'd hardcoded.

The tournament idea

Most algo trading tutorials give you a fixed strategy: buy when RSI < 30, sell when RSI > 70. The problem is that works until it doesn't — markets shift, and static params go stale.

So instead of tuning a single strategy, TradeSight runs a tournament each night:

  1. Seed ~20 strategy variants with randomized indicator weights (RSI threshold, MACD fast/slow, Bollinger width, etc.)
  2. Backtest each on the past 90 days of data
  3. Score by Sharpe ratio (risk-adjusted return)
  4. Keep the top 50%, mutate their params, repeat for 10 generations
  5. Promote the winner to live paper trading at market open

This is basically a genetic algorithm on trading configs. Simple, but it works.

def run_tournament(historical_data, generations=10, population_size=20):
    population = [random_strategy() for _ in range(population_size)]

    for gen in range(generations):
        scored = [(strategy, backtest_sharpe(strategy, historical_data)) 
                  for strategy in population]
        scored.sort(key=lambda x: x[1], reverse=True)

        # Keep top half
        survivors = [s for s, _ in scored[:population_size // 2]]

        # Mutate + crossover to refill
        population = survivors + [
            mutate(random.choice(survivors)) 
            for _ in range(population_size // 2)
        ]

    winner = max(scored, key=lambda x: x[1])
    return winner[0]
Enter fullscreen mode Exit fullscreen mode

What TradeSight includes

  • 15+ technical indicators: RSI, MACD, Bollinger Bands, EMA, SMA, ADX, Stochastic, VWAP, and more
  • Overnight tournament engine: evolves strategy configs while you sleep
  • Circuit breakers: per-position stop-loss, daily drawdown limits, position sizing constraints
  • Alpaca integration: connects to Alpaca's paper trading API — free to use, real market data
  • Web dashboard: see active positions, P&L, tournament results, and signal history
  • No subscription fees: fully self-hosted, runs on any machine with Python 3.9+

The circuit breaker design

One thing I spent a lot of time on: making sure a bad signal can't blow up the whole account. Every position has:

class CircuitBreaker:
    def __init__(self, max_daily_loss_pct=0.02, max_position_pct=0.10):
        self.max_daily_loss_pct = max_daily_loss_pct  # 2% daily max loss
        self.max_position_pct = max_position_pct      # 10% max per position

    def check(self, account_value, daily_pnl, proposed_position_value):
        daily_loss_pct = abs(daily_pnl) / account_value
        position_pct = proposed_position_value / account_value

        if daily_loss_pct >= self.max_daily_loss_pct:
            raise CircuitBreakerTripped(f"Daily loss limit hit: {daily_loss_pct:.1%}")
        if position_pct > self.max_position_pct:
            raise PositionTooLarge(f"Position {position_pct:.1%} exceeds limit")
Enter fullscreen mode Exit fullscreen mode

A trading system without circuit breakers is an account-destroyer waiting to happen.

Getting started

git clone https://github.com/rmbell09-lang/tradesight
cd tradesight
pip install -r requirements.txt
cp .env.example .env  # add your Alpaca paper trading keys
python app.py
Enter fullscreen mode Exit fullscreen mode

You'll need a free Alpaca account for paper trading keys. No real money involved.

What I learned

Static strategies are a trap. The evolutionary approach consistently outperforms any single configuration I could tune by hand. The market isn't static — your strategy config shouldn't be either.

Position sizing matters more than signal quality. I had strategies with great win rates getting blown out by oversized positions on bad days. The circuit breakers fixed this.

Backtesting is necessary but not sufficient. A strategy that scores 2.53 Sharpe on 90 days of history doesn't mean it will keep that in live paper trading. The system is still evolving.


The repo is at github.com/rmbell09-lang/tradesight. It's MIT licensed, self-hosted, and free to use.

If you're interested in algo trading or building something similar, happy to answer questions in the comments.

Top comments (0)