Appearance
Your first strategy
How do you test a trading rule on past bars? Write it as a strategy: strategy() where an indicator has indicator(), and orders where it has only plots. Add it to the chart, and the Strategy Tester shows every trade the rule would have made.
pine
//@version=6
strategy("Moving average cross", overlay = true, initial_capital = 10000,
default_qty_type = strategy.percent_of_equity, default_qty_value = 90,
commission_type = strategy.commission.percent, commission_value = 0.1)
fast = ta.sma(close, input.int(10, "Fast length"))
slow = ta.sma(close, input.int(30, "Slow length"))
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long) // fills at the next open
if ta.crossunder(fast, slow)
strategy.close("Long")
plot(fast, "Fast", color = color.teal)
plot(slow, "Slow", color = color.orange)New strategy, in the Script Editor's menu, starts you on a rule much like this one.
What the rule says
The strategy buys when the 10-bar average crosses above the 30-bar one and sells when it crosses back below. strategy.entry opens a position under the name "Long", and strategy.close closes the position of that name. Each call places an order. On a bar where neither condition holds, nothing is placed and the position stays as it is.
How the backtest is sized
The arguments of strategy() set the account the backtest trades. With none of them, it starts with 1,000,000 in the chart's currency and trades one unit at a time, free of commission, which rarely matches what you would trade.
| Argument | In this example | Without it |
|---|---|---|
initial_capital | 10,000 to start | 1,000,000 |
default_qty_type, default_qty_value | each entry spends 90% of equity | one unit |
commission_type, commission_value | 0.1% of each fill | no commission |
Why 90 and not 100? An entry takes its size at the close that placed it and fills at the next open. If that open is higher, an entry sized at 100% costs more than the account holds and is refused, and one that fills leaves the commission short, so small margin calls sell slivers of it. Size the orders has the rule.
When an order fills
Your script runs at the close of each bar. An order it places there fills at the next bar's open, because the close it read is already over. A trade's entry price is therefore the open after the cross, not the close where you saw it.
A fill at the close you saw is a lookahead
process_orders_on_close = true fills orders at the same close that triggered them. That can't be done in real trading unless you place the order before the bar closes, so a backtest with it can look better than any account would do. Leave it off unless your rule really trades at the close.
Read the results
After Add to chart, the editor's status line gives the count of closed trades and the net profit, as in Strategy, 10 trades, net +16.62%. Your numbers depend on your chart's bars. The chart marks each entry and exit.
For the whole report, type TESTER in the command field to open the Strategy Tester. It reports the strategy on the chart you added it to:
| View | What it shows |
|---|---|
| Equity | The account's equity bar by bar beside buy and hold, with the drawdown beneath. |
| Metrics | The report: net profit from closed trades, total P&L with what's still open added, drawdown, profit factor, Sharpe and more. |
| Monthly | The return of each month. |
| Trades | Each trade, from its entry to its exit, with its profit. |
Change the fast or slow length in the study's settings, and the Tester reads the new run.
See also
- Strategies: orders, exits, sizing and how the backtest fills them.
- strategy reference: every
strategy.*function and variable. - Your first script: the editor, the status line and saving.
- Pine or AmenoScript: which dialect to write in.