One trade per asset class, end to end, with the arithmetic. Every figure comes from the contract spec the engine holds for that instrument and the formulas on Costs and Fills, so you can reproduce them by hand and check the engine against them.
Each example also lists what the engine did not charge, because that is the part a P&L number cannot tell you.
Two numbers drive every line below: pip size, the increment a stop, a target, a spread and a swap are quoted in, and contract size, the units of the instrument in one lot. The engine holds both for the instruments it recognises, and where it does, the example defines nothing.
The run configurations below set no spread. Bars downloaded with both sides fill at the bid and the ask they recorded, and the sums below come out the same. A bar without an ask side, such as an import with one price series, uses the average spread on its custom symbol instead.
Forex: EURUSD, one standard lot
The engine derives both numbers from the symbol. Nothing to define.
| Setting | Value |
|---|---|
| Pip size | 0.0001 (two currency codes, quote is not JPY) |
| Contract size | 100,000 units of the base currency |
| Size | 1.0 lot |
Run configuration: the spread from the data, commission 7.00 per lot round turn, swap long -0.8 pips, swap short 0.3 pips, accuracy M1 proxy, intrabar pessimistic.
The strategy signals long on a Monday with sl_pips=30, tp_pips=45. The target is hit two nights later, on Wednesday.
gross 45 pips x 0.0001 x (1.0 x 100,000) = 450.00
commission 7.00 x 1.0 lot = -7.00
swap 2 nights x -0.8 x 0.0001 x 100,000 = -16.00
---------
net 427.00The spread is not a line in that sum because it is in the fill price instead. The buy filled at the ask, and the stop and the target were placed 30 and 45 pips from that fill, so a target exit pays exactly 45 pips. What the spread costs is the distance the market had to travel first: a long's target is reached on the bid, which sits a spread below the ask it bought at. A wider spread does not move the gross above; the number of trades that reach a target does. An exit on a signal rather than on the target is the other case: it sells at the bid open, so the spread is in the exit price as well.
Not charged: nothing is missing from the sum. The swap line follows the rollover calendar on Costs and Fills: opened on a Tuesday instead, the same trade would cross the rollover out of Wednesday, which counts three, and pay four nights, -32.00. Held from Friday to Monday it pays one. Forex is the case the engine was built for.
Index: US500, ten lots
The engine carries a row for US500 and for every other index in the picker, so an index defines nothing either. Read the row before writing a stop distance, because the pip is not a point.
| Setting | Value |
|---|---|
| Pip size | 0.1, a tenth of an index point |
| Contract size | 1.0 unit per lot |
| Size | 10 lots, so 10 currency units per index point |
Run configuration: the spread from the data, commission 0.40 per lot round turn, swap long -7.0 pips, accuracy OHLC, intrabar pessimistic.
Long from 5,000.0 with tp_pips=250. That is 250 x 0.1, so 25.0 index points, and the target sits at 5,025.0. Held one night.
gross 250 pips x 0.1 x (10 x 1.0) = 250.00
commission 0.40 x 10 lots = -4.00
swap 1 night x -7.0 x 0.1 x (10 x 1.0) = -7.00
---------
net 239.00A strategy that wants a 25 point target has to ask for 250, not 25. The engine does not use one pip for every index: US500, USTEC, US2000, DE40, UK100, FR40, EU50 and AUS200 use 0.1, while US30, JP225 and HK50 use 1.0. The same tp_pips is a ten times larger move on US30 than on US500.
Not charged: expiry, roll and cash settlement. The run treats the index as continuously tradable. Currency is the other gap: DE40 quotes in EUR, UK100 in GBP and JP225 in JPY, and the account conversion rate is fixed at 1.0, so a result on those is in the quote currency wearing your account currency's label. US500 quotes USD, which is the only reason the sum above is safe.
Crypto: BTCUSD, half a coin
BTC is one of the coin codes the engine recognises and USD one of the quotes it accepts, so BTCUSD places itself.
| Setting | Value |
|---|---|
| Pip size | 1.0, one whole US dollar |
| Contract size | 1.0 coin per lot |
| Size | 0.5 lots, so 0.5 BTC |
Run configuration: the spread from the data, commission 50.00 per lot round turn, swap long -6.0 pips, accuracy OHLC, intrabar pessimistic.
Long from 60,000.00 with tp_pips=1500. The pip is a dollar, so the target is 1,500 dollars away at 61,500.00. Held two nights.
gross 1500 pips x 1.0 x (0.5 x 1.0) = 750.00
commission 50.00 x 0.5 lots = -25.00
swap 2 nights x -6.0 x 1.0 x (0.5 x 1.0) = -6.00
---------
net 719.00The pip is a whole dollar deliberately: 0.0001 on a 60,000 dollar instrument is not a distance anybody trades, and sl_pips=800 reading as an 800 dollar stop is the point. The engine also records a tick size of 0.01 for crypto. A strategy can read it as ctx.symbol.tick_size, and nothing in the fill path rounds a price to it.
Not charged, and the first one is the largest: the exchange fee. Every real venue charges a percentage of notional and the engine's commission is a flat amount per lot, so it does not move when the price does. The 25.00 above is right at 60,000 and half of what it should be at 120,000. Funding is the second: a perpetual funds every eight hours, and the engine charges swap once per UTC date boundary crossed, so it can only be a rough sum of three real charges.
Data is the third thing to watch. The archive serves ten coins, Bitcoin, Ether and eight more, so another coin arrives by CSV import or a plugin data source. Crypto trades seven days a week and the engine has no calendar in either direction, so a series that stops on Friday gives the run a weekend the market did not have.
Stock: AAPL, one hundred shares
A share from the archive places itself: AAPL.US/USD has a row with one share per lot and a cent pip. A share from your own CSV under its plain ticker does not. AAPL is four letters and it is not in the engine's table, so a run on it is refused with a message naming what to add, rather than priced as a currency pair. Define it under Data, in the Instruments tab.
| Setting | Value |
|---|---|
| Pip size | 0.01, one cent |
| Contract size | 1, one share per lot |
| Size | 100 lots, which is 100 shares |
Both numbers have to be set. A blank spec starts at the forex pair, 0.0001 and 100,000, and leaving those is the exact mistake the refusal exists to prevent: 100 lots of AAPL at 190 would be 1.9 billion of notional. The US Stock template in the editor sets 0.01 and 1 for you.
Run configuration: an average spread of 1 to 2 pips on the symbol, which is 1 to 2 cents, since an import has no ask side, commission 0.01 per lot round turn, swap 0 both sides, accuracy OHLC.
Long from 190.00 with tp_pips=250, which is 2.50, so the target is 192.50.
gross 250 pips x 0.01 x (100 x 1) = 250.00
commission 0.01 x 100 lots = -1.00
swap 0 = 0.00
---------
net 249.00Swap is set to zero deliberately. The engine's swap is a per night charge in pips, which models financing on a leveraged contract; unleveraged cash equity has none. If you trade the share as a CFD, put your broker's financing rate in the swap field instead.
The result will report this run's asset class as cfd, not equity. A symbol spec carries an asset class field, the editor does not set one, and the engine then uses cfd, the class that claims the least. It changes the label on the result and nothing in the arithmetic. A run submitted through the API can send an asset class of its own instead, and equity supplies the same 0.01 and 1.
Not charged, and this one bites: dividends and splits. If the position had been held across an ex-dividend date, the price series drops by the dividend and the engine reads that drop as a loss, with no offsetting credit. Across a split it reads a step change as a crash or a spike. Use an adjusted series, or keep runs away from those dates.
Overnight gaps themselves are handled. A bar that opens past your stop fills at that open, not at the stop level, so a gap down costs what it cost rather than what you asked for. A gap through a target fills at the open too.
There is still no trading calendar. A holiday is an absence of bars and nothing more.
Reproducing these
The arithmetic above is all the engine does. If your run disagrees with a figure you computed the same way, one of these is usually why:
- Pip size. The single most common mistake. Everything scales from it: the stop, the target, the spread and the swap. Check the asset class on the result against what you meant to trade before you check anything else.
- Sides. The commission field is the round turn, charged half on each side. A broker that quotes per side wants twice its number in the field.
- Nights. Swap counts UTC date boundaries crossed, not 24 hour periods, and weights them by the rollover calendar: three out of Wednesday, none out of Friday or Saturday. A position opened at 23:50 on a Monday and closed at 00:10 is charged one night.
- Intrabar. On OHLC, a bar that spans both the stop and the target is resolved by the policy, not by the data. Pessimistic takes the stop. On M1 proxy and Tick the order is read from the minute bars or the ticks, so the policy only decides when a single sample holds both levels.
- The tier you got. A result records the accuracy tier it actually achieved, which is not always the one you asked for. Tick over a range with no cached ticks is an OHLC run.
- A run that ended early. If the account reaches zero the engine closes the position at the price that costs exactly what was left, stops the run, and marks the result ruined with the timestamp. A short equity curve is a stop out, not a strategy that went quiet.