Skip to main content

A toolbox library for quant traders

Project description

Papers With Backtest Toolbox

The pwb-toolbox package is designed to provide tools and resources for systematic trading strategies. It includes datasets and strategy ideas to assist in developing and backtesting trading algorithms. For detailed instructions on how to use this package effectively, please refer to the associated Substack publication by visiting: https://blog.paperswithbacktest.com/.

Installation

To install the pwb-toolbox package:

pip install pwb-toolbox

This package requires Python 3.10 or higher.

To login to Huggingface Hub (where PWB datasets are hosted) with Access Token

huggingface-cli login

Usage

The pwb-toolbox package offers a range of functionalities for systematic trading analysis. Here are some examples of how to utilize the package:

Datasets

  • Import pwb_toolbox.datasets and sequentially loads datasets for different asset classes, such as bonds, commodities, cryptocurrencies, ETFs, forex, indices, and stocks, using the load_dataset function:
import pwb_toolbox.datasets as pwb_ds

df = pwb_ds.get_pricing(["AAPL", "MSFT", "GOOGL"])
df = pwb_ds.load_dataset("Bonds-Daily-Price")
df = pwb_ds.load_dataset("Commodities-Daily-Price")
df = pwb_ds.load_dataset("Cryptocurrencies-Daily-Price")
df = pwb_ds.load_dataset("ETFs-Daily-Price")
df = pwb_ds.load_dataset("Forex-Daily-Price")
df = pwb_ds.load_dataset("Indices-Daily-Price")
df = pwb_ds.load_dataset("Stocks-Daily-Price")
  • Load daily stock price data for specific symbols using the load_dataset function. The first call retrieves data for Apple and Microsoft. The second call retrieves the same stocks but without price adjustments (adjust=False). The third call loads daily price data for the S&P 500 index:
import pwb_toolbox.datasets as pwb_ds

df = pwb_ds.load_dataset(
    "Stocks-Daily-Price",
    ["AAPL", "MSFT"],
)

df = pwb_ds.load_dataset(
    "Stocks-Daily-Price",
    ["AAPL", "MSFT"],
    adjust=False,
)

df = pwb_ds.load_dataset(
    "Stocks-Daily-Price",
    ["sp500"],
)
  • The extend=True argument instructs the function to return an extended historical data using indices, commodities, and bonds data.
import pwb_toolbox.datasets as pwb_ds

df = pwb_ds.load_dataset(
    "ETFs-Daily-Price",
    ["SPY", "IEF"],
    extend=True,
)
  • The argument rate_to_price=False specifies that bond yield rates should not be converted to price values in the returned data:
import pwb_toolbox.datasets as pwb_ds

df = pwb_ds.load_dataset(
    "Bonds-Daily-Price",
    ["US10Y"],
    rate_to_price=False,
)
  • The argument to_usd=False indicates that the data should not be converted to U.S. dollars, implying that it might be available in another currency.
import pwb_toolbox.datasets as pwb_ds

df = pwb_ds.load_dataset(
    "Indices-Daily-Price",
    ["US10Y"],
    to_usd=False,
)

Backtest engine

The pwb_toolbox.backtesting module offers simple building blocks for running Backtrader simulations. Alpha models generate insights which are turned into portfolio weights and executed via Backtrader orders.

from pwb_toolbox.backtesting.examples import GoldenCrossAlpha, EqualWeightPortfolio
from pwb_toolbox.backtesting import run_backtest
from pwb_toolbox.backtesting.execution_models import ImmediateExecutionModel
from pwb_toolbox.backtesting.risk_models import MaximumTotalPortfolioExposure
from pwb_toolbox.backtesting.universe_models import ManualUniverseSelectionModel

run_backtest(
    ManualUniverseSelectionModel(["SPY", "QQQ"]),
    GoldenCrossAlpha(),
    EqualWeightPortfolio(),
    execution=ImmediateExecutionModel(),
    risk=MaximumTotalPortfolioExposure(max_exposure=1.0),
    start="2015-01-01",
)

The backtesting package is composed of a few focused modules:

  • backtest_engine – glue code that wires together universe selection, alpha models, portfolio construction and execution into a Backtrader run.
  • base_strategy – common bookkeeping and helpers used by all provided strategies.
  • commission – cost models for simulating broker commissions and spreads.
  • indicators – reusable signal and technical indicator implementations.
  • optimization_engine – genetic‑algorithm tooling for parameter searches.
  • portfolio – utilities for combining the results of several strategies and producing performance reports.
  • strategies – ready‑to‑use Backtrader Strategy subclasses.
  • universe – helpers for building trading universes (e.g. most liquid symbols).

