Trading StrategyPine Script v5

TradingView MACD Crossover Strategy: Rules and Backtest Checks

This tutorial walks through an existing Pine Script v5 example: 12/26/9 MACD crossovers, an optional 200-period EMA price filter, and percentage profit/stop orders. The source is a starting point for inspection, not a verified profitable system. No reproducible performance result is supplied here; the checklist below shows what a test must record.

Define the crossover before testing it

MACD is the fast average minus the slow average. This example uses EMAs with lengths 12 and 26, then a 9-period EMA signal. The histogram is MACD minus signal.

  • A bullish crossover moves MACD from at or below signal to above it.
  • A bearish crossunder moves MACD from at or above signal to below it.
  • A histogram crossing zero is the same relationship changing sign; it is not an earlier independent signal.

Periods follow the chart interval, not necessarily days. A histogram value is a gap between averages, not the velocity of the underlying price. Crossovers can reverse quickly in ranges.

Sources: TradingView MACD definitions and TradingView strategy order and broker-emulator behavior.

ComponentDescriptionRole
MACD lineFast EMA minus slow EMAA difference in the source price’s units
Signal line9-period EMA of MACD by defaultComparison series for crossover rules
HistogramMACD minus signalPositive means MACD exceeds signal; negative means it is below
Price filterClose above/below a 200-period EMARestricts long/short entry eligibility; not a proven improvement

Pine Script v5 Implementation

Pine Script v5
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify_Official

//@version=5
strategy("MACD Crossover Pro Strategy - Pineify Optimized", 
     overlay=true, 
     initial_capital=10000, 
     default_qty_type=strategy.percent_of_equity, 
     default_qty_value=100,
     commission_type=strategy.commission.percent,
     commission_value=0.1)

// --- Input Parameters ---
// MACD Settings
fast_length = input.int(12, title="MACD Fast Length", minval=1, group="MACD Settings")
slow_length = input.int(26, title="MACD Slow Length", minval=1, group="MACD Settings")
signal_smoothing = input.int(9, title="Signal Line Smoothing", minval=1, group="MACD Settings")
src = input.source(close, title="Source", group="MACD Settings")

// Trend Filter Settings
use_ema_filter = input.bool(true, title="Use 200 EMA Filter?", group="Filters")
ema_filter_len = input.int(200, title="EMA Filter Length", minval=1, group="Filters")

// Risk Management Settings
tp_percent = input.float(5.0, title="Take Profit (%)", minval=0.1, step=0.1, group="Risk Management")
sl_percent = input.float(2.5, title="Stop Loss (%)", minval=0.1, step=0.1, group="Risk Management")

// --- Calculations ---
// MACD Calculation
[macdLine, signalLine, histLine] = ta.macd(src, fast_length, slow_length, signal_smoothing)

// Trend Filter Calculation
ema_filter = ta.ema(close, ema_filter_len)
is_uptrend = close > ema_filter
is_downtrend = close < ema_filter

// --- Entry & Exit Logic ---
// Long Entry: MACD Crossover + (Optional) Price above 200 EMA
longCondition = ta.crossover(macdLine, signalLine) and (not use_ema_filter or is_uptrend)

// Short Entry: MACD Crossunder + (Optional) Price below 200 EMA
shortCondition = ta.crossunder(macdLine, signalLine) and (not use_ema_filter or is_downtrend)

// --- Execution ---
if (longCondition)
    strategy.entry("Long", strategy.long, comment="Bullish Crossover")

if (shortCondition)
    strategy.entry("Short", strategy.short, comment="Bearish Crossover")

// Exit Logic: Fixed TP/SL
strategy.exit("Exit Long", "Long", limit=strategy.position_avg_price * (1 + tp_percent/100), stop=strategy.position_avg_price * (1 - sl_percent/100))
strategy.exit("Exit Short", "Short", limit=strategy.position_avg_price * (1 - tp_percent/100), stop=strategy.position_avg_price * (1 + sl_percent/100))

// --- Visuals ---
plot(use_ema_filter ? ema_filter : na, color=color.new(color.gray, 50), title="Trend Filter EMA")
plotshape(longCondition, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, title="Long Signal")
plotshape(shortCondition, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, title="Short Signal")

// Color the background based on the trend
bgcolor(use_ema_filter and is_uptrend ? color.new(color.green, 90) : use_ema_filter and is_downtrend ? color.new(color.red, 90) : na)

