Edgoro
Guides

strategy.entry vs strategy.order in Pine Script v6: reversals, pyramiding, closing and position size

When to use strategy.entry, strategy.order, strategy.close and strategy.exit in Pine Script v6: automatic reversals, pyramiding, partial closes and risk-based quantity.

Pine Script gives a strategy four ways to send orders, and they behave differently in ways the Strategy Tester won't warn you about. A position that doubles when you meant to reverse it, a second entry that never fills, a position that keeps growing bar after bar: these come from using the wrong command, not from the strategy idea.

The four commands

CommandWhat it doesLimited by pyramidingReverses on its own
strategy.entry()Opens or adds to a position in one directionYesYes: an entry the other way closes the position first
strategy.order()Sends a plain buy or sell orderNoNo: an opposite order reduces the position, and flips it only if it's bigger
strategy.close(), strategy.close_all()Exit one entry by its id, or everything, at marketn/an/a
strategy.exit()Stop-loss, take-profit and trailing exits attached to an entryn/an/a

How strategy.entry() reverses

Say the strategy is long 1 BTC and this runs:

strategy.entry("Short", strategy.short, qty = 1)

TradingView sends a sell order for 2: one to close the long and one to open the short. You end up short 1. That's what you want for a stop-and-reverse system, and a surprise if you expected to end flat.

The same situation with strategy.order():

strategy.order("Sell", strategy.short, qty = 1)

sells exactly 1, so the position goes from long 1 to flat. Only an order larger than the position flips it.

Pyramiding

pyramiding in the strategy() declaration caps how many entries can stack in the same direction. The default is 0, which allows one: once you're long, every further strategy.entry() long is ignored until the position closes. Set pyramiding = 3 to allow up to three.

strategy.order() ignores pyramiding entirely. Put one inside a condition that stays true for ten bars and you get ten orders. If you use it, check strategy.position_size yourself before sending anything.

Long-only strategies

To trade only one direction without rewriting the signals, restrict the entries:

strategy.risk.allow_entry_in(strategy.direction.long)

With this line, a strategy.entry() short no longer opens a short. It closes the open long instead, which is usually exactly what a long-only version of a long/short system should do.

Closing positions

  • strategy.close("Long") closes the entry whose id is "Long", at market on the next bar's open by default. The id must match the entry's id exactly, case included.
  • strategy.close("Long", qty_percent = 50) closes half of it.
  • strategy.close_all() closes everything.
  • Add immediately = true to fill on the same bar's close instead of the next open.

When several entries are open, exits follow first in, first out by default. Set close_entries_rule = "ANY" in strategy() if you want to close a specific entry out of order.

Stops and targets belong in strategy.exit(), which has its own rules: our strategy.exit() guide covers them.

Position size: the default and the qty argument

Without a qty argument, an entry uses the declaration's default: default_qty_type set to strategy.fixed (a number of contracts or units), strategy.cash (an amount of money) or strategy.percent_of_equity. None of those ties the size to your stop. For a fixed risk per trade, compute the quantity yourself:

quantity = (equity × risk %) ÷ (stop distance × syminfo.pointvalue)

syminfo.pointvalue is what a full point of price movement is worth for one contract. Three examples with 10,000 of equity and 1% risk (100):

SymbolStop distancePoint valueQuantity
BTCUSD2,400 (2 × an ATR of 1,200)10.0417 BTC
EURUSD0.0020 (20 pips)150,000 units (0.5 lot)
ES futures20 points500.1 contracts

The last row is a useful warning. The backtest will happily trade 0.1 of an ES contract; a real broker won't. For futures, round down with math.floor() and treat a result below 1 as "the account is too small for this stop". The position size calculator does the same arithmetic for forex and gold.

A complete example

This breakout strategy uses each idea above: risk-based size, automatic reversal with strategy.entry(), one add with pyramiding = 2, and a separate stop for each entry id.

//@version=6
strategy("Risk-sized breakout with one add", overlay = true, initial_capital = 10000, pyramiding = 2, commission_type = strategy.commission.percent, commission_value = 0.05, slippage = 2)

riskPct  = input.float(1.0, "Risk per entry (% of equity)", minval = 0.1, step = 0.1)
atrLen   = input.int(14, "ATR length", minval = 1)
atrMult  = input.float(2.0, "Stop distance (x ATR)", minval = 0.1, step = 0.1)
lookback = input.int(20, "Breakout lookback (bars)", minval = 2)

atr     = ta.atr(atrLen)
upper   = ta.highest(high, lookback)[1]
lower   = ta.lowest(low, lookback)[1]
breakUp = close > upper
breakDn = close < lower