pwb_toolbox.backtesting.strategies ships a collection of portfolio templates with different rebalancing rules and signal expectations:

  • DailyEqualWeightPortfolio – holds all assets with a long signal and allocates equal weight each day.
  • DailyLeveragePortfolio – goes long with fixed leverage when the signal is 1 and is otherwise flat.
  • EqualWeightEntryExitPortfolio – opens equally‑weighted positions when an entry condition triggers and leaves existing winners untouched.
  • DynamicEqualWeightPortfolio – event‑driven equal‑weight portfolio that can rebalance on any signal change or only when the set of long assets changes.
  • MonthlyLongShortPortfolio – once per month allocates half of the leverage to longs and half to shorts based on a universe‑aware signal.
  • MonthlyLongShortQuantilePortfolio – monthly rebalance that ranks assets by a per‑asset signal and goes long the strongest and short the weakest.
  • MonthlyRankedEqualWeightPortfolio – monthly equal‑weight portfolio with an optional ranking step and support for keeping only the top N assets.
  • QuarterlyTopMomentumPortfolio – every quarter concentrates exposure in the single asset with the strongest recent momentum.
  • RollingSemesterLongShortPortfolio – semi‑annual rebalancing template that accumulates long/short signals over six‑month windows.
  • WeeklyLongShortDecilePortfolio – rebalances weekly and trades the top and bottom deciles of a signal distribution.
  • WeightedAllocationPortfolio – turns user‑provided weights into integer share positions under a leverage constraint.

Optimal Limit Order Execution

The module pwb_toolbox.execution.optimal_limit_order implements the optimal limit‑order placement framework described in Optimal Portfolio Liquidation with Limit Orders by Guéant, Lehalle, and Tapia. Given a target quantity and time horizon, get_optimal_quote solves the associated system of differential equations to return the price offset from the mid‑price that maximises the expected utility of execution. Market parameters such as volatility (sigma), arrival rate of market orders (A), liquidity impact (k), trader risk aversion (gamma) and liquidation penalty (b) can be supplied to model different scenarios. Setting is_plot=True visualises the optimal quote path over time.

Live Strategy Execution

The execution helpers in pwb_toolbox.execution can connect to brokers to run strategies in real time. A typical session collects account information, computes target positions and submits the necessary orders.

Interactive Brokers

from pathlib import Path
import pandas as pd
from pwb_toolbox import execution as pwb_exec

STRATEGIES = {"my_strategy": {"path": "my_package.my_strategy", "weight": 1.0}}
logs_dir = Path("logs")
ACCOUNT_REFERENCE_NAV_VALUE = 100_000
ACCOUNT_REFERENCE_NAV_DATE = pd.Timestamp("2023-01-01")
LEVERAGE = 1.0
MARKET_DATA_TYPE = 1

ibc = pwb_exec.IBConnector(market_data_type=MARKET_DATA_TYPE)
ibc.connect()

account_nav_value = ibc.get_account_nav()
account_nav_date = pd.Timestamp.today().normalize()

nav_entry = pwb_exec.append_nav_history(logs_dir, account_nav_value)
nav_series, raw_positions = pwb_exec.run_strategies(STRATEGIES)
strategies_positions, theoretical_positions = pwb_exec.scale_positions(
    STRATEGIES,
    raw_positions,
    nav_series,
    ACCOUNT_REFERENCE_NAV_VALUE,
    LEVERAGE,
    ACCOUNT_REFERENCE_NAV_DATE,
)

ib_positions = ibc.get_positions()
orders = pwb_exec.compute_orders(theoretical_positions, ib_positions)

execution_time = 5 * 60  # five minutes
trades = pwb_exec.execute_and_log_orders(ibc, orders, execution_time)

pwb_exec.log_current_state(
    logs_dir,
    account_nav_value,
    strategies_positions,
    theoretical_positions,
    ib_positions,
    orders,
    account_nav_date,
    trades=trades,
    nav_history_entry=nav_entry,
)

ibc.disconnect()

CCXT Exchanges

from pathlib import Path
import pandas as pd
from pwb_toolbox import execution as pwb_exec

STRATEGIES = {"my_strategy": {"path": "my_package.my_strategy", "weight": 1.0}}
logs_dir = Path("logs")
ACCOUNT_REFERENCE_NAV_VALUE = 100_000
ACCOUNT_REFERENCE_NAV_DATE = pd.Timestamp("2023-01-01")
LEVERAGE = 1.0