What the preserved example actually does

  1. 1

    Entry rules: a MACD/signal crossover permits a long when the optional price filter passes; a crossunder permits a short. Opposite strategy.entry orders can reverse an existing position. Signal markers are conditions, not confirmations of actual fills.

  2. 2

    Price filter: when enabled, long eligibility requires close above the filter EMA and short eligibility requires close below it. This can remove signals, but does not establish fewer losing trades or higher returns.

  3. 3

    Sizing and costs: initial capital is 10,000, default order size is 100% of equity and commission is 0.1% of traded value per filled order. The 2.5% stop is a price distance, not a guarantee that only 2.5% of account equity can be lost. Slippage is not configured in the source.

  4. 4

    Exit basis and timing: targets use strategy.position_avg_price, with default 5% profit and 2.5% stop distances. The script does not enable calc_on_order_fills or process_orders_on_close. From flat, average-price exits become available only after the entry fills and the strategy recalculates; do not assume the entry bar is protected by a bracket immediately.

  5. 5

    Version and settings: this example remains Pine v5. Its title contains “Pro” and “Optimized”, but those labels are not performance evidence. Confirm Properties overrides, margin settings, session, chart type and fill assumptions before comparing runs.

Backtest Assumptions and Metrics

The earlier BTC/USD 2022–2024 performance table had no reproducible export or complete test setup, so its return, win-rate, drawdown and ratio claims have been withdrawn. Use the following record before reporting any result from this example.

MetricValueInterpretation
Symbol and dataRecord before testingExchange-qualified ticker, feed, standard candles, bar interval, session and date range.
Inputs and propertiesRecord before testingMACD lengths, filter toggle/length, TP/SL, equity size, commission, slippage, margin and fill options.
Trade sequenceExport and inspectCheck signal time, next available entry fill, bracket creation, reversals and first-bar exposure.
Net return and drawdownNot established hereCalculate on one stated equity basis, including costs and open-trade treatment; compare the same test window.
Profit factor and win rateNot established hereRetain closed-trade count, gross profit/loss and cost convention; no loss denominator means profit factor is undefined.
Holdout and sensitivityRun separatelyKeep unseen dates untouched while selecting inputs, then inspect nearby parameters and different cost assumptions.

A single favorable run cannot identify a durable edge. Filters and exits can trade fewer losses for missed winners. Keep failed variants and test settings, and separate in-sample selection from holdout evaluation. This page has not validated profitability or executed these trades.

Use Pineify to inspect rules and results

Pineify’s coding tools can help draft or revise Pine Script rules. Review the generated source and reproduce the resulting trades in TradingView before treating a change as correct.

The Backtest Deep Report is an analysis workflow for strategy results. It is separate from running a new parameter search in TradingView and cannot repair invalid fill assumptions or establish future profitability. Check the current product workflow and account access before relying on a report.

Strategy Optimization Suggestions

1

Test one change at a time

Compare the filter on and off using identical dates and costs. Retain trade counts and missed winners as well as drawdown.

2

Separate higher-timeframe confirmation

If adding higher-timeframe data, specify when that value becomes available and test repainting. The preserved example does not contain this filter.

3

Make sizing a separate rule

ATR-based sizing is not present here. If added, define stop distance, contract units, rounding and fees rather than assuming constant monetary risk.

4

Do not add MACD values directly to price stops

MACD is an average difference, not a price level. A proposed trailing exit needs a price-based rule and activation behavior, then a separate test.

Frequently Asked Questions

No. This page provides inspectable rules and a test checklist, with no substantiated return or win-rate claim. Intraday use requires its own cost, execution and holdout analysis.

No. Histogram equals MACD minus signal, so crossing zero corresponds to the same crossing relationship. Histogram slope changes are different events and do not guarantee an earlier profitable entry.

No. It restricts eligibility by the close’s position relative to an EMA. Its effect on losing trades, missed trends and net results must be measured on the chosen sample.

Do not assume so. Coding, running a TradingView strategy, parameter search and analysis of exported results are separate steps. Confirm the current product workflow and supported inputs.

This page does not establish a best timeframe. Choose a bar interval that matches your intended holding period and data, then compare net results and trade counts without changing the holdout window to favor a result.

Review the rules before drawing conclusions

Use Pineify for code assistance and result analysis, then reconcile orders and metrics with the exact TradingView run. Neither a generated script nor a report guarantees live execution or returns.

Disclaimer: Trading involves significant risk. The strategies and code provided are for educational purposes only and do not constitute financial advice. Past performance is not indicative of future results.