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.