cc = pwb_exec.CCXTConnector(
    exchange="binance",
    api_key="YOUR_API_KEY",
    api_secret="YOUR_API_SECRET",
)
cc.connect()

account_nav_value = cc.get_account_nav()
account_nav_date = pd.Timestamp.today().normalize()

nav_entry = pwb_exec.append_nav_history(logs_dir, account_nav_value)
nav_series, raw_positions = pwb_exec.run_strategies(STRATEGIES)
strategies_positions, theoretical_positions = pwb_exec.scale_positions(
    STRATEGIES,
    raw_positions,
    nav_series,
    ACCOUNT_REFERENCE_NAV_VALUE,
    LEVERAGE,
    ACCOUNT_REFERENCE_NAV_DATE,
)

cc_positions = cc.get_positions()
orders = pwb_exec.compute_orders(theoretical_positions, cc_positions)

execution_time = 5 * 60
trades = pwb_exec.execute_and_log_orders(cc, orders, execution_time)

pwb_exec.log_current_state(
    logs_dir,
    account_nav_value,
    strategies_positions,
    theoretical_positions,
    cc_positions,
    orders,
    account_nav_date,
    trades=trades,
    nav_history_entry=nav_entry,
)

cc.disconnect()

Performance Analysis

After running a live trading session, you can analyze the returned equity series using the pwb_toolbox.performance module.

from pwb_toolbox.backtesting.examples import GoldenCrossAlpha, EqualWeightPortfolio
from pwb_toolbox.backtesting import run_backtest
from pwb_toolbox.backtesting.execution_models import ImmediateExecutionModel
from pwb_toolbox.performance import total_return, cagr
from pwb_toolbox.performance.plots import plot_equity_curve

result, equity = run_backtest(
    ManualUniverseSelectionModel(["SPY", "QQQ"]),
    GoldenCrossAlpha(),
    EqualWeightPortfolio(),
    execution=ImmediateExecutionModel(),
    start="2015-01-01",
)

print("Total return:", total_return(equity))
print("CAGR:", cagr(equity))

plot_equity_curve(equity)

Contributing

Contributions to the pwb-toolbox package are welcome! If you have any improvements, new datasets, or strategy ideas to share, please follow these guidelines:

  1. Fork the repository and create a new branch for your feature.
  2. Make your changes and ensure they adhere to the package's coding style.
  3. Write tests to validate the functionality or provide sample usage examples.
  4. Submit a pull request, clearly explaining the purpose and benefits of your contribution.

Please note that all contributions are subject to review and approval by the maintainers.

Build the Package

To build the package, run:

python -m pip install --upgrade build
rm -r dist
python -m build

To upload the package to PyPI, run:

twine upload dist/*

Contact

For any questions, issues, or suggestions regarding the pwb-toolbox package, please contact the maintainers or create an issue on the repository. We appreciate your feedback and involvement in improving the package. Happy trading!

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

pwb_toolbox-0.1.21.tar.gz (49.5 kB view details)

Uploaded Source

Built Distribution

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

pwb_toolbox-0.1.21-py3-none-any.whl (53.8 kB view details)

Uploaded Python 3

File details

Details for the file pwb_toolbox-0.1.21.tar.gz.

File metadata

  • Download URL: pwb_toolbox-0.1.21.tar.gz
  • Upload date:
  • Size: 49.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pwb_toolbox-0.1.21.tar.gz
Algorithm Hash digest
SHA256 1847a2e0035d51d1ea7dd09971ce1c5fc5566a19a2044501d406a87cf4956bc9
MD5 27e819bf97fefced2961146262eb168e
BLAKE2b-256 08d7c16469783c1894b24ed78f3005d26ce0af171a15d0ef01c3b93e7e9238cc

See more details on using hashes here.

File details

Details for the file pwb_toolbox-0.1.21-py3-none-any.whl.

File metadata

  • Download URL: pwb_toolbox-0.1.21-py3-none-any.whl
  • Upload date:
  • Size: 53.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pwb_toolbox-0.1.21-py3-none-any.whl
Algorithm Hash digest
SHA256 1f1d6a634567c72b75d5f22a894fdc4b94689478940c8b286ef8a431bdde96ae
MD5 563efdd70771f36f0f7a67988fa17dec
BLAKE2b-256 fda4c66c404efe134fbdc57d96c645092e27da2c0b067839c903c74534ca47d3

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