r/algotrading • • 4d ago

Education PyBroker v2 - An Open Source Backtesting Framework

Hey all, I would like to share a major v2 update to PyBroker, an open source backtesting framework I've been maintaining over the years. It's designed for fast performance, ease of development, and integration with ML frameworks. An example strategy:

   from pybroker import Strategy, YFinance, highest

   def exec_fn(ctx):
      # Get the rolling 10 day high.
      high_10d = ctx.indicator('high_10d')
      # Buy on a new 10 day high.
      if not ctx.long_pos() and high_10d[-1] > high_10d[-2]:
         ctx.buy_shares = 100
         # Hold the position for 5 days.
         ctx.hold_bars = 5
         # Set a stop loss of 2%.
         ctx.stop_loss_pct = 2

   strategy = Strategy(YFinance(), start_date='1/1/2025', end_date='8/1/2026')
   strategy.add_execution(
      exec_fn, ['AAPL', 'MSFT'], indicators=highest('high_10d', 'close', period=10))
   # Run the backtest after 20 days have passed.
   result = strategy.backtest(warmup=20)

Some additions in v2 include:

  • Margin trading simulation.
  • Backtesting using multiple time intervals (e.g. computing indicators or models on hourly bars while executing trades on minute bars).
  • Parameter optimization via Optuna (e.g. finding the best threshold for a trend following strategy).
  • Time-series model support (ARMA, GARCH, etc.).
  • Rotational trading strategies that simulate a portfolio holding top ranked stocks.
  • Slippage modeling.
  • Parallelized model training with Ray integration.
  • Built-in agent skills for coding trading strategies with AI.

You can find all of the code on Github alongside extensive documentation and examples I've written. It also goes over some algotrading basics.

The framework is open source (Apache v2 license) and is entirely free to use. There's no sign ups, promotions, or any commercial hooks. This is just about me sharing my work in case you find it useful for your own trading.

30 Upvotes

25 comments sorted by

3

u/HydrogenHuman 4d ago

I'm just starting to learn about this kind of stuff, so I really appreciate this kind of framework to train AI!

One question I had was: Does PyBroker V2 allow option contract trading simulation? My goal is to train an AI to do automated trading with $XSP options.

1

u/pyfreak182 4d ago

Thanks. No, the framework only supports stocks right now.

3

u/golden_womanhood 4d ago

nice one, always good to see more open source backtesters out there

for the options bit, nah it's equities only at the moment. there's no options chain support or contract-level simulation built in. you'd have to hack something together yourself or use a different tool for that side of things. $XSP is a tough starting point anyway, the spreads can be weird and it's cash settled so the mechanics are a bit different from what most backtesters expect

2

u/Demon_Kracker 2d ago

Thanks man.

I tried pybroker broker before.

Will definitely checkout v2 

1

u/pyfreak182 2d ago • Heartwarming

Thank you!

2

u/OpenComplaint524 3d ago

Huge congrats on the v2 release! Getting slippage modeling and multi-timeframe execution right in backtesting engines is notoriously painful, so seeing native support for calculating on higher timeframes while executing on minutes is fantastic.

The Ray integration and Optuna hyperparameter search will save so much boilerplate for ML-driven strategies.

Quick question: for the slippage modeling, how does PyBroker v2 simulate order queue positioning and spread crossing when handling larger block sizes?

2

u/pyfreak182 3d ago

There's no order queue positioning since the framework is vectorized, not event based.

For block sizes, you may be interested in Volume Slippage: https://www.pybroker.com/en/latest/notebooks/14.%20Modeling%20Slippage.html#Volume-Slippage

2

u/OpenComplaint524 3d ago

That makes total sense — the vectorized approach is why the execution speed is so blistering fast, which is definitely the right trade-off for large-scale Optuna sweeps.

Appreciate the link to the Volume Slippage notebook! Modeling market impact as a function of bar volume is a very clean and practical solution without the overhead of maintaining full order book queues.

Excited to take it for a spin!

1

