Pine Script v6 Strategy Examples: Code, Rules, and Backtest Checks
A Pine Script strategy expresses trade rules and produces simulated orders in TradingView. This guide includes one moving-average code example and two additional rule specifications to test. It explains what the example actually does, which assumptions are missing, and how to record a reproducible run. No verified profit, win-rate, or drawdown result accompanies these examples.
What Changes in Pine Script v6
TradingView's v6 migration guide documents specific changes: division of constant integers can retain a fractional result, requests are dynamic by default, Boolean evaluation is lazy, and the default strategy margin is 100%. These changes can affect a migrated script's behavior.
Commission, slippage, pyramiding, and bracket exits are not newly invented v6 capabilities. Upgrading a version declaration does not validate a trading idea or eliminate repainting. Compare order lists before and after migration, including any changes to margin and exit parameters.
Example 1: Moving-Average Crossover
The retained example below is a long-only instructional strategy. Its default parameters are inputs for experimentation, not optimized settings for a named asset. Review it in the Pine Editor before relying on its output; this editorial revision does not include a new compiler run or a performance backtest.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//======================================================================//
// ____ _ _ __ //
// | _ \(_)_ __ ___(_)/ _|_ _ //
// | |_) | | '_ \ / _ \ | |_| | | | //
// | __/| | | | | __/ | _| |_| | //
// |_| |_|_| |_|\___|_|_| \__, | //
// |___/ //
//======================================================================//
//@version=6
strategy("Enhanced MA Crossover", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// User inputs for strategy customization
fastLength = input.int(9, title="Fast MA Length", minval=1)
slowLength = input.int(21, title="Slow MA Length", minval=1)
useStopLoss = input.bool(true, title="Use Stop Loss")
stopLossPercent = input.float(2.0, title="Stop Loss %", minval=0.1, maxval=10.0)
// Calculate moving averages
fastMA = ta.sma(close, fastLength)
slowMA = ta.sma(close, slowLength)
// Trend confirmation using longer-term MA
trendMA = ta.sma(close, 50)
bullishTrend = close > trendMA
// Entry conditions
longCondition = ta.crossover(fastMA, slowMA) and bullishTrend
shortCondition = ta.crossunder(fastMA, slowMA)
// Execute trades
if longCondition
strategy.entry("Long", strategy.long)
if useStopLoss
strategy.exit("Long Exit", "Long", stop=close * (1 - stopLossPercent / 100))
if shortCondition
strategy.close("Long")
// Visual elements
plot(fastMA, color=color.green, title="Fast MA", linewidth=2)
plot(slowMA, color=color.red, title="Slow MA", linewidth=2)
plot(trendMA, color=color.blue, title="Trend MA", linewidth=1)
// Signal markers
plotshape(longCondition, title="Buy Signal", location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small)
plotshape(shortCondition, title="Sell Signal", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small)
Read the Rules Before Reading the Equity Curve
| Part | Behavior in this example | Consequence to inspect |
|---|---|---|
| Entry | The 9-bar SMA crosses above the 21-bar SMA while close is above the 50-bar SMA | The filter and crossover must coincide on the signal bar |
| Normal exit | The fast SMA crosses below the slow SMA | Despite its name, shortCondition closes a long; it does not open a short |
| Optional stop | An exit stop is submitted from the entry signal bar's close | It is not calculated from the eventual fill price |
| Position size | The declaration requests 10% of equity | This is position notional, not 10% equity at risk |
| Markers | Shapes plot the entry and exit conditions | A marker is not proof of an executed order |
| Missing rules | No take-profit, session filter, or explicit test-date filter | Do not attribute these features to the example |
The stop is submitted inside the entry-condition block, not recalculated on every subsequent bar. With a 100 signal close and a 2% input, the requested stop price is 98. If the next fill is 101, the entry-to-stop distance is 3, not 2. A gap through the stop can also change the realized loss. This arithmetic explains why a stop input is not an account-loss guarantee.
TradingView's strategy documentation distinguishes order creation from execution in the broker emulator. Under default bar-close calculation, a market order is normally eligible to fill on the next tick, typically the next bar's open in a historical test. Inspect actual fills and the active execution settings rather than equating the signal close with the entry price.
Example 2: Specify an RSI Mean-Reversion Experiment
This is a rule design, not a second code listing or a tested result:
- Observe completed bars and calculate a 14-period RSI.
- Enter long when RSI crosses back above 30 after being at or below 30.
- Exit when RSI reaches or exceeds 50, or after a predefined maximum holding period, whichever happens first.
- Specify a protective exit and size calculation separately before any live use.
Choose the maximum holding period before comparing outcomes. Record how many candidate values were tried. Crossing back above a threshold differs from buying on every bar below it, and both differ from the crossover-plus-RSI condition used in some combined strategies.
The purpose of this experiment is to measure whether recovery from a low RSI reading has useful subsequent returns in the selected market. A threshold does not demonstrate that price must reverse.
Example 3: Specify a Breakout Experiment
A separate candidate could enter long after a completed close exceeds the highest high of the preceding 20 completed bars. Exclude the current bar from that comparison window. Define an exit, such as a close below the lowest low of the preceding 10 completed bars, before evaluating results.
Add a volume filter only as a separate recorded variant. Confirm what the feed's volume represents, and keep entry timing, position size, and transaction costs identical in the comparison. A better historical result after adding a filter may reflect selection rather than a repeatable improvement.
Reproduce a Backtest in TradingView
- Save the exact source and input values. Record the exchange-qualified symbol, timeframe, chart type, session, and price-adjustment settings.
- Use standard candles for the baseline and record the first and last observations actually evaluated. A requested date range and the available history may differ.
- Open strategy Properties and record starting capital, account currency, quantity mode, margin, commission, and slippage. The source example does not supply a broker-specific cost model.
- Review several trades from signal to fill to exit. Include at least one stop exit and one crossover exit if both occur. Reconcile their prices and quantities with the order list.
- Export the available trade results and save the settings beside them. If the platform cannot provide the intended date range, disclose that limitation rather than labeling the output a full-period test.
- Freeze the rule before evaluating a later holdout interval. Any change made after seeing that interval creates a new research iteration.
The strategy Properties reference explains commission modes and slippage in ticks. Commission applies to entries and exits; percentage-of-equity sizing describes order value. Use the actual instrument's units rather than copying a generic broker fee or treating allocation as stop-defined risk.
Compare Strategies with the Same Accounting
For a fixed-size trade sample, a useful diagnostic is:
Average net outcome = win fraction × average gross win − loss fraction × average gross loss − average round-trip cost
Use comparable currency units for wins, losses, and costs. If the trade results already include fees, do not subtract those fees again. This diagnostic does not replace a compounded equity curve when position sizes vary.
Compare net profit, drawdown, exposure, turnover, and trade count over identical intervals. A lower-return strategy may also spend much less time invested; a higher win rate may hide infrequent large losses. Report those differences before deciding that one example is better.
Repainting and Higher-Timeframe Data
The crossover example uses the chart's close and does not request another timeframe. If adding higher-timeframe data, review when that requested bar becomes final. A chart bar closing does not mean that a daily or weekly requested bar has also closed.
TradingView's repainting guide describes differences between historical and real-time calculations, including unconfirmed data and misleading lookahead. barstate.isconfirmed is not a universal remedy for all of these cases. Check data timing, reload behavior, and live signal logs for the specific implementation.
Frequently Asked Questions
Are these profitable Pine Script v6 strategies?
No verified performance result is supplied here. The code and rule designs are starting points for reproducible evaluation. Syntax acceptance, historical profit, and live performance are separate questions.
Does the crossover example open short positions?
No. Its shortCondition variable triggers a close of the Long entry. There is no short entry order in the listing.
Does a 2% stop mean 2% account risk?
No. The input sets a price distance from the signal close. Account exposure also depends on position size, the actual fill, contract value, and execution costs.
Can I build these rules visually?
A visual builder can help express supported indicators and conditions. Inspect the exported source and test its order behavior against the intended rule; the builder interface alone is not evidence of correctness or profitability.
