Client SDK for the tau hosted backtester. Write a market-making rule in Python, submit it, and get results back — no C++ required.
pip install git+https://github.com/TRB-Capital-Management/tau-client.gitRequires Python 3.10+. No third-party dependencies.
Create a file my_strategy.py:
from tau_research import Analyzer
class MyStrategy(Analyzer):
symbols = ["AAPL"] # symbols to trade
shares = 100 # shares quoted per symbol
def fair_value(self, ctx):
# Where do you think the stock should trade?
# Return a price in dollars. ctx.mid is the current midpoint.
return ctx.mid
def cushion(self, ctx):
# How wide should your quotes be?
# Return a half-width in dollars: buys at fair_value - cushion,
# sells at fair_value + cushion.
return max(0.01, 2.0 * ctx.realized_vol(window_s=30.0))Submit it:
from tau_research import submit, list_datasets
BASE_URL = "https://research.example.com" # provided by Taylor
API_KEY = "sk-..." # provided by Taylor
# See what datasets are available
print(list_datasets(BASE_URL, API_KEY))
# Run your strategy
result = submit(
"my_strategy.py",
dataset = "equities_2026_q2",
config = "strat.cfg",
base_url = BASE_URL,
api_key = API_KEY,
)
print(f"Files run: {result['num_files']}")
print(f"Total PnL: {result['total_final_pnl']:.2f}")
for f in result["per_file"]:
print(f["file"], f["summary"])| Method | Returns | Meaning |
|---|---|---|
fair_value(ctx) |
float (dollars) |
Your estimate of where the stock should trade |
cushion(ctx) |
float or list[float] (dollars) |
Half-width of your quotes |
The engine places a limit buy at fair_value − cushion and a limit sell at
fair_value + cushion, snapped to whole pennies. Return a list from cushion
to post a ladder of quotes at increasing distances.
| Field / call | Type | Description |
|---|---|---|
ctx.mid |
float | Current midpoint (bid + ask) / 2 |
ctx.bid |
float | Best bid |
ctx.ask |
float | Best ask |
ctx.spread |
float | ask − bid |
ctx.bid_size |
float | Best bid size |
ctx.ask_size |
float | Best ask size |
ctx.last |
float | Last trade price |
ctx.position |
float | Signed shares held (+long / −short) |
ctx.avg_entry |
float | Average entry price (0 when flat) |
ctx.param("name") |
float | A named knob from the config file |
ctx.realized_vol(window_s) |
float | RMS of returns over a trailing window (dollars) |
ctx.roll_mean(x, n) |
float | Rolling mean of the last n samples of x |
ctx.roll_min(x, n) |
float | Rolling min of the last n samples of x |
ctx.roll_max(x, n) |
float | Rolling max of the last n samples of x |
A plain-text key=value file with required strategy parameters and any named
knobs your rule references via ctx.param("name"):
drawdown_limit = 500
max_daily_profit = 500
start_hour = 9
start_min = 30
end_hour = 16
end_min = 0
half_spread_dollars = 0.03 # referenced as ctx.param("half_spread_dollars")
Set symbols to more than one ticker and the same fair_value/cushion logic
runs independently per symbol on each tick:
class MultiSymbol(Analyzer):
symbols = ["AAPL", "MSFT", "GOOG"]
shares = 50
def fair_value(self, ctx): return ctx.mid
def cushion(self, ctx): return ctx.param("half_spread_dollars")Return a list from cushion to place multiple quote levels:
def cushion(self, ctx):
base = ctx.param("half_spread_dollars")
return [base, 2.0 * base, 3.0 * base] # three levels per sidefair_value and cushion support: numeric literals, arithmetic (+ - * / **),
comparisons, boolean ops (and/or/not), if/elif/else, local variable
assignments, min/max/abs, and any ctx field or primitive listed above.
Not supported: loops, imports, arbitrary function calls, data structures, or cross-tick mutable state. If you need a signal that isn't in the table above, ask Taylor to add it.
submit(
analyzer, # Analyzer subclass, path to a .py file, or source string
dataset = "...", # dataset name (from list_datasets())
config = "...", # path to your config file, or its contents as a string
base_url = "...",
api_key = "...",
broker_latency_ms = 150, # simulated order latency (ms)
market_data_latency_ms = 150, # simulated data feed latency (ms)
jobs = 4, # parallel backtest workers (capped by your quota)
timeout = 900.0, # HTTP timeout in seconds
)Returns a dict:
{
"dataset": "equities_2026_q2",
"num_files": 42,
"total_final_pnl": 1234.56,
"per_file": [
{"file": "20260101.txt", "summary": {
"num_fills": 312,
"num_orders": 1800,
"num_closed_trades": 156,
"net_pnl_sum": 29.14,
"final_pnl": 29.14,
...
}},
...
]
}