> ## Documentation Index
> Fetch the complete documentation index at: https://gocharting.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Backtest a moving-average crossover

> Build a complete strategy that buys when a fast average crosses above a slow one and closes when it crosses back, with an account set up in strategy().

In this tutorial we write a strategy: it goes long when a fast moving average crosses above a slow one and closes the position when
the fast one crosses back below. A strategy runs on the chart's history and records the trades it would have made. The orders are
simulated on an account inside the script engine; nothing is sent to a broker. Every step is a whole script: replace what is in the
editor, and check it.

### 1. declare a strategy and draw the averages

A strategy declares itself with `strategy(...)` instead of `indicator(...)`. A script has exactly one of the two. It may plot like an
indicator.

> [!WARNING]
>
> GoCharting is a charting and analytics tool. This is not investment advice. Trading and investing carry a high risk of loss and are not suitable for everyone. You can lose some or all of your money.

> [!WARNING]
>
> These results are based on simulated or hypothetical performance that has inherent limitations. They do not represent actual trading and were not executed, and may under- or over-compensate for market factors such as liquidity. Simulated results are designed with the benefit of hindsight. No representation is made that any account will or is likely to achieve similar profits or losses.

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
strategy("MA crossover", overlay=true)
fastLen = input.int(10, "Fast length", minval=1)
slowLen = input.int(30, "Slow length", minval=2)
float fast = talib.sma(close, fastLen)
float slow = talib.sma(close, slowLen)
plot(fast, title="Fast", color=color.blue)
plot(slow, title="Slow", color=color.orange)
```

Two lines are drawn over the price bars. No orders are placed yet.

### 2. enter when the fast average crosses above

`talib.crossover(fast, slow)` is true on the bar where `fast` moves from at or below `slow` to above it. `strategy.entry(id, direction)`
places an order to open a position: `id` names it, and `direction` is `strategy.long` or `strategy.short`.

```lipi highlight={7-9} theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
strategy("MA crossover", overlay=true)
fastLen = input.int(10, "Fast length", minval=1)
slowLen = input.int(30, "Slow length", minval=2)
float fast = talib.sma(close, fastLen)
float slow = talib.sma(close, slowLen)
if talib.crossover(fast, slow) {
    strategy.entry("Long", strategy.long)
}
plot(fast, title="Fast", color=color.blue)
plot(slow, title="Slow", color=color.orange)
```

The strategy now opens a long position at each upward cross. A market order placed on a bar is filled at the start of the next bar,
at its open, so the entry price is the next bar's open and not the close that triggered it. While a long position is open a second
`strategy.entry` in the same direction is ignored, because `pyramiding` defaults to 1.

### 3. close when it crosses back

`strategy.close(id)` closes the position opened under that id. `talib.crossunder(fast, slow)` is true where `fast` moves from at or
above `slow` to below it.

```lipi highlight={10-12} theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
strategy("MA crossover", overlay=true)
fastLen = input.int(10, "Fast length", minval=1)
slowLen = input.int(30, "Slow length", minval=2)
float fast = talib.sma(close, fastLen)
float slow = talib.sma(close, slowLen)
if talib.crossover(fast, slow) {
    strategy.entry("Long", strategy.long)
}
if talib.crossunder(fast, slow) {
    strategy.close("Long")
}
plot(fast, title="Fast", color=color.blue)
plot(slow, title="Slow", color=color.orange)
```

Each long trade now ends at the next downward cross. To reverse into a short instead of going flat, call
`strategy.entry("Short", strategy.short)` there: an entry against an open position closes it and opens the new one.

### 4. set up the account

The account is set in `strategy(...)`. Every argument is a fixed value, not a calculation. The ones used most:

| Argument | Default | Meaning |
| - | - | - |
| `initial_capital` | 1,000,000 | Starting equity |
| `default_qty_value` | 1 | Size of an order that gives no `qty`: with the default type, units |
| `default_qty_type` | `strategy.fixed` | `strategy.fixed` (units); the strings `"cash"` and `"percent_of_equity"` only work for orders that carry a `limit` or `stop` price |
| `commission_type`, `commission_value` | percent, 0 | A cost charged when a leg opens and when it closes |
| `pyramiding` | 1 | How many entries in one direction may be open |
| `process_orders_on_close` | `false` | `true` adds a fill at the close of the bar that placed the order |

`strategy.fixed` is a constant. There is no `strategy.cash` or `strategy.percent_of_equity`:

```lipi-invalid theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
strategy("Sizing", default_qty_type=strategy.percent_of_equity, default_qty_value=10)
plot(close)
```

The compiler says: Namespace `strategy` has no variable `percent_of_equity`. To size by equity, pass the quantity to the order: `strategy.entry("Long", strategy.long, qty=strategy.equity * 0.1 / close)`.

### 5. show the position and the result

`strategy.position_size` is the signed size of the open position (positive long, negative short, zero flat). We shade the background
while long and give each order a comment. The trade list, equity and totals appear in the strategy's results (see
[Reading a strategy's results](https://gocharting.com/docs/scripting/strategies/strategy-results.md)); `strategy.netprofit`, `strategy.equity` and the other
`strategy.*` variables are readable in the script too.

```lipi wrap highlight={2,8,11,15} theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
strategy("MA crossover", overlay=true, initial_capital=10000, default_qty_value=1, commission_type=strategy.commission_percent, commission_value=0.05)
fastLen = input.int(10, "Fast length", minval=1)
slowLen = input.int(30, "Slow length", minval=2)
float fast = talib.sma(close, fastLen)
float slow = talib.sma(close, slowLen)
if talib.crossover(fast, slow) {
    strategy.entry("Long", strategy.long, comment="fast over slow")
}
if talib.crossunder(fast, slow) {
    strategy.close("Long", comment="fast under slow")
}
plot(fast, title="Fast", color=color.blue)
plot(slow, title="Slow", color=color.orange)
bgcolor(strategy.position_size > 0 ? color.new(color.green, 0.9) : na)
```

## What we built

A long-only crossover strategy with inputs for both lengths, a 10,000 account, a 0.05 percent commission on each fill, and a green
background while a position is open. The orders are simulated; to be told when a signal appears, use an alert (see
[Alert on your own condition](https://gocharting.com/docs/scripting/learn/alert-on-your-condition.md)).

## Next

> [card] [Strategies and backtesting](https://gocharting.com/docs/scripting/strategies/overview.md)
>
> how a strategy runs and what it can and cannot do.

> [card] [Orders and positions](https://gocharting.com/docs/scripting/strategies/orders-and-positions.md)
>
> limit and stop orders, `strategy.exit`, `strategy.order`.

> [card] [Reading a strategy's results](https://gocharting.com/docs/scripting/strategies/strategy-results.md)
>
> the trade list and the `strategy.*` variables.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.