A workspace for systematic trading
Bring your strategy.
Build the evidence.
Develop trading ideas. Test how they behave.
One workspace for you and your AI.
MARKET DATA
Data from 20 exchanges and 3 DEXs
Spot and futures, linear and inverse contracts — test strategies on historical market data.
Available markets and history depend on the exchange and instrument. Historical-data support does not imply live-trading integration.
01 / Bring your strategy
Start with what
you already have.
Bring a file, folder or Git repository. Work through platform differences with AI-assisted conversion—or start in the editor.C# core · experimental language bridges. Compilation alone does not prove trading equivalence.
Range Breakout reference · separate local model. The main Multi-Regime strategy is in the window above.
Select a file in Explorer. Review the rules, change a parameter, or inspect a proposed conversion before applying it.
02 / Understand the result
A backtest is
the beginning.
Look beyond a headline return. Inspect trades, equity and drawdown. Explore how risk sizing changes a strategy before your next experiment.Below: Range Breakout on generated candles. Real browser calculations; no historical market data or XTester execution.
Range Breakout reference · separate local model. The main Multi-Regime strategy is in the window above.
Run the synthetic example from the toolbar. Switch equity to drawdown, inspect a trade, or change the risk budget and rerun.
03 / Work with your AI
A workspace.
Not just a chat box.
Connect Claude Code, Codex or another MCP client to your open Studio project. Keep edits, research and decisions in view.Studio MCP requires the app to be running. Sensitive actions retain consent. This page demonstrates the interaction locally; it connects to no agent.
Range Breakout reference · separate local model. The main Multi-Regime strategy is in the window above.
Choose a prompt inside the chat, inspect attached context, or configure a client in the workspace settings.
MCP / Claude Code · Codex · Claude Desktop · Cursor
Connect AI agents / MCP
Choose a client: an expected path after installation is pre-filled. Check the installation folder and edit the path if needed before connecting.
Your next experiment
One workspace.
A better-understood strategy.
Current version: 1.0.0-alpha.4 · Windows · macOS · Linux
Strategy templates and examples
10 languages · C# core · experimental bridges · Pine subset. Reference files, not ten browser runtimes.
main.cs
Core runtimeDownloadOriginal Studio lifecycle skeleton; add trading decisions in the bar callback. No orders in this starter. Source
public class UserStrategy : IStrategy
{
// Services available to the strategy: orders, indicators, parameters,
// market data, and logging.
private IApi _api = null!;
private IIndicators _indicators = null!;
private IStrategyParams _params = null!;
private IMarketData _marketData = null!;
private ILogger _logger = null!;
public void OnInit(StrategyContext context)
{
_api = context.Api;
_indicators = context.Indicators;
_params = context.Parameters;
_marketData = context.MarketData;
_logger = context.Logger;
_logger.Info("UserStrategy initialized.");
}
public void OnTick(decimal? price = null)
{
}
// Called for every closed bar in every subscription.
// symbolKey identifies the exchange, market, pair, and timeframe.
public void OnBar(ISymbolKey symbolKey, IKline kline)
{
}
// Called exactly once when a Tester, Paper, or Live run finishes.
public void OnFinish(StrategyFinishContext context)
{
}
}main.py
Experimental SDK bridgeDownloadOriginal Studio lifecycle skeleton; add trading decisions in the bar callback. No orders in this starter. Source
# Add your decisions in on_bar. self.context.api places orders (buy, sell, place_order,
# close_position); self.context.indicators reads the engine's indicators (rsi, sma, ema,
# macd, call("ADX", period=14)); self.context.logger writes to the strategy log.
from xtester import Strategy, OrderSide, OrderType
class UserStrategy(Strategy):
# symbol_key: exchange, market, symbol, timeframe of the closed bar.
# bar: open_time, close_time, open, high, low, close, volume as Decimal.
def on_init(self, context):
context.logger.info("UserStrategy initialized.")
def on_tick(self, price):
pass
def on_bar(self, symbol_key, bar):
pass
def on_finish(self, context):
pass
def create_strategy():
return UserStrategy()main.mjs
Experimental SDK bridgeDownloadEducational Tester example: one market buy on a bullish candle, one close request on a later bearish candle. One symbol, initially flat; acceptance is not a fill. Not for live trading. Source
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5: the XTester engine runs this strategy over the project's candles and
// executes orders, fees and balances itself; this file only decides.
// 3. Add your decisions in onBar. this.context.api places orders (buy, sell, placeOrder,
// closePosition); this.context.indicators reads the engine's indicators (rsi, sma, ema,
// macd, call('ADX', { period: 14 })); this.context.logger writes to the strategy log.
// Ask the AI assistant to explain this file.
import { Strategy, OrderSide, OrderType } from 'xtester';
export class UserStrategy extends Strategy {
phase = 0;
// symbolKey: exchange, market, symbol, timeframe of the closed bar.
// bar: openTime, closeTime, open, high, low, close, volume as numbers (bar.text.* keeps the exact decimals).
onInit(context) {
context.logger.info('UserStrategy initialized.');
}
onTick(price) {
}
onBar(symbolKey, bar) {
if (this.phase === 0 && bar.close > bar.open) {
const result = this.context.api.buy('0.01');
this.phase = result.success ? 1 : 2;
if (!result.success) this.context.logger.info(result.errorMessage);
} else if (this.phase === 1 && bar.close < bar.open) {
const result = this.context.api.closePosition();
this.phase = 2;
if (!result.success) this.context.logger.info(result.errorMessage);
}
}
onFinish(context) {
}
}
export function createStrategy() {
return new UserStrategy();
}
main.ts
Experimental SDK bridgeDownloadOriginal Studio lifecycle skeleton; add trading decisions in the bar callback. No orders in this starter. Source
// The XTester engine type-checks this strategy, runs it over the project's candles
// and executes orders, fees and balances itself; this file only decides.
import { Strategy, OrderSide, OrderType, type Bar, type Context, type SymbolKey } from 'xtester';
export class UserStrategy extends Strategy {
// symbolKey: exchange, market, symbol, timeframe of the closed bar.
// bar: openTime, closeTime, open, high, low, close, volume as numbers.
onInit(context: Context): void {
context.logger.info('UserStrategy initialized.');
}
onTick(price: number | undefined): void {
}
onBar(symbolKey: SymbolKey, bar: Bar): void {
}
onFinish(context: Context): void {
}
}
export function createStrategy(): UserStrategy {
return new UserStrategy();
}main.java
Experimental SDK bridgeDownloadEducational Tester example: one market buy on a bullish candle, one close request on a later bearish candle. One symbol, initially flat; acceptance is not a fill. Not for live trading. Source
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5: the XTester engine runs this strategy over the project's candles and
// executes orders, fees and balances itself; this file only decides. A JDK is needed:
// Studio offers the Java language pack when none is installed.
// 3. Add your decisions in onBar. context.api() places orders (buy, sell, placeOrder,
// closePosition); context.indicators() reads the engine's indicators (rsi, sma, ema,
// macd, call("ADX", "period", 14)); context.logger() writes to the strategy log.
// Ask the AI assistant to explain this file.
import xtester.Bar;
import xtester.Context;
import xtester.Strategy;
import xtester.SymbolKey;
import java.math.BigDecimal;
class UserStrategy extends Strategy {
private int phase = 0;
@Override
public void onInit(Context context) {
context.logger().info("UserStrategy initialized: " + context.parameters().symbolKey());
}
@Override
public void onTick(BigDecimal price) {
}
@Override
public void onBar(SymbolKey symbolKey, Bar bar) {
if (phase == 0 && bar.close().compareTo(bar.open()) > 0) {
var result = context.api().buy("0.01");
phase = result.success() ? 1 : 2;
if (!result.success()) context.logger().info(result.errorMessage());
} else if (phase == 1 && bar.close().compareTo(bar.open()) < 0) {
var result = context.api().closePosition();
phase = 2;
if (!result.success()) context.logger().info(result.errorMessage());
}
}
@Override
public void onFinish(Context context) {
}
}
main.cpp
Experimental SDK bridgeDownloadEducational Tester example: one market buy on a bullish candle, one close request on a later bearish candle. One symbol, initially flat; acceptance is not a fill. Not for live trading. Source
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5 inside a project: the XTester engine compiles every .cpp of this folder with the
// header-only xtester.hpp and runs it over the project's candles, executing orders, fees and
// balances itself; this file only decides. A C++ compiler is needed (Xcode CLT, clang/g++).
// 3. Add your decisions in onBar. ctx.api places orders (buy, sell, placeOrder, closePosition);
// ctx.indicators reads the engine's indicators (rsi, sma, ema, call("ADX", ...)); ctx.logger
// writes to the strategy log. XTESTER_STRATEGY defines main: never write main yourself.
// Ask the AI assistant to explain this file.
#include "xtester.hpp"
class UserStrategy : public xtester::Strategy {
int phase = 0;
void onInit(xtester::Context& ctx) override {
ctx.logger.info("UserStrategy initialized: " + ctx.parameters.symbolKey.str());
}
void onTick(xtester::Context& ctx, std::optional<double> price) override {
}
void onBar(xtester::Context& ctx, const xtester::SymbolKey& symbolKey, const xtester::Bar& bar) override {
if (phase == 0 && bar.close > bar.open) {
auto result = ctx.api.buy("0.01");
phase = result.success ? 1 : 2;
if (!result.success) ctx.logger.info(result.errorMessage);
} else if (phase == 1 && bar.close < bar.open) {
auto result = ctx.api.closePosition();
phase = 2;
if (!result.success) ctx.logger.info(result.errorMessage);
}
}
void onFinish(xtester::Context& ctx) override {
}
};
XTESTER_STRATEGY(UserStrategy)
main.rs
Experimental SDK bridgeDownloadEducational Tester example: one market buy on a bullish candle, one close request on a later bearish candle. One symbol, initially flat; acceptance is not a fill. Not for live trading. Source
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5 inside a project: the XTester engine builds this folder as a crate around the
// xtester SDK and runs it over the project's candles, executing orders, fees and balances
// itself; this file only decides. A Rust toolchain is needed: Studio offers the Rust language pack.
// 3. Add your decisions in on_bar. ctx.api places orders (buy, sell, place_order, close_position);
// ctx.indicators reads the engine's indicators (rsi, sma, ema, call("ADX", ...)); ctx.logger
// writes to the strategy log (println! breaks the protocol). The engine generates main.
// Ask the AI assistant to explain this file.
use xtester::*;
#[derive(Default)]
struct UserStrategy { phase: u8 }
impl Strategy for UserStrategy {
fn on_init(&mut self, ctx: &Context) {
ctx.logger.info(format!("UserStrategy initialized: {}", ctx.parameters.symbol_key));
}
fn on_tick(&mut self, ctx: &Context, price: Option<f64>) {
}
fn on_bar(&mut self, ctx: &Context, symbol_key: &SymbolKey, bar: &Bar) {
if self.phase == 0 && bar.close > bar.open {
let result = ctx.api.buy("0.01");
self.phase = if result.success { 1 } else { 2 };
if !result.success { ctx.logger.info(result.error_message); }
} else if self.phase == 1 && bar.close < bar.open {
let result = ctx.api.close_position(None, None);
self.phase = 2;
if !result.success { ctx.logger.info(result.error_message); }
}
}
fn on_finish(&mut self, ctx: &Context) {
}
}
pub fn create_strategy() -> Box<dyn Strategy> {
Box::new(UserStrategy::default())
}
main.go
Experimental SDK bridgeDownloadEducational Tester example: one market buy on a bullish candle, one close request on a later bearish candle. One symbol, initially flat; acceptance is not a fill. Not for live trading. Source
// EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
// First bullish candle: attempt a 0.01 market buy. First later bearish candle:
// attempt to close the whole position. At most one entry and one exit request.
// Acceptance is not a fill; errors stop the example. No retries, restart recovery,
// position reconciliation or risk controls. Choose valid size/funds in Studio.
// GETTING STARTED
// 1. Open Data and download candles for an exchange, market, and symbol.
// 2. Press F5 inside a project: the XTester engine builds this folder (package main) with the
// xtester SDK and runs it over the project's candles, executing orders, fees and balances
// itself; this file only decides. A Go toolchain is needed: Studio offers the Go language pack.
// 3. Add your decisions in OnBar. ctx.Api places orders (Buy, Sell, PlaceOrder, ClosePosition);
// ctx.Indicators reads the engine's indicators (RSI, SMA, EMA, Call("ADX", ...)); ctx.Logger
// writes to the strategy log. Do not write func main: the engine generates it.
// Ask the AI assistant to explain this file.
package main
import (
"fmt"
"xtester"
)
type UserStrategy struct {
xtester.Base
phase int
}
func init() { xtester.Register(func() xtester.Strategy { return &UserStrategy{} }) }
func (s *UserStrategy) OnInit(ctx *xtester.Context) {
ctx.Logger.Info(fmt.Sprintf("UserStrategy initialized: %s", ctx.Parameters.SymbolKey))
}
func (s *UserStrategy) OnTick(ctx *xtester.Context, price *float64) {
}
func (s *UserStrategy) OnBar(ctx *xtester.Context, symbolKey xtester.SymbolKey, bar xtester.Bar) {
if s.phase == 0 && bar.Close > bar.Open {
result := ctx.Api.Buy("0.01")
if result.Success { s.phase = 1 } else { s.phase = 2; ctx.Logger.Info(result.ErrorMessage) }
} else if s.phase == 1 && bar.Close < bar.Open {
result := ctx.Api.ClosePosition(nil, "")
s.phase = 2
if !result.Success { ctx.Logger.Info(result.ErrorMessage) }
}
}
func (s *UserStrategy) OnFinish(ctx *xtester.Context) {
}
main.r
Experimental SDK bridgeDownloadEducational Tester example: one market buy on a bullish candle, one close request on a later bearish candle. One symbol, initially flat; acceptance is not a fill. Not for live trading. Source
# EDUCATIONAL TESTER EXAMPLE — one symbol, initially flat; not for live trading.
# First bullish candle: attempt a 0.01 market buy. First later bearish candle:
# attempt to close the whole position. At most one entry and one exit request.
# Acceptance is not a fill; errors stop the example. No retries, restart recovery,
# position reconciliation or risk controls. Choose valid size/funds in Studio.
# GETTING STARTED
# 1. Open Data and download candles for an exchange, market, and symbol.
# 2. Press F5 inside a project: the XTester engine runs this file with Rscript over the
# project's candles, executing orders, fees and balances itself; this file only decides.
# R must be installed (https://cloud.r-project.org); the R pack adds jsonlite and the language server.
# 3. Add your decisions in on_bar. context$api places orders (buy, sell, place_order,
# close_position); context$indicators reads the engine's indicators (rsi, sma, ema,
# call("ADX", list(period = 14))); context$logger writes to the strategy log.
# Ask the AI assistant to explain this file.
create_strategy <- function() {
state <- new.env()
state$phase <- 0L
list(
on_init = function(context) {
context$logger$info(paste("UserStrategy initialized:", xtester_symbol_text(context$parameters$symbol_key)))
},
on_tick = function(context, price) {
},
on_bar = function(context, symbol_key, bar) {
if (state$phase == 0L && bar$close > bar$open) {
result <- context$api$buy("0.01")
state$phase <- if (result$success) 1L else 2L
if (!result$success) context$logger$info(result$error_message)
} else if (state$phase == 1L && bar$close < bar$open) {
result <- context$api$close_position()
state$phase <- 2L
if (!result$success) context$logger$info(result$error_message)
}
},
on_finish = function(context) {
}
)
}
main.pine
Pine subset interpreterDownloadOriginal EMA crossover strategy for the Pine subset interpreter. Source
//@version=6
// XTester's own Pine interpreter runs this script once per closed bar and
// the engine executes strategy.entry / strategy.exit / strategy.close orders,
// fees and balances. Plots and drawings are accepted and ignored.
strategy("UserStrategy", overlay = true, default_qty_type = strategy.percent_of_equity, default_qty_value = 10)
fast = ta.ema(close, input.int(9, "Fast EMA"))
slow = ta.ema(close, input.int(21, "Slow EMA"))
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("Long")
plot(fast, "Fast", color.new(color.blue, 0))
plot(slow, "Slow", color.new(color.orange, 0))The wider ecosystem
Research here. Explore publishing separately.
CopyTrader is a separate product path. Publishing availability and commercial terms need confirmation—not a promise that this demo can trade or monetize strategies.
About the separate product path ↗Questions & answers
Do I need to know how to code?
Not necessarily. Describe the idea in words: the spec wizard helps you pin down the rules and the AI assistant helps write and fix the code. AI features need a connected provider — your own key or a local model. If you write code yourself, the editor has templates, hints and diagnostics.
What language are strategies written in?
In C#, Python, JavaScript, TypeScript, Pine Script, Java, C++, Rust, Go or R. C# is the primary language, with the most complete support for development, execution and AI Lab. The other languages have run and backtest adapters. APIs, libraries and results can differ between languages.
Can I bring over an existing strategy?
Yes. The conversion wizard takes a file, a folder, an archive, text, an HTTPS link or a GitHub repository, analyses the logic, asks about incompatible features, generates a project, fixes compile errors and reports what was ported directly, what was changed and what was not ported. The port is created as a new project; the wizard needs an AI model. Always verify the result: comparing against a reference trade list checks the time and direction of entries and exits, but does not prove identical trading results.
How compatible is Pine Script with TradingView?
XTester runs Pine Script v5/v6 with its own interpreter — it is not the TradingView engine. Supported: ta.*, math.*, str.*, array.*, map.*, input.* and strategy.entry / order / exit / close / cancel orders. Plots, drawings and alerts are accepted but ignored; library imports, matrix.*, enum and some request.* functions are not supported. Fills, fees and slippage are computed by the XTester engine, so results can differ from TradingView.
What else do I need to install for my language?
For C#, JavaScript, TypeScript and Pine Script — nothing: the C# compiler is built into Studio and the others run on the Node.js that ships with Studio. For Python, Java, Go and Rust, Studio offers to download a language pack; for Python your own interpreter works too. C++ needs your system's compiler (Xcode Command Line Tools, clang/g++ or MinGW-w64) — Studio downloads the language server itself. R needs R installed; the language pack adds jsonlite and the language server.
How is a backtest different from a robustness check?
A backtest runs the strategy over a chosen period and conditions. A robustness check is a separate step after it: the saved result becomes the baseline, and the strategy is rerun with changed fees and slippage and on individual market phases. The outcome is saved to a report together with the limits of the check. Phase episodes come from the same history, so this is not an independent test on new data, and the evaluation criteria are adjustable guides, not a guarantee.
Can I connect an external AI agent?
Yes, over MCP: a compatible client works with the project, data, tests and results. Every external connection is confirmed in the Studio window, access can be read-only, and only one session at a time can make changes. More about MCP
What works locally and what needs the network?
The editor, projects, downloaded history, simulation, backtests and reports work locally, with no account sign-in or exchange keys. The network is needed to download history and instrument lists from exchanges, for AI features with a cloud provider, to fetch language packs and updates, and to work with GitHub. Keeping the project on your disk does not make every network feature work offline; you can skip the cloud for AI by connecting a local model.
Which exchanges are supported?
20 centralized ones: Binance, Bybit, OKX, Bitget, KuCoin, MEXC, Gate.io, BingX, HTX, CoinEx, Kraken, Coinbase, Bitfinex, Crypto.com, Deepcoin, XT, BloFin, Bitstamp, CoinW, WEEX — and 3 perpetual DEXs: HyperLiquid, dYdX, Aster. Spot and futures, linear and inverse contracts.
Can I trade live from XTester?
Yes, through XTester Launcher — an app for running strategies over long periods that ships with Studio. A finished strategy is launched from Studio into Launcher: one strategy, one window. Modes are Paper (trading on a virtual account) and Live (through the API keys of your exchange account); before a Live start Launcher runs a chain of checks. The window shows positions, orders and trades, sends notifications including Telegram, and warns you if anyone interferes with the robot's trading. Trading decisions and risks remain yours.
Where is my data stored?
On your disk. Telemetry is optional and enabled only with your consent. AI features use your own key for the provider you choose, or a local model; data sent to an AI provider is processed under its rules.
How much does it cost?
XTester Studio is free, with no feature limits. External AI providers work under their own terms and pricing: requests made with your key are billed by the provider. You can also connect a local model.
What are the requirements?
Windows, macOS or Linux (64-bit). Size, signature, package contents and requirements for each platform are listed on the download page from the release's real files. Some languages need a language pack or a toolchain — see the question above.
Latest articles
Loading articles…