Skip to content

Comparison

A backtesting.py alternative for crypto traders

backtesting.py is an excellent lightweight Python library if you already live in notebooks and like wiring data yourself. Torquant is for when you have the strategy idea and want the backtest, not the setup.

What Torquant actually backtests

Torquant supports directional crypto strategies: long, short, and leverage when you ask for them. Historical prices come from spot market candles (e.g. BTCUSDT, ETHUSDT). That is enough to test most trend, momentum, and mean-reversion ideas on crypto pairs.

It is not a full perpetuals simulator. Funding rates, liquidation engines, and other perp-specific mechanics are not modeled. If your edge depends on those, you need a different stack.

What backtesting.py is good at

backtesting.py (by kernc) is a popular open-source library for running vectorized backtests in Python. You subclass Strategy, implement init() and next(), feed it a pandas DataFrame of OHLCV bars, and call Backtest.run(). It is fast, hackable, and ideal when you already have a Python environment and clean historical data on disk.

The friction for many crypto traders is everything around the library: installing Python, fetching exchange candles, normalizing timestamps, handling missing bars, and turning a trading idea into boilerplate before you see an equity curve.

Typical workflow

Same goal: see whether an SMA crossover on ETH would have worked. Two very different paths to get there.

With backtesting.py

  1. Install Python, pip, and the library (pip install backtesting).
  2. Download or fetch OHLCV for your crypto pair and timeframe.
  3. Clean the DataFrame: datetime index, column names, gaps, time zones.
  4. Write a Strategy class with indicators and entry/exit logic.
  5. Run the backtest, then plot or export stats yourself.

With Torquant

  1. Open the web app. No install.
  2. Describe the strategy in plain English or use the guided builder.
  3. Run the backtest on built-in crypto pair data.
  4. Review equity curve, drawdown, and buy-and-hold comparison.
  5. Refine the idea and re-run in minutes.

From prompt to code

A crossover fits in a short code sample. Add a few more rules to the prompt and the script grows quickly.

ETH 4-hour SMA crossover

Torquant prompt

“ETH 4h: long when SMA 8 crosses above SMA 20. Exit on cross below.”

backtesting.py code

class SmaCross(Strategy):
    n1, n2 = 8, 20

    def init(self):
        close = self.data.Close
        self.sma1 = self.I(SMA, close, self.n1)
        self.sma2 = self.I(SMA, close, self.n2)

    def next(self):
        if crossover(self.sma1, self.sma2):
            self.buy()
        elif crossover(self.sma2, self.sma1):
            self.sell()

Somewhat more complex: daily ETH trend follow

A few extra lines in the prompt add momentum, a rising SMA, an RSI band, volume, ATR sizing, and a re-entry cooldown. In backtesting.py that becomes CSV prep, indicator helpers, state variables, sizing logic, and a script to run it all.

Torquant prompt

“Daily ETH trend follow. Long when 20d momentum is at least +5%, price above SMA 30 rising vs 5 bars ago, RSI(14) 40 to 65, volume at or above 20d avg. Exit on close below SMA 30 or negative 20d momentum. Size with ATR(14) for about 10% equity at risk. One position, 5 bar cooldown after exit.”

backtesting.py code

import numpy as np
import pandas as pd
from backtesting import Backtest, Strategy


def load_eth_daily_csv(path: str) -> pd.DataFrame:
    """You source OHLCV before Backtest(...) can run."""
    df = pd.read_csv(path)
    df.columns = [c.strip().title() for c in df.columns]
    rename = {"Timestamp": "Date", "Datetime": "Date", "Open_time": "Date"}
    df = df.rename(columns={k: v for k, v in rename.items() if k in df.columns})
    df["Date"] = pd.to_datetime(df["Date"], utc=True)
    df = df.set_index("Date").sort_index()
    df = df[["Open", "High", "Low", "Close", "Volume"]].astype(float)
    return df[~df.index.duplicated(keep="first")].dropna()


def sma(values, period):
    return pd.Series(values).rolling(period).mean()


def rsi(values, period=14):
    delta = pd.Series(values).diff()
    gain = delta.clip(lower=0).rolling(period).mean()
    loss = (-delta.clip(upper=0)).rolling(period).mean()
    rs = gain / loss.replace(0, np.nan)
    return 100 - (100 / (1 + rs))


def atr(high, low, close, period=14):
    h, l, c = map(pd.Series, (high, low, close))
    prev_c = c.shift(1)
    tr = pd.concat([
        h - l,
        (h - prev_c).abs(),
        (l - prev_c).abs(),
    ], axis=1).max(axis=1)
    return tr.rolling(period).mean()


def momentum_pct(close, period=20):
    s = pd.Series(close)
    return s / s.shift(period) - 1.0