// Quantity that loses riskPct of equity if price travels stopDistance against the trade
qtyFor(stopDistance) =>
    riskCash = strategy.equity * riskPct / 100
    stopDistance > 0 ? riskCash / (stopDistance * syminfo.pointvalue) : 0.0

var float stopLevel = na

if breakUp and strategy.position_size <= 0
    // strategy.entry reverses a short on its own: it buys the short back and opens the long
    stopLevel := close - atrMult * atr
    strategy.entry("Long", strategy.long, qty = qtyFor(close - stopLevel))
else if breakDn and strategy.position_size >= 0
    stopLevel := close + atrMult * atr
    strategy.entry("Short", strategy.short, qty = qtyFor(stopLevel - close))
else if breakUp and strategy.position_size > 0 and strategy.opentrades < 2
    // one add, risking the same amount to the same stop (needs pyramiding = 2)
    strategy.entry("Long add", strategy.long, qty = qtyFor(close - stopLevel))
else if breakDn and strategy.position_size < 0 and strategy.opentrades < 2
    strategy.entry("Short add", strategy.short, qty = qtyFor(stopLevel - close))

if strategy.position_size > 0
    strategy.exit("Long stop", "Long", stop = stopLevel)
    strategy.exit("Long add stop", "Long add", stop = stopLevel)
if strategy.position_size < 0
    strategy.exit("Short stop", "Short", stop = stopLevel)
    strategy.exit("Short add stop", "Short add", stop = stopLevel)

plot(upper, "Breakout high", color.teal)
plot(lower, "Breakout low", color.orange)
plot(strategy.position_size != 0 ? stopLevel : na, "Stop", color.red, style = plot.style_linebr)

Things to notice:

  • The reversal branch runs when the position is flat or on the other side, so the same strategy.entry() call opens a fresh position or reverses an existing one.
  • The add risks the same amount to the same stop, so the second entry is smaller when price has moved further from the stop.
  • Each strategy.exit() names its entry id. An exit for "Long add" placed before the add exists does nothing until the add fills.
  • Commission and slippage are set in the declaration, so the report includes costs. The Strategy Tester settings guide explains each one.

Common bugs

SymptomCauseFix
The second entry never fillspyramiding is 0Set it to the number of entries you allow
A reversal opens double the size you expectedstrategy.entry() adds the open position to qtyExpected behavior; use strategy.close() first if you want to end flat
The position keeps growingstrategy.order() inside a condition that stays trueCheck strategy.position_size before ordering
An exit never triggersIts from_entry doesn't match the entry idUse the exact same id string
"The 'when' parameter is not supported"when = was removed in v6Wrap the call in an if block (see the error page)
Results change after switching to a smaller accountFractional quantities on contractsRound down for futures and stocks

To start from a full template, see the Pine Script strategy template (v6). The AI Pine Script error fixer explains and fixes compile errors in a pasted script.

Write it with Edgoro

Describe the entries, exits and sizing in plain English ("risk 1% per trade with a 2 ATR stop, reverse on the opposite signal, add once") and the Pine Script generator writes the strategy in v6, with the order commands chosen for you.

Code examples are for education and aren't trading advice. Backtest results don't guarantee future returns. Trading involves substantial risk of loss.

Frequently asked questions

What is the difference between strategy.entry and strategy.order?

strategy.entry() opens a position in one direction, respects the pyramiding limit and reverses an opposite position automatically. strategy.order() sends a plain order: it ignores pyramiding and only flips a position when its quantity is larger than the position.

Why does my strategy open double the size when it reverses?

strategy.entry() in the opposite direction closes the open position and opens the new one in a single order, so the order quantity is the position size plus the new quantity. You end up with the new quantity in the new direction.

What does pyramiding do in Pine Script?

It sets how many entries can stack in the same direction. The default of 0 allows a single entry; further strategy.entry() calls in that direction are ignored until the position closes.

How do I make a strategy long only?

Add strategy.risk.allow_entry_in(strategy.direction.long). Short entry signals then close the open long instead of opening a short position.

How do I size a Pine Script position by risk?

Compute qty = (strategy.equity × risk %) ÷ (stop distance × syminfo.pointvalue) and pass it as the qty argument of strategy.entry(). Round down for instruments that only trade whole contracts.

Build it with Edgoro

Describe your strategy in plain English and get a TradingView indicator in Pine Script v6 or a MetaTrader 5 Expert Advisor in minutes. Every first purchase is covered by a 7-day money-back guarantee.

Build your indicator with Edgoro