millionchart
فارسی

Lesson 14: Your first strategy

Turn a crossover into a strategy with entries, a stop and a target, put real costs in the header, and read the trades the chart draws.

Lesson 14 of 18. A strategy is an indicator that also places orders. The chart does not trade for you: it replays your orders on the bars you can see and shows the trades that would have happened, with the costs you declare.

Orders from a crossover#

Cuprel
strategy "Crossover strategy"
    edition = 1
    display = price

input fast_length: int = 10, name = "Fast length", min = 1
input slow_length: int = 30, name = "Slow length", min = 2
let fast = tech.ema(close, fast_length)
let slow = tech.ema(close, slow_length)
if tech.crosses_above(fast, slow)
    orders.enter("Long", side.long)
if tech.crosses_below(fast, slow)
    orders.close("Long")
plot(fast, name = "Fast", color = color.green)
plot(slow, name = "Slow", color = color.red)
  • strategy "Crossover strategy" is the header, in place of indicator "...".
  • orders.enter("Long", side.long) asks to open a long trade called "Long". The name is how you refer to the trade later.
  • orders.close("Long") asks to close it.
  • An order is placed when the bar closes, and it fills at the next bar's open. The script cannot buy at the close it has just seen.

A stop and a target#

orders.exit places a stop and a limit for a trade at once. Whichever is reached first closes the trade, and the other is cancelled.

Cuprel
strategy "Crossover with exits"
    edition = 1
    display = price

input stop_pct: float = 1.0, name = "Stop %", min = 0.1, step = 0.1
input target_pct: float = 2.0, name = "Target %", min = 0.1, step = 0.1
let fast = tech.ema(close, 10)
let slow = tech.ema(close, 30)
if tech.crosses_above(fast, slow)
    orders.enter("Long", side.long)
if position.size > 0
    let entry = position.avg_price
    orders.exit(
        "Exit",
        "Long",
        stop = entry * (1 - stop_pct / 100),
        limit = entry * (1 + target_pct / 100),
    )
plot(fast, name = "Fast", color = color.green)
plot(slow, name = "Slow", color = color.red)

orders.exit(key, entry, stop = ..., limit = ...) belongs to the trade named in entry (here "Long"). It lives only as long as that trade does. position.size is the open size, positive for a long; position.avg_price is the price the trade opened at.

Size and costs in the header#

A result with no costs is flattering. Say what trading costs in the header, in the same place as the size:

Cuprel
strategy "Crossover with costs"
    edition = 1
    display = price

setup:
    capital = 10000
    size = sizing.lots(0.1)
    fees = fee.per_lot(3.5)

execution:
    spread = 20 ticks
    slippage = 2 ticks

let fast = tech.ema(close, 10)
let slow = tech.ema(close, 30)
if tech.crosses_above(fast, slow)
    orders.enter("Long", side.long)
if tech.crosses_below(fast, slow)
    orders.close("Long")
plot(fast, name = "Fast", color = color.green)
plot(slow, name = "Slow", color = color.red)
  • size = sizing.lots(0.1) trades 0.1 lot (a lot is the standard trading size of an instrument). Other ways to say the size are sizing.fixed(n) for units, sizing.equity(p) for a share of the account and sizing.cash(m) for money.
  • spread = 20 ticks and slippage = 2 ticks are in ticks of the symbol (a tick is its smallest price step). The spread is the gap between the buying and the selling price; slippage is the price moving between the order and its fill. fees = fee.per_lot(3.5) charges 3.5 of account money per lot, on every fill.
  • Every setting is live: you can give one an input, and changing the input changes the next run.

Read the result#

The chart marks each entry with a triangle (the name of the entry beside it) and each exit with a cross, green for a profit and red for a loss, with a dotted line between them. A table in a corner shows the net profit and its percentage, the number of closed trades, the share of them that made money, the profit factor (the money won divided by the money lost), the largest drawdown (the biggest fall of the account from a peak) and the number of trades still open. A Costs row appears when commission or swap was paid. The marks and lines are kept for the newest 500 trades; the table counts all of them. Two inputs on the strategy, Show the trades on the chart and Show the results table, switch the marks and the table off.

In the editor a strategy has one more button, Test: it saves the script and runs it in the Strategy Lab, which tests it over a longer period with more choices of price data and costs. Lesson 15 shows the Lab, and Strategies and the header lists every setting of the header.

Try changing#

  • Set slow_length to 50 in the settings of the first program. There are fewer crossings, so the table counts fewer trades.
  • In the second program, make target_pct smaller than stop_pct, then larger again. Watch how the share of trades that made money and the size of each loss change in the table.
  • In the third program, raise spread to 60 ticks. Every entry fills higher, and the net profit in the table falls.
  • In the first program, write side.short in place of side.long and use tech.crosses_below to enter and tech.crosses_above to close. The strategy now sells short.

Checkpoint#

  • You can write a strategy header and open and close a trade with orders.enter and orders.close.
  • You can protect a trade with orders.exit and a stop and a target.
  • You can put the size and the costs in setup: and execution:.
  • You know that an order fills at the next bar's open, and that the chart only simulates the trades.

Next: Lesson 15: Testing in the Strategy Lab