Appearance

Personalize your experience

Mode
Accent Color
Direction
Backtesting in Python and C++

Backtesting in Python and C++

Backtesting

The quatick Python package and the header-only C++ library let you import indicators, backtest on your own machine and send the same file to Quatick. Locally and on the server, the fills, costs and statistics come from the same model, so the numbers agree.

Python: install and import

install
pip install ./packages/quatick-backtest-python          # from the Quatick repository
pip install "./packages/quatick-backtest-python[pandas]"  # with numpy + pandas helpers
research.py
from quatick import Bars, ta, backtest, trade_monte_carlo

def strategy(bars, params):
    fast, slow = ta.ema(bars.close, params["fast"]), ta.ema(bars.close, params["slow"])
    return [0 if ta.is_na(s) else (1 if f > s else -1) for f, s in zip(fast, slow)]

bars = Bars.read_csv("btc_1h.csv", interval="1h")          # or Bars.from_dataframe(df)
result = backtest(strategy, bars, params={"fast": 12, "slow": 26}, capital=100_000,
                  costs=0.02, slippage_bps=1)                # percent per side, bps
print(result.summary())                                     # return, sharpe, maxDD, trades, win, PF
mc = trade_monte_carlo([t.pnl for t in result.trades], 100_000, paths=5000)
print(mc["probLossPct"], mc["maxDrawdownPct"]["p05"])
  • Bars is (bars.close is a array when numpy is installed) and also a list of row dicts (bars[i]["close"]), so both styles of work.
  • quatick.ta: sma, , rma, wma, , highest, lowest, change, roc, , rsi, tr, atr, macd, bbands, vwap, crossover, crossunder. Every uses only past .
  • The file you research with is the file you upload. On Quatick, from quatick import ta works inside your .

Python: run on Quatick from your script

remote.py
import os
from quatick import Client

qt = Client(token=os.environ["QUATICK_TOKEN"])   # QUATICK_API_URL overrides the server
data = qt.market("NSE", "INFY", "1d", "2022-01-01", "2025-12-31")
r = qt.run_file("strategies/ema_cross/", data=data, params={"fast": 12})   # a folder = a project
print(r["stats"]["sharpe"], r["stats"]["trades"])
mc = qt.monte_carlo_file("strategies/ema_cross/", data=data, trades={"paths": 10000})
command line
quatick-backtest strategy.py --csv btc_1h.csv --interval 1h --param fast=10 --monte-carlo 5000
quatick-backtest strategy.py --remote --exchange BINANCE --symbol BTCUSDT --interval 1h --from 2025-01-01 --to 2025-06-30

C++: include and build

The is header-only C++20: add packages/quatick-backtest-cpp/include to the include (or link the target quatick::backtest) and include one header.

ema_cross.cpp
#include <quatick/quatick.hpp>

std::vector<double> strategy(const quatick::Bars& b, const quatick::Params& p) {
  auto fast = quatick::ema(b.close, p.geti("fast", 12)), slow = quatick::ema(b.close, p.geti("slow", 26));
  std::vector<double> out(b.size(), 0);
  for (size_t i = 0; i < b.size(); ++i)
    if (!quatick::is_na(slow[i])) out[i] = fast[i] > slow[i] ? 1 : -1;
  return out;
}

int main() {                                 // local research only: leave main out when uploading
  quatick::Execution ex; ex.costs_pct = 0.02;
  auto r = quatick::backtest(strategy, quatick::read_csv("bars.csv", "1h"), {}, ex);
  std::printf("sharpe %.2f, %zu trades\n", r.stats.sharpe, r.stats.trades);
}
ℹ
Note:Upload the file without main and the server adds its own: it reads the bars, passes your parameters and collects the positions. A file that keeps its own main runs as a program and must write its result (QUATICK_OUTPUT_JSON) itself.

Why local and server results agree

PartShared definition
next bar open (default) or signal , delay in bars, lot rounding, volume cap
Costs and slippagethe same cost models and slippage formulas
first in, first out from the ; open positions are marked at the last close
, , Calmar, , and the rest, annualized by bars per year for the (crypto 24/7, India 375 minutes, US 390)
Indicatorsidentical formulas in Python, C++ and (SMA-seeded , and )

The engine’s tests run the same through the Python package, the C++ and the server and require equal trade counts, final equity and .

See also

Related articles

  • C++ SDK Reference

    Backtesting / SDKs / C++

    Header-only C++20 (packages/quatick-backtest-cpp): the position simulator, an event-driven engine with the same order rules as Python, analytics, a parallel…

  • The Backtest Engine

    Backtesting / Engine

    One service backtests every kind of strategy on Quatick. Each source type runs on the engine built for it, and every result is measured with the same…

  • Engines — Python vs C++

    Automation / Predefined Strategies

    Two independent implementations of the same grid semantics, consuming the same config and the same command channel. The choice is a runtime choice, not a…

  • Python: Event-Driven Strategies

    Backtesting / SDKs / Python

    Subclass quatick.Strategy to trade bar by bar with real orders: brackets, trailing stops, limits, risk-based sizing and a drawdown kill switch. The same…

  • Python: Research Toolkit

    Backtesting / SDKs / Python

    Everything after the first backtest: tearsheet analytics, multi-asset portfolios, position sizing, optimization and walk-forward, overfitting tests, Monte…

  • Orders and Fills

    Backtesting / SDKs / Orders and Fills

    The event-driven engines of the Python and C++ SDKs share one set of order types and fill rules, so the same strategy fills identically in both languages…

  • Python Scripting with Pyodide

    Coding / IDE / Python

    Quatick strategies run in Python 3.11 via Pyodide — a full CPython compiled to WebAssembly. This means your strategies execute entirely in the browser, with…

  • QuaScript C++ Engine & Quant DSL

    Coding / QuaScript

    Sub-microsecond quantitative algorithmic scripting engine powered by C++20 bytecode VM, SIMD AVX2 acceleration, cache-aligned columnar memory, and direct…

  • Quatick Script SDK Reference

    Coding / IDE / Reference

    The Quatick IDE injects the SDK directly into TypeScript indicator, overlay, and strategy scripts at Apply time. You do not import SDK functions. Use the…

Browse all knowledge base articles →