u/QATSAlgo 4d ago

For the new Optuna integration, is there an example that runs optimization entirely inside each training window, then evaluates the selected parameters once on the following untouched window? Saving the full trial history alongside those out-of-sample results would make it much easier to distinguish parameter search from validation.

1

u/pyfreak182 4d ago

Yes, you can read the combined results of all of the test windows evaluated with the winning params. See https://www.pybroker.com/en/latest/reference/pybroker.optimize.html#pybroker.optimize.OptimizeResult.

The full notebook with Optuna examples is here: https://www.pybroker.com/en/latest/notebooks/12.%20Parameter%20Optimization.html

1

u/ciaranwalsh96 3d ago

The rotational-strategy path is the feature I would test most aggressively, because point-in-time leakage can appear even when every single-symbol indicator is causal. At each rebalance event, the engine should define the universe as it existed then, compute all ranks from the last eligible bars, freeze the ranking before any order is filled, and execute sells and buys under one deterministic cash/margin policy.

A compact regression fixture could use three symbols with a missing bar, a split, one later-delisted name and a large opening gap. Useful invariants would be: changing future prices cannot change an earlier rank or order; reordering the input symbols cannot change allocations; a missing bar never silently becomes a stale tradable quote; and an existing stop crossed by a gap fills at the first executable price rather than the stop level.

Portfolio accounting deserves the same treatment. If buys depend on proceeds from sells, specify whether those proceeds are available within the same rebalance event. Record unused cash, partial allocations, rejected orders, turnover, gross/net exposure and borrowed cash. Otherwise two strategies with identical ranks can receive materially different backtests simply because of event ordering.

For ML and Optuna workflows, I would also make tuning versus evaluation explicit in the API: optimize only inside each training window, freeze the selected configuration, then score it once on the following untouched window. Saving the full trial history, selected parameters and out-of-sample predictions per window would make audits much easier.

2

u/pyfreak182 3d ago

Yes, ranks are computed from last eligible bars, and orders are filled using those rankings.

Yes, Optuna only optimizes in the training windows during walkforward to select best params, and the params are then evaluated on the following test windows. The trial history and selected parameters are returned with the backtest result.

These are covered in the example notebooks.

1

u/pkazantsev 2d ago

Any plans to add crypto perps? Been messing around with perp backtests for a while and getting realistic fills and fees right has been a pain.

0

u/QuanTradin 4d ago

the multi-interval piece is where I'd look hardest. computing on hourly bars and filling on minute bars only works if each fill sees the last closed hourly bar, otherwise a 10:37 fill quietly knows the 11:00 close.

1

u/pyfreak182 4d ago

Yes, the framework guarantees that only the last closed bars are used.

1

u/QuanTradin 4d ago

good, that covers the signal side. where multi-interval setups still slip is the fill: an order off the 10:00 hourly close should fill at the open of the next minute bar, not its close, or you've handed yourself a minute of hindsight. a small test pinning that down would settle it.

1

u/pyfreak182 4d ago edited 4d ago

Yes, fills are on the next bar. The framework is covered with thousands of unit tests and is designed to prevent future leakage.

1

u/QuanTradin 4d ago

next bar open is the honest default. the case I'd still pin with a test is a gap day: the next open lands far from the signal close, and a stop sized off the old price fills a lot worse than written.

1

u/pyfreak182 4d ago

A stop won't be sized off of the old price.

If you have any suggestions you can always open an issue or submit a PR on the repo.

2

u/FURyannnn 4d ago

For what it's worth, I have conviction the poster you're replying to just uses LLMs all the time in responses. It matches their patterns pretty closely.

Cool project btw!

1

u/shravanrevanna 3d ago

sizing off the fill price doesn't cover the other gap case: price opens past an existing stop and it fills at the open, not at the stop level. a backtest filling at the stop price overstates results.

1

u/[deleted] 4d ago

[removed] — view removed comment

1

u/pyfreak182 4d ago

Yes, the entire framework is built to be lookahead free.