class EthTrendVolSized(Strategy):
    mom_period = 20
    ma_period = 30
    atr_period = 14
    rsi_period = 14
    vol_ma_period = 20
    mom_entry = 0.05
    equity_risk = 0.10
    cooldown_bars = 5

    def init(self):
        c = self.data.Close
        h = self.data.High
        l = self.data.Low
        v = self.data.Volume
        self.ma30 = self.I(sma, c, self.ma_period)
        self.momentum = self.I(momentum_pct, c, self.mom_period)
        self.rsi = self.I(rsi, c, self.rsi_period)
        self.atr = self.I(atr, h, l, c, self.atr_period)
        self.vol_ma = self.I(sma, v, self.vol_ma_period)
        self.bars_since_exit = self.cooldown_bars

    def _ma_rising(self):
        if len(self.ma30) < 6:
            return False
        return self.ma30[-1] > self.ma30[-6]

    def _atr_position_size(self):
        atr_val = float(self.atr[-1])
        price = float(self.data.Close[-1])
        if not np.isfinite(atr_val) or atr_val <= 0 or price <= 0:
            return 0.0
        risk_cash = self.equity * self.equity_risk
        units = risk_cash / atr_val
        fraction = (units * price) / self.equity
        return min(max(fraction, 0.0), 0.99)

    def next(self):
        self.bars_since_exit += 1
        warmup = max(self.ma_period, self.mom_period, self.vol_ma_period) + 6
        if len(self.data) < warmup:
            return

        price = float(self.data.Close[-1])
        mom = float(self.momentum[-1])
        rsi_val = float(self.rsi[-1])
        ma = float(self.ma30[-1])
        vol_ok = float(self.data.Volume[-1]) >= float(self.vol_ma[-1])

        if self.position:
            if price < ma or mom < 0:
                self.position.close()
                self.bars_since_exit = 0
            return

        if self.bars_since_exit < self.cooldown_bars:
            return

        entry_ok = (
            mom >= self.mom_entry
            and price > ma
            and self._ma_rising()
            and 40 <= rsi_val <= 65
            and vol_ok
        )
        if not entry_ok:
            return

        size = self._atr_position_size()
        if size > 0:
            self.buy(size=size)


if __name__ == "__main__":
    data = load_eth_daily_csv("eth_usd_daily.csv")

    bt = Backtest(
        data,
        EthTrendVolSized,
        cash=100_000,
        commission=0.001,
        exclusive_orders=True,
        trade_on_close=True,
    )
    stats = bt.run()
    print(stats[["Return [%]", "Max. Drawdown [%]", "Sharpe Ratio", "# Trades"]])
    bt.plot(open_browser=False)

Strategies can get much more involved than this. Even this step up shows the pattern: a few sentences of prompting, and 130+ lines of Python to write and maintain.

At a glance

Feature Torquant backtesting.py
Language Plain English or guided UI Python required
Install and environment None. Browser-based. Python, pip, virtualenv, dependencies
Crypto price data Built in for USDT pairs You source and prepare CSV/API data
Long, short, leverage Yes, when you specify them Yes, in your Strategy code
Time to first backtest Minutes Often hours on first setup
Strategy flexibility Common entry/exit patterns, indicators, filters Arbitrary Python logic in next()
Open source and self-host Hosted product MIT license, run locally
Output Equity curve, drawdown, vs buy & hold Custom stats, plots via matplotlib / your code
Best for Crypto traders testing ideas without code Developers building Python backtest pipelines

When Torquant is the better fit

You are not trying to become a Python quant. You want to know if your RSI filter, Bollinger fade, or moving-average cross held up on BTC or ETH before you trade it.

  • You searched for a backtesting.py alternative because setup cost exceeds the value of a quick test.
  • You do not have clean OHLCV files ready and do not want to script an exchange download.
  • You think in trading rules (“buy below RSI 30”) rather than class methods and DataFrame indices.
  • You want to test many ideas this week, not maintain a research codebase.

When backtesting.py is the better fit

backtesting.py remains a strong choice when code is the product: you are iterating on execution logic, custom fills, portfolio-level rules, or wiring backtests into an automated pipeline.

  • You already work in Jupyter or VS Code and version-control strategy code.
  • You need non-standard order logic, custom indicators, or fine-grained control of each bar.
  • You are backtesting non-crypto assets with your own datasets.
  • You want a free, open-source library with no vendor dependency.

Common questions

Is Torquant a drop-in replacement for backtesting.py?

No. Torquant is not a Python library and does not run your existing scripts. It is a web app for describing crypto strategies in plain English and running backtests without a local environment. If you need arbitrary Python in every bar, backtesting.py is the better tool.

Can I backtest crypto with backtesting.py?

Yes. Many developers do. You typically export candles from an exchange or API into a pandas DataFrame with Open, High, Low, Close, and Volume columns, then pass it to Backtest. Torquant skips that data prep for supported crypto pairs.

Can I backtest a perp or leveraged strategy?

You can test long, short, and leveraged logic on crypto pair history in Torquant. Price data is spot market candles, not a dedicated perp feed. Funding, liquidation, and other perpetual-specific mechanics are not simulated.

Which is faster for a one-off idea?

For a trader with no Python setup, Torquant is usually faster: open the app, describe the rule, run. For a developer with data on disk and a configured environment, backtesting.py can be fast too. The difference is upfront setup, not simulation speed.

I know Python but I am tired of prep work. Does that make sense?

Yes. That is a common reason to use Torquant. You can return to backtesting.py when an idea graduates to a coded strategy or needs logic Torquant does not support.

Skip the Python setup

Describe your crypto strategy and run a backtest with built-in data. No pip install, no CSV merge, no Strategy class.