Skip to main content

Professional event-driven backtesting framework for quantitative trading strategies

Project description

enode-backtester

Lightweight event-driven backtesting framework that wires together data handlers, strategies, sizing logic, a portfolio, execution simulation, and analysis helpers. The library is designed as a foundation you can extend with richer metrics, visualisations, and strategy research.


Repository Layout

  • backtester/__init__.py – Public entry point exporting run_backtest, utility helpers, and default sizing/execution models.
  • backtester/data.py – Data-handling abstractions. DataFrameDataHandler streams pandas data frames into the event queue as StockEvents.
  • backtester/event.py – Event hierarchy that flows through the engine (market data, signals, orders, fills).
  • backtester/strategy.py – Base strategy contract; provides the signal helper for emitting SignalEvents.
  • backtester/sizer.py – Base sizing abstraction plus a simple FixedSizeSizer.
  • backtester/portfolio.py – Tracks cash, positions, trade log, equity curve, and reacts to incoming events.
  • backtester/execution.py – Simulated execution handler with configurable slippage and commission models.
  • backtester/engine.py – Core event loop that coordinates the handlers and processes the event queue.
  • backtester/analysis.py – Post-run utilities, including an optional PyFolio tear sheet and trade log export.
  • backtester/models.py – Pydantic models shared across modules (e.g., StockCandle).

Installation

# using uv (recommended)
uv sync

# or using pip / virtualenv
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

pyfolio is optional; install it (pip install pyfolio) if you need tear-sheet generation.


Creating a Strategy

  1. Subclass backtester.strategy.BaseStrategy.
  2. Implement on_stock_event(self, event) to react to incoming candles (event.payload is a StockCandle).
  3. Use self.signal(symbol, timestamp, action) to enqueue SignalEvents (action is typically "buy" or "sell").
from collections import deque

from backtester.strategy import BaseStrategy
from backtester.event import StockEvent


class MySMAStrategy(BaseStrategy):
    def __init__(self, event_queue, data_handler, window: int = 20):
        super().__init__(event_queue, data_handler)
        self.window = window
        self.prices: dict[str, deque[float]] = {}

    def on_stock_event(self, event: StockEvent) -> None:
        symbol = event.payload.symbol
        price = event.payload.close
        history = self.prices.setdefault(symbol, deque(maxlen=self.window))
        history.append(price)

        if len(history) < history.maxlen:
            return

        avg_price = sum(history) / len(history)
        if price > avg_price:
            self.signal(symbol, event.payload.timestamp, "buy")
        elif price < avg_price:
            self.signal(symbol, event.payload.timestamp, "sell")

Running a Backtest

import pandas as pd

from backtester import FixedSizeSizer, run_backtest, get_trade_log_df
from backtester.data import DataFrameDataHandler
from my_strategies import MySMAStrategy

# 1. Prepare your market data as pandas DataFrames keyed by symbol
data_dict: dict[str, pd.DataFrame] = {
    "AAPL": aapl_df,
    "GOOGL": googl_df,
}

# 2. Choose a sizing model (optional)
sizer = FixedSizeSizer(default_size=10)

# 3. Execute the backtest
portfolio = run_backtest(
    data_dict=data_dict,
    strategy_class=MySMAStrategy,
    initial_cash=100_000.0,
    sizer=sizer,
)

# 4. Inspect results
trade_log = get_trade_log_df(portfolio)
print(trade_log.tail())
print(f"Final equity: {portfolio.equity_curve[-1][1]:,.2f}")

run_backtest instantiates all core components for you:

  • DataFrameDataHandler feeds candles into the event queue.
  • Your strategy consumes StockEvents and emits SignalEvents.
  • Portfolio generates OrderEvents using the provided Sizer.
  • SimulatedExecutionHandler fills orders with configurable commission and slippage.

After the engine finishes processing all data, you receive the final Portfolio object for downstream analysis.


Extending the Framework

  • Metrics & Visuals: Add new functions under backtester.analysis or integrate notebooks that consume the trade log and equity curve.
  • Strategies: Drop additional strategy classes alongside your own module; they only need to inherit from BaseStrategy.
  • Execution/Sizing: Create custom classes that follow the abstract base class signatures in execution.py and sizer.py.
  • Data: Implement new handlers by subclassing BaseDataHandler if you need live feeds, streaming data, or alternative storage.

Contributing

Pull requests and issues welcome—especially around additional strategy templates, validation rules, and analytical tooling.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

enode_backtester-0.1.2.tar.gz (198.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

enode_backtester-0.1.2-py3-none-any.whl (192.3 kB view details)

Uploaded Python 3

File details

Details for the file enode_backtester-0.1.2.tar.gz.

File metadata

  • Download URL: enode_backtester-0.1.2.tar.gz
  • Upload date:
  • Size: 198.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for enode_backtester-0.1.2.tar.gz
Algorithm Hash digest
SHA256 4aa9e25f67f3062eccb61610d246942aa4733e402f649563e7d28244dc2b2ded
MD5 dc0d6988f9b0e74319a233ddfc86915d
BLAKE2b-256 fe7f27837eab4dc58bfe467ca116511d96ed92698fd6a04dd4e3018ad7a1006c

See more details on using hashes here.

File details

Details for the file enode_backtester-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for enode_backtester-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 7c0f4120fe7708a932ac98195ad9bed1b1b8321113a47126fbf4514fbd5f377b
MD5 00d42873999b01c21614be9fc0d92199
BLAKE2b-256 3b7eafafc0910b0aae9a1ea65547cb87619bbb138dbd255d62f2701734844fba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page