Tasilab
Home Pricing Docs EN · عربي Sign in Start free →
Home / Guides / Backtest a TASI strategy

Backtest a TASI strategy in Python.

From a one-line API call to a fully logged experiment — on real Saudi Exchange bars, with real commission and VAT. Every fill is simulated; no real order is ever placed.

Backtesting is how you ask history what a strategy would have done, before you risk a single riyal. Most Python backtesting tutorials assume US stocks and a data feed you have to wire up yourself. This guide does it on the Saudi Exchange (Tadawul, index TASI) with Tasilab, so the commission, VAT, and price bars are the real Saudi-market ones — not a generic approximation.

We'll run the classic RSI mean-reversion strategy — buy when RSI drops below 30 (oversold), sell when it rises above 70 (overbought) — on Saudi Aramco (2222), two ways:

  • Method 1 — the hosted backtest. One HTTP call. Tasilab runs the strategy over cached historical bars and hands back the result, including a buy-and-hold comparison.
  • Method 2 — roll your own. Pull the bars, compute the signal yourself in Python, simulate the fills with real fees, and log the whole run as a tracked experiment.

Before you start

You need a free Tasilab account and an API key. Sign up — it takes a minute and comes with a paper portfolio of SAR 100,000 in simulated cash. Copy your API key from the dashboard, then install the SDK and export the key:

Terminal
pip install tasilab
export TASILAB_API_KEY="your-api-key"
The free tier includes 5 backtests per month and 15-minute-delayed data — plenty to work through this guide. Everything here is a simulation on historical data: no real order is placed, and past performance never predicts future results.

Method 1 — the hosted backtest (one call)

The fastest path is POST /v1/backtest/run. You describe the strategy as data — indicator, thresholds, symbol, window — and Tasilab does the rest. Here is the RSI mean-reversion run on Aramco over the last year (1Y ≈ 250 trading days):

curl
curl -X POST https://api.tasilab.com/v1/backtest/run \
  -H "X-API-Key: $TASILAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "symbol": "2222",
    "period": "1Y",
    "strategy_type": "threshold",
    "indicator": "RSI",
    "params": {"period": 14},
    "buy_op": "<",  "buy_threshold": 30,
    "sell_op": ">", "sell_threshold": 70
  }'

The same request from Python, reading the two numbers that actually matter:

Python
import os, requests

resp = requests.post(
    "https://api.tasilab.com/v1/backtest/run",
    headers={"X-API-Key": os.environ["TASILAB_API_KEY"]},
    json={
        "symbol": "2222",            # Saudi Aramco
        "period": "1Y",              # ~250 trading days
        "strategy_type": "threshold",
        "indicator": "RSI",
        "params": {"period": 14},
        "buy_op": "<",  "buy_threshold": 30,   # oversold -> buy
        "sell_op": ">", "sell_threshold": 70,  # overbought -> sell
    },
    timeout=60,
)
resp.raise_for_status()
r = resp.json()

print(f"Strategy  : {r['return_pct']:+.2f}%  ({r['num_trades']} trades)")
print(f"Buy & hold: {r['buy_hold_return_pct']:+.2f}%")
print(f"Final     : {r['final_value']} SAR  vs  {r['buy_hold_final_value']} SAR held")

The response is a full record of the run — not just a number. The fields you'll use most:

  • return_pct / return_sar — how the strategy did.
  • buy_hold_return_pct / buy_hold_final_value — how simply holding the stock over the same window did. This is the benchmark.
  • num_trades, num_bars — how active the strategy was, over how many days.
  • trades — every BUY/SELL leg with date, price, quantity, and value.
  • equity_curve — daily portfolio value, ready to plot.
  • run_id — a handle to the saved run.

Reading history's verdict

The single most useful line in that output is the comparison between return_pct and buy_hold_return_pct. A strategy is only interesting if it beats the boring alternative of buying the stock and doing nothing.

Here is the uncomfortable part, and the reason we show you both numbers by default: a clever-sounding rule often loses to buy-and-hold. Classic RSI mean-reversion on a strong trending name frequently sells its winners too early and underperforms. Tasilab reports that plainly — it does not sugar-coat history, and neither should your own analysis. An honest "this edge is weak" is worth more than a backtest tuned until it looks good.

If your strategy's return_pct comes in below buy-and-hold, that is a real result, not a failure of the tool. The discipline of comparing against the benchmark — every time — is most of what separates a tradeable edge from a story.

Method 2 — roll your own, and track it

The hosted backtest covers the common indicator strategies. When you want full control — custom signals, custom position sizing, your own metrics — pull the bars and run the loop yourself, then log the run as a Tasilab experiment so it is reproducible and comparable later. Here is the shape, using a simple moving-average crossover:

Python
import os
from decimal import Decimal
from tasilab import Tasilab

COMMISSION, VAT = Decimal("0.00155"), Decimal("0.15")   # real TASI fees

def fees(price, qty):
    commission = price * qty * COMMISSION
    return commission + commission * VAT

tasi = Tasilab(api_key=os.environ["TASILAB_API_KEY"])

# 1) real historical bars for Saudi Aramco
bars = tasi.get_historical("2222", "2024-01-01", "2025-12-31")["bars"]
closes = [float(b["close"]) for b in bars]

# 2) your own signal — a 10/30 SMA crossover here
def sma(v, p): return [None]*(p-1) + [sum(v[i-p+1:i+1])/p for i in range(p-1, len(v))]
fast, slow = sma(closes, 10), sma(closes, 30)

# 3) simulate fills with real fees, collect trades ... (loop omitted)

# 4) log the run as a tracked experiment
with tasi.create_experiment(
    name="SMA 10/30 on Saudi Aramco",
    symbol="2222", start_date="2024-01-01", end_date="2025-12-31",
    parameters={"fast": 10, "slow": 30, "starting_capital_sar": 100000},
) as exp:
    exp.log_trades(trades)
    exp.log_metrics({"total_return_pct": total_return_pct, "num_trades": len(trades)})

print("Logged experiment:", exp.id)

Every run you log shows up under Experiments in your dashboard with its parameters, metrics, trade list, and equity curve — so you can line up "SMA 10/30" against "RSI 30/70" against "MACD 12/26/9" on the same symbol and window, and let the numbers decide. That is the difference between running a backtest and building a track record.

Why doing it on TASI specifically matters

You could approximate all of this with a generic backtesting library and a free data source. What you would miss is exactly what determines whether an edge survives contact with the real Saudi market:

  • Real fees. Commission of 0.155% plus 15% VAT on the commission, applied to every fill — the same math the exchange uses. A high-frequency rule that looks profitable before fees often is not after them.
  • Real bars and tick rules. Actual TASI historical prices, not a proxy index.
  • Real trading hours. Sunday–Thursday, 10:00–15:00 AST — the calendar your live strategy would actually trade on.

Model the market you're going to trade, not a convenient stand-in for it.

Try it without writing a line

Prefer to click through the whole flow first? The interactive First Steps walkthrough runs a backtest, an API call, and a Python bot for you — in about ten minutes.

Start free →

Next: read the full API reference, or explore the other hosted strategies — ma_crossover, price_ma_cross, and macd_signal_cross — by swapping strategy_type in the request above.

Tasilab

An API-native paper-trading sandbox for the Saudi Exchange. Trade with discipline.

Product
  • Backtesting
  • Paper trading
  • Python SDK
  • Documentation
Guides
  • Backtest in Python
  • About Tasilab
  • Pricing
Legal
  • Terms of use
  • Privacy
  • Disclaimer

Tasilab is a simulation-only paper-trading environment. No real orders are placed on the Saudi Exchange. Tasilab is not licensed by the Capital Market Authority and does not provide investment advice. Backtest results use historical data and do not predict future performance.

© 2026 Tasilab