ThetaScript
A scripting language for chart studies, auto trading, custom tools, and trade-signal scripts. One Rust engine behind every runtime, WebAssembly in the browser, native on the server in Rust or through Python and Elixir bindings. Held together by a normative spec and a bit-exact conformance corpus.
npm install theta-script
study("Cross Strategy", overlay=true)
fast = ema(close, 9)
slow = ema(close, 21)
plot(fast, color="#22d3ee")
plot(slow, color="#f59e0b", width=2)
var entries = 0
if crossover(fast, slow)
entries := entries + 1
strategy.buy(crossover(fast, slow), 10, trailing=2)
strategy.sell(crossunder(fast, slow), 10)
alertcondition(crossover(fast, slow), message="cross up")
Learn
A seven-step walkthrough from your first plot to a backtested strategy.
Reference
Every builtin, statement, draw call, source and operator.
Examples
Complete scripts, every one runs against the current engine in CI.
Specification
The normative language definition, plus the conformance contract.
Why another chart language?
ThetaScript is an opensource language designed to run untrusted user scripts safely, identically,
everywhere: no recursion, no unbounded loops, no I/O, no aggregate data
structures beyond bounded arrays. Work per run is bounded by
bars × statements × loop-limit, and the per-bar execution model
evaluates incrementally, a live tick appends one bar of work, making it ideal for
streaming.
The same script produces bit-identical results in the browser (the Rust core compiled to WebAssembly), on the server (native Rust), and through the Python and Elixir bindings, one engine, compiled everywhere. (how conformance works).
Quick start
JavaScript
import { init, runScript } from 'theta-script';
await init(); // once, at app startup loads the wasm engine
const result = runScript(source, bars, { timezone: 'America/New_York' });
// result.plots / result.trades / result.strategy / result.error …
Rust
use theta_script::{bars_from_json, opts_from_json, run_script};
let result = run_script(source, &bars, opts);
Python
import json, theta_script
result = json.loads(theta_script.run_script_json(source, json.dumps(bars), None))
Elixir
{:ok, result} = Jason.decode(ThetaScript.run_json(source, bars_json))
Bars are { date, open, high, low, close, volume } with
date in milliseconds since the Unix epoch. All four runtimes
return the same result object.