Describe a strategy in plain English. The built-in assistant writes it in FXScript, the engine replays it bar by bar over years of real market history, and the optimizer sweeps every input you declared to show which settings actually held up. You read the rules before anything runs — the model proposes, you approve.
Four steps, none of which ask you to leave the browser or trust a number you cannot inspect.
Type the strategy the way you would explain it to another trader. "Buy when the 20 EMA crosses above the 50, stop 20 pips, target 2R." The assistant returns a working FXScript with the entry, the stop, the target and the sizing already wired up.
The script lands in the editor, not in a black box. You see the exact rules that will execute — every condition, every level, every input — and can change any of them. The previous version is stashed before every write and one Undo restores it.
The engine walks your script across years of real market history one candle at a time, opening and closing positions exactly where the rules say. No indicator math is reimplemented for the backtest: ta.ema calls the same function the chart draws with, and profit and loss goes through the same routine as a manual trade.
Declare inputs with a min, a max and a step, tick the ones you want varied, and the optimizer runs the full grid and ranks the results. Only numeric and boolean inputs are offered — a string has no ordering, so there is no range to sweep.
A chat column next to an editor is the easy half, and everyone has seen that demo. The hard part is that a language model asked for code in a small, specific language will confidently write a function that does not exist. It has read an enormous amount of Pine Script and MQL5 and almost none of FXScript, so it pattern-matches — and a plausible but imaginary indicator costs you a run, an error, and a piece of your belief that the feature works at all.
Two engineering decisions fix that, and both are worth knowing about because they are what separate a usable assistant from a demo.
The language reference is generated from the engine, never written by hand. The assistant's system prompt carries a complete, exhaustive list of every builtin, with a closed-world instruction stating plainly that no others exist. That reference is produced from the same source of truth the editor's "copy for AI" button hands out, and a test asserts the two agree in both directions — nothing documented that the interpreter lacks, nothing the interpreter offers left undocumented. A hand-copied reference drifts the day someone adds an indicator, and a drifted reference is worse than none at all, because the model then writes the missing function with total confidence.
Every script is parse-checked the moment it arrives, not when you press Run. A failure shows a red row with a FIX IT button that sends the error straight back for a correction. And the previous version of your work is stashed before every write, so one Undo restores it. An assistant that can silently replace forty lines of your own script is one people stop using.
Here is a complete strategy — trend filter on a higher timeframe, ATR stop, fixed reward-to-risk target, and a move to break-even once the trade is one R in profit — with three inputs declared for the optimizer to sweep.
strategy("EMA pullback", risk_pct = 1, fill_on = "next_open") emaLen = input(50, "Trend EMA", minval = 5, maxval = 400) atrMult = input(2.0, "Stop in ATR", minval = 0.5, maxval = 10) target = input(2.0, "Reward:Risk", minval = 0.5, maxval = 10) trend = ta.ema(close, emaLen) atr = ta.atr(14) bias = htf.close("H4") > htf.ema("H4", 50) longSetup = bias and ta.crossover(close, trend) shortSetup = not bias and ta.crossunder(close, trend) if longSetup and not strategy.inPosition strategy.entry("long", sl = close - atrMult * atr, rr = target) else if shortSetup and not strategy.inPosition strategy.entry("short", sl = close + atrMult * atr, rr = target) // Once the trade is 1R up, protect it at break-even. if strategy.inPosition and strategy.posMfe(0) > 1 strategy.setSl(strategy.entryPrice)
FXScript ships 49 technical builtins under ta. — VWAP, Supertrend and daily pivots among them — higher-timeframe access through htf., other-symbol series through sym., market sessions in local time through session., and the usual math. helpers. The language is interpreted rather than compiled — source is tokenised, parsed to a syntax tree and walked, so nothing reaches eval and a shared script cannot reach another trader's session.
No math drift. The engine contains no indicator math of its own and no cost math of its own. ta.ema delegates to the exact function the chart draws with; profit and loss delegates to the same routine the manual-trading path uses. Nothing is reimplemented "for the backtest". This sounds like tidiness and is actually correctness — it prevents the failure every tester eventually meets, where the chart shows one EMA, the backtest used another, and the discrepancy surfaces months later via a trader who now trusts no number on the page.
No look-ahead, proven rather than promised. Every tester claims it cannot see the future. This one is asserted by a test that is harder to fool than inspection: truncate two thousand bars off the end of the data, re-run, and no trade that closed before the cut is permitted to move. If any part of the engine could read forward, earlier trades would change. The grammar also refuses a forward subscript outright — close[-1] is a parse error, not a runtime surprise.
Same-bar ties resolved from data, not a rule of thumb. One candle contains both your stop and your target. Which came first? From that candle alone the question has no answer, and how a tester handles it is the single biggest lever on the numbers it prints. The engine walks finer timeframes finest-first — M1, then M5, then M15, then M30 — and takes whichever level was touched first in the finest series that actually covers the candle. Switch the SL/TP CHECK to TICKS and, on all 105 markets, the real ticks decide first — longs on the bid, shorts on the ask — with the minute cascade covering anything the ticks do not. Ticks are part of Ultra.
Breakouts, pullbacks, session opens and baskets — written in a few lines and tested on the same engine, with nothing assumed that the data can answer.
strategy.stop() enters the moment a level breaks; strategy.limit() waits for a pullback. Group them with oco so one fill cancels the other, move them with strategy.modify(), let them expire after N bars. A candle that gaps through a stop fills at the open, not at a price that never traded.
Add trail = 20 * pip to any order, optionally starting once the trade is 1R up. The stop ratchets from each closed bar and only ever tightens — it never borrows the high of the bar it is moving on.
session.start("London") is true on the one bar that holds the London open — 08:00 UTC in winter, 07:00 in summer. New York, NYSE, Chicago, Frankfurt, Tokyo and Sydney follow their own clocks too, so an opening-range strategy does not drift an hour twice a year.
ta.vwap() with its bands, ta.supertrend() and its direction, and the daily floor pivots P, R1–R3 and S1–S3 — computed by the same functions that draw them on the chart, so the script and the chart never disagree.
Add symbol = "GBPUSD" to an order and that leg fills, settles and is priced on GBPUSD's own candles, pip size and measured spread — from the chart you are on. Correlation, spread and relative-strength ideas become testable.
Hold back the last 20–40% of the data, or run an anchored walk-forward, and see every pass scored on bars it was never ranked on. A neighbour score shows whether the best row sits on a plateau or on a lucky spike.
Tick the inputs you want varied, give each a min, max and step, and every combination runs and is ranked. Only numeric and boolean inputs are offered — a string has no ordering, so there is no range to sweep, and a boolean is always exactly false and true.
There is no policy cap on combinations, and that is a measured decision rather than a boast. The backtest function is pure, and everything expensive around it — the higher-timeframe series, the other-symbol series, the finer series used for tie resolution — is already cached from the ordinary Run. A sweep is therefore one prepare and N replays over bars already in memory. On OHLC it downloads nothing; on TICKS it fetches only the tick days that same-candle exits fall on, once, and every later combination reuses them. Replay cost was measured on real EUR/USD H1 bars before any limit was chosen:
| Bars | Light script (1 indicator) | Medium (3) | Heavy (10 + loops) |
|---|---|---|---|
| 3,000 | 5 ms | 6 ms | 12 ms |
| 12,000 | 17 ms | 22 ms | 51 ms |
| 40,000 | 56 ms | 329 ms | 675 ms |
A typical 12,000-bar sweep costs about 22 ms per combination, so 500 combinations is roughly eleven seconds. Rather than impose a limit, the panel times two real runs of your own script on your own bars and builds a live estimate from that — taking the faster of the two, because the first run pays for the JIT warming up and a sweep pays that once rather than N times. Work is time-sliced rather than run per-combination, so the tab never freezes.
The VALIDATION switch tests the winners on bars they were never ranked on: HOLD OUT re-runs every pass on the last 20–40% of the data and shows its out-of-sample result beside the in-sample one, and WALK-FORWARD picks the best pass on each anchored fold and trades it on the slice that follows, reporting the stitched out-of-sample result and its efficiency. A neighbour column scores every pass by the passes around it, so a spike stands out from a plateau.
It does not find you a profitable strategy. It removes the translation step between an idea and a tested result, which is a real cost and a real barrier — but a bad idea tested quickly is still a bad idea, and an optimizer run over enough combinations will always surface something that looks good on the sample it was fitted to. The ranking table is a starting point for out-of-sample work, not a verdict.
It does not trade for you, connect to a broker, or place a live order. Nothing here touches real money.
And the assistant is a language model, so it can misread an ambiguous instruction. That is precisely why the script lands in an editor you can read and edit rather than executing straight from the chat, and why the parse check runs before you ever press Run.
An assistant that writes strategy code is not the only way to get a rule set tested, and it is not automatically the best one. Three approaches are worth putting side by side honestly.
| FXScript with the assistant | MQL5 or Pine by hand | A no-code rule builder | |
|---|---|---|---|
| How you express a strategy | Plain English, then edit the script it returns | You write every line | Dropdowns and preset conditions |
| Time to a first result | Seconds | An afternoon, longer if you are learning the language | Minutes |
| What you can express | Anything the language supports; you can edit any line | Effectively unlimited | Only what the builder exposes |
| Where it runs | Browser, no install | MetaTrader or TradingView | Vendor's platform |
| Ceiling | The language's builtins | None worth naming | Hit quickly, and invisible until you hit it |
The honest summary is that hand-written MQL5 has no ceiling and this does. If your strategy needs something the language does not expose, writing it yourself in MQL5 remains the right answer, and no assistant changes that.
Where a rule builder differs is subtler and matters more. A builder's ceiling is invisible until you hit it: you construct the strategy you can construct, not the one you meant, and you often do not notice the substitution. A script does not have that failure mode, because the rules are written down in front of you and anything the language cannot do fails loudly rather than quietly becoming a different strategy.
And one comparison deserves stating plainly rather than spun: for optimization specifically, MetaTrader's Strategy Tester is better equipped than this. It distributes passes across local agents and the MQL5 Cloud Network and offers a genetic algorithm for grids too large to enumerate. This runs a complete grid on a single thread in a browser tab. That is a real advantage and it belongs to them.
An optimizer will always hand you a winner. Run five hundred combinations against any sample and the top row will look excellent, because you selected it for looking excellent on that sample. The ranking is a list of candidates, not a result. Four habits separate a finding from a coincidence.
Split the history before you sweep, not after. Set the range so the optimizer only ever sees part of your data, then take the winning inputs and re-run them on the span the sweep never touched. If the edge survives on data it was not fitted to, you have something worth more work. If it collapses, the sweep found a property of those particular bars. This is the single most useful thing you can do, and it costs one extra run — or set VALIDATION to HOLD OUT and the optimizer does it for every pass.
Prefer a plateau to a spike. Look at the neighbours of the winning row, not only the row. A 50-period EMA that scores well while 45 and 55 also score well is describing something real about the market. A 50 that scores brilliantly while 45 and 55 are mediocre is describing noise, and it will not repeat. Robustness looks like a broad hill, not a needle. The NBR column in the results does this arithmetic for you.
Watch the trade count as hard as the returns. Every combination you test is another chance to get lucky, so the more of the grid you sweep the more evidence you need from each candidate. A row showing a superb profit factor over 22 trades is not a strategy, it is a small sample. Sort by trades alongside the ranking metric and be suspicious of anything thin.
Judge on the numbers that survive contact with reality. Win rate is the most quoted and the least informative — a strategy can win 70% of the time and lose money. Expectancy tells you what an average trade is worth, max drawdown tells you what you would have had to sit through, and the two together tell you whether you could actually have traded it. A run you could not psychologically have held is not an edge you have.
None of this is specific to AI-written scripts. It is what separates a backtest from a story, and it applies exactly as much to a strategy you coded by hand. The assistant removes the translation step between an idea and a tested result; it does not remove the burden of proving the result means something.
AI backtesting means describing a trading strategy in plain English and having a language model turn it into runnable code that a backtest engine can execute over historical price data. On FxBacktest the assistant writes FXScript, the platform's own strategy language, and the engine replays that script bar by bar over real market history. You read the rules it produced before anything runs, so the model proposes and you approve.
No. You can describe the strategy in a sentence and run the script the assistant returns. FXScript is readable enough that most traders end up editing it directly after a few sessions — changing a number, flipping a condition — but nothing forces you to write it from scratch.
The assistant runs on AI credits. Credits can be bought as a one-off pack or bundled with a Pro or Ultra plan. Writing FXScript yourself, running the backtest and using the optimizer do not consume credits — only asking the assistant to generate or fix a script does.
It is specifically engineered not to. The language reference in the assistant's system prompt is generated from the engine itself rather than written by hand, and it states a closed world: these are the builtins, there are no others. A test asserts the reference and the interpreter agree in both directions, so nothing documented is missing from the engine and nothing in the engine is left undocumented. On top of that, every script the assistant returns is parse-checked the moment it arrives, not when you press Run.
Two ways. The grammar refuses a forward subscript outright — close[-1] is a parse error, not a runtime surprise. And the engine is checked by a test that truncates two thousand bars off the end of the data and re-runs: no trade that closed before the cut is allowed to move. If any part of the engine could read forward, earlier trades would change.
It is resolved from data rather than guessed, and you choose the data with the SL/TP CHECK switch beside RUN SCRIPT and in the optimizer. On OHLC, the default, the engine walks finer timeframes finest-first — M1, then M5, then M15, then M30 — and takes whichever level was touched first in the finest series that actually covers the candle. On TICKS, available with Ultra on all 105 markets, the real ticks inside the candle decide first — longs on the bid, shorts on the ask — and the minute cascade covers any candle the ticks do not. How a tester handles this tie is the single biggest lever on the numbers it prints.
Yes. strategy.stop() enters on a breakout and strategy.limit() on a pullback; orders can share an oco group so one fill cancels the other, can be moved with strategy.modify() and can expire after a number of bars. Any order can carry a trailing stop with trail = distance, optionally starting once the trade is 1R up. Adding symbol = "GBPUSD" to an order trades that instrument on its own candles, pip size and spread from whatever chart you are on. Market sessions such as session.start("London") follow each market's own clock, daylight saving included.
There is no policy cap. The backtest function is pure and everything expensive around it is already cached from the ordinary Run, so a sweep is one prepare and N replays over bars already in memory — on OHLC it downloads nothing. On TICKS the first combinations fetch only the tick days their same-candle exits fall on, and later combinations reuse them. On real EUR/USD H1 bars a typical 12,000-bar replay costs about 22 ms per combination, so 500 combinations is roughly eleven seconds. Before a sweep the panel times two real runs of your own script on your own bars and builds the estimate from that.
Create an account and open the script editor. Write FXScript yourself, or tell the assistant what you trade and read what it hands back.
AI backtesting is a way of testing a trading strategy without writing the code for it yourself: you describe the rules in plain English, a language model turns them into a script a backtest engine can execute, and the engine replays those rules across historical price data one bar at a time. The value is not that the model is clever — it is that the distance between "I think this setup works" and a table of measured results stops being an afternoon of coding.
What separates a useful implementation from a demo is everything around the model. A closed-world language reference generated from the engine stops the assistant inventing indicators that do not exist. A parse check on arrival stops a broken script wasting a run. An engine that delegates its indicator and cost math to the same functions the chart and the manual-trading path use stops the backtest and the chart disagreeing. A look-ahead test that truncates the data and demands earlier trades stay identical catches a whole class of bug rather than the instances someone happened to think of. Tie resolution from real ticks or finer timeframes replaces a coin-flip on every candle that contains both a stop and a target.
If you would rather not touch a script at all, no code backtesting builds the same kind of strategy from a form and optimizes it in the dashboard. If you would rather test strategies by hand, the same engine powers manual bar-by-bar backtesting on the same data. If you are weighing the two approaches, manual versus automated backtesting covers where each one earns its keep, and how to backtest a trading strategy walks through the process itself.