Robots and AI
Updated 7 October 2026, 5 min readTide is the language eTrader robots and chart indicators are written in. A moving average is one expression, ema(close, 50), and an order is one call with named arguments. You write a plain text file ending in .tide in eTrader Code, and it builds into a small file that eTrader runs for you.
This guide is the short tour. The full manual, with a worked example for every part of the language, is at tide.etraderweb.com.
What you can build
| You write | It builds to | It does |
|---|---|---|
| A bot | .etb | Watches the market and places trades on your account from eTrader's servers, with your computer off |
| An indicator | .eti | Draws lines, bands, arrows and histograms on your chart |
| A library | part of the bot that imports it | Holds functions you reuse in several bots |
A whole bot
This one buys when a fast moving average crosses above a slow one, and never holds more than one position:
bot "Golden Cross" { version "1.0" }
input int fast = 50
input int slow = 200
input lots volume = 0.10
fn onBar() {
guard positions.count() == 0 else { return }
if crossesOver(ema(close, fast), ema(close, slow)) {
trade.buy(volume, sl: symbol.ask - 40 * symbol.pip, tp: symbol.ask + 90 * symbol.pip)
}
}
Read from the top. The first line names the bot. The three input lines become the settings form you fill in when you switch the bot on, with the numbers after = as defaults. onBar runs once at the start of every new candle. The guard line says: carry on only when nothing is open, otherwise leave. The last part checks for the cross and places the order.
Because symbol.pip is the size of one pip on whatever instrument the bot runs on, the same file works on a currency pair and on gold without a change.
Series, the idea to learn first
Almost everything in a strategy has one value per candle: the close, a moving average, whether a candle was green. Tide calls that a series. You read one with square brackets, and the number counts backwards in time.
close[0]is this candle's close, the one still forming.close[1]is the candle before it.ema(close, 50)[0]is the moving average's value now.
Series do arithmetic without a loop. close - open is the body of every candle, and close > open is whether each one closed up. Add [0] only when you need one actual number, usually inside an if. Comparing a whole series to a single number, as in ema(close, 50) > 1.08, is refused when the file is checked, which catches the most common beginner mistake before it trades.
Types that protect your account
Tide checks types when the file compiles, not when it trades. Two of them exist for traders: price, which rounds to the instrument's digits, and lots, which snaps to the instrument's volume step. Pass a price where a volume belongs and the file does not compile. A mistake that would be expensive on a live account shows up as a line in the Problems tab instead.
Orders
Only the volume is required. Everything else is named, so a stop loss and a take profit cannot be swapped by accident.
| Call | What it does |
|---|---|
trade.buy(0.10) | Buys at the market |
trade.sell(0.10, sl: stop, tp: target) | Sells with a stop loss and a take profit |
trade.buyLimit(1.0800, 0.10) | Places a buy limit at 1.0800 |
trade.sellStop(1.0750, 0.10) | Places a sell stop at 1.0750 |
trade.closePartial(pos, 0.05) | Closes part of a position |
trade.breakEven(pos, offsetPips: 5) | Moves the stop loss to break even, with an offset in pips |
trade.trail(pos, distancePips: 40, stepPips: 5) | Trails the stop behind the price |
A position has one take profit, and reaching it closes the whole position.
Every call returns a result. A Broker can refuse an order for ordinary reasons, such as a closed market or a stop too close to the price, so a careful bot checks r.ok and writes the reason to its journal.
To list what is open, positions.mine() returns only the positions this bot opened. Two bots on the same account never touch each other's trades that way.
Events
A bot does nothing until eTrader calls one of its handlers:
onBarruns once per new candle. It is the right default, because the same signal cannot fire twice on one candle.onTickruns on every price change. Use it when you need every tick, such as for a trailing stop.onTimerruns on an interval you set withtimer.every(5m).onFilledandonClosedrun when this bot's orders fill and its positions close.
Journal and notifications
log.info("text") writes a line to the bot's journal, which you read in the terminal's Bots window. notify("Title", "text") sends a push notification to your phone. Every runtime error is written to the journal with the file and line it came from. Three errors in a row on the same line stop the bot, and you are told.
What Tide leaves out
Some things are missing on purpose. A bot cannot read or write files on a disk; it keeps state that must survive a restart in store instead. It cannot run native code. It can reach the internet only at addresses it declares in a permissions block, and you see that list before you add the bot. Indicators cannot reach the internet at all.
The quickest way in is to open eTrader Code, press +, choose New Bot, paste the example above and press Run Test.