Strategy · Pine Script v4 · On the chart

Davo Strategy

by GreyssonEnterprises

A strategy version of a W and M pattern detector that looks for five-point double-bottom and double-top shapes in price, on-balance volume and optionally Williams %R, MFI, RSI and directional movement.

View on GitHub

GitHub stars1on the repository
Pine versionv4older, still runs
Lines of code409
Settings40inputs
LicenceMIT
Last update2 months ago1 Aug 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

409 lines of Pine Script v4 from strategies/davo/pinescript/strategy.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

strategy.pine
//@version=4
//Davo Strategy - Trading Strategy
strategy(title="Davo Strategy", shorttitle="Davo Strategy", overlay=true, precision=8, max_bars_back=500)

// ################################################################################################################################################################
// General info and acknowledgements
// ################################################################################################################################################################
// Author: maqpie (a.k.a sanne)
// Date: 4th of December 2016
// Adapted for Grimm Trading Systems
// 
// This script is based upon Davinci's dav-o meter and his original script, which searches for W's and M's in price, OBV, RSI and/or Willy.
// Although the original script is elegant, a W or M has to occur within 5 bars. 
// However, often what you will see is that a W or M forms over more than 5 bars.
// This script tries to remove that limit.
// 
// Strategy Implementation: Full backtesting with position management and risk controls
// 
// ################################################################################################################################################################
// How it works
// ################################################################################################################################################################
//
// Now, trading is more of an art form than a science and this indicator is no exception.
// When talking about M's and W's, it begs the question: what exactly counts as a W or M?
// My personal experience is that for a W to count as such, it has to adhere to the following rules:
//  
//      1. A 'W'  has 5 points, A, B, C, D and E                                E
//      2. Point A can be any point                                        C   /
//      3. Point B should be lower than A                             A   / \ /
//      4. Point C should be higher than B                             \ /   D
//      5. Point D should be lower than C, but higher than B            B
//      6. Point E should be higher than C
//
//      1. A 'M'  has 5 points, A, B, C, D and E                        B
//      2. Point A can be any point                                    / \   D
//      3. Point B should be higher than A                            A   \ / \
//      4. Point C should be lower than B                                  C   \
//      5. Point D should be higher than C, but lower than B                    E
//      6. Point E should be lower than C
//
// ######################################################################################################################################################################################################

src = input(title="Source", type=input.source, defval=close)

// Pattern Detection Settings
includePrice = input(defval=true, title="Use price")
strictPrice = input(defval=true, title="Strict")
rangePrice = input(9, minval=5, title="Max. width of price W/M")
offsetPrice = input(0, minval=0, title="Max. offset of price W/M")

includeOBV = input(defval=true, title="Use OBV")
strictOBV = input(defval=true, title="Strict")
rangeOBV = input(9, minval=5, title="Max. width of OBV W/M")
offsetOBV = input(0, minval=0, title="Max. offset of OBV W/M")

includeWly = input(defval=true, title="Use Willy")
includeWillyStupid = input(defval=false, title="Use Willy stupid")
strictWly = input(defval=true, title="Strict")
rangeWly = input(9, minval=5, title="Max. width of Willy W/M")
offsetWly = input(0, minval=0, title="Max. offset of Willy W/M")
lengthWly = input(21, minval=1, title="Willy length")
lengthWlyEma = input(13, minval=1, title="Willy length ema")

includeMFI = input(defval=false, title="Use MFI")
strictMFI = input(defval=true, title="Strict")
rangeMFI = input(9, minval=5, title="Max. width of MFI W/M")
offsetMFI = input(0, minval=0, title="Max. offset of MFI W/M")
lengthMFI = input(14, minval=1, title="MFI length")

includeRSI = input(defval=false, title="Use RSI")
strictRSI = input(defval=true, title="Strict")
rangeRSI = input(9, minval=5, title="Max. width of RSI W/M")
offsetRSI = input(0, minval=0, title="Max. offset of RSI W/M")
lengthRSI = input(14, minval=1, title="RSI length")

includeDMI = input(defval=false, title="Use DMI (DI+ & DI-)")
strictDMI = input(defval=true, title="Strict")
rangeDMI = input(9, minval=5, title="Max. width of DMI W/M")
offsetDMI = input(0, minval=0, title="Max. offset of DMI W/M")
lengthDMI = input(14, minval=1, title="DMI length")

// RLZ Settings
includeWithinRLZ = input(defval=false, title="Price within RLZ")
includeBelowRLZ = input(defval=false, title="Price above/below RLZ")
upperBoundRLZ = input(defval=61.8, minval=0.0, maxval=100.0, title="Upper bound of RLZ (fib)")
lowerBoundRLZ = input(defval=78.6, minval=0.0, maxval=100.0, title="Lower bound of RLZ (fib)")
lengthPeriodRLZ = input(defval=200, minval=5, title="Lookback period (bars)")

includeSMA = input(defval=false, title="Price above/below SMA")
lengthSMA = input(20, minval=1, title="SMA length")

// Session filtering
limitPeriod = input(defval=true, title="Limit period (increases performance)")
lengthPeriod = input(240, minval=1, title="Length of period (hours)")

// Risk Management
stopLossPercentage = input(defval=0.01, minval=0, maxval=100, step=0.01, title="Stop loss %")
riskRewardRatio = input(defval=2.0, minval=0.0, title="Risk to Reward 1-to-")

// Strategy Settings
initialCapital = input(defval=10000, title="Initial Capital")
riskPerTrade = input(defval=0.01, minval=0.001, maxval=0.1, step=0.001, title="Risk per trade (% of capital)")
maxPositions = input(defval=1, minval=1, maxval=10, title="Max concurrent positions")

// Time filtering
hours_in_milliseconds = 1000 * 60 * 60
withinPeriod = not limitPeriod or timenow - time < hours_in_milliseconds * lengthPeriod

// Indicator calculations
change_1 = change(src)
OBVs = cum(change(src) > 0 ? volume : change_1 < 0 ? -volume : 0 * volume)

// Calculate MFI series
upper_s = sum(volume * (change(hlc3) <= 0 ? 0 : hlc3), lengthMFI)
lower_s = sum(volume * (change(hlc3) >= 0 ? 0 : hlc3), lengthMFI)
MFIs = rsi(upper_s, lower_s)

RSIs = rsi(lengthRSI, src)
SMAs = sma(src, lengthSMA)

// Williams %R calculation
upperWly = highest(lengthWly)
lowerWly = lowest(lengthWly)
WLYs = 100 * (src - upperWly) / (upperWly - lowerWly)
emaWly = ema(WLYs, lengthWlyEma)

// RLZ calculations
ATH = highest(high, lengthPeriodRLZ)
ATL = lowest(low, lengthPeriodRLZ)
range = ATH - ATL

longUpperRLZ = (1 - upperBoundRLZ / 100) * range + ATL
longLowerRLZ = (1 - lowerBoundRLZ / 100) * range + ATL
longWithinRLZ = longUpperRLZ >= src and src >= longLowerRLZ
longBelowRLZ = longLowerRLZ > src

shortUpperRLZ = ATH - (1 - upperBoundRLZ / 100) * range
shortLowerRLZ = ATH - (1 - lowerBoundRLZ / 100) * range
shortWithinRLZ = shortUpperRLZ <= src and src <= shortLowerRLZ
shortAboveRLZ = shortLowerRLZ < src

// Series comparison functions
series_a_above_series_b(seriesA, seriesB, aRange) =>
    result = true
    for i = 0 to aRange - 1 by 1
        if seriesB[i] > seriesA[i]
            result := false
            break
    result := result
    result

series_a_below_series_b(seriesA, seriesB, aRange) =>
    result = true
    for i = 0 to aRange - 1 by 1
        if seriesB[i] < seriesA[i]
            result := false
            break
    result := result
    result

// DMI calculation
dirmov(len) =>
    up = change(high)
    down = -change(low)
    truerange = rma(tr, len)
    plus = fixnan(100 * rma(up > down and up > 0 ? up : 0, len) / truerange)
    minus = fixnan(100 * rma(down > up and down > 0 ? down : 0, len) / truerange)
    [plus, minus]

// W Pattern Detection
data_W(aSeries, aRange, anOffset, strict) =>
    e = 0
    d = 0
    c = 0
    b = 0
    a = 0
    valueE = aSeries[0]
    valueD = aSeries[0]
    valueC = aSeries[0]
    valueB = aSeries[0]
    valueA = aSeries[0]
    found = false

    for offset = 0 to anOffset by 1
        if found
            break
        e := 0
        d := 0
        c := 0
        b := 0
        a := 0
        valueE := aSeries[0]
        valueC := aSeries[0]
        valueD := aSeries[0]
        valueB := aSeries[0]
        valueA := aSeries[0]

        for i = 1 to aRange - 1 by 1
            // find d
            if aSeries[i + offset] < aSeries[i + offset - 1] and valueC == aSeries[0]
                d := i + offset
                valueD := aSeries[i + offset]
                continue
            if d == 0
                break
            // find c
            if aSeries[i + offset] > aSeries[i + offset - 1] and valueB == aSeries[0]
                c := i + offset
                valueC := aSeries[i + offset]
                continue
            if c == 0
                break
            if aSeries[i + offset] < aSeries[i + offset - 1] and valueA == aSeries[0]
                b := i + offset
                valueB := aSeries[i + offset]
                continue
            if b == 0
                break
            if aSeries[i + offset] > aSeries[i + offset - 1]
                a := i + offset
                valueA := aSeries[i + offset]
                continue
            if a == 0
                break
        // W found if we have found point A, and point B has a lower value than point D                
        found := a > 0 and a != b and c != 0 and d != 0 and aSeries[e] > aSeries[c] and 
           aSeries[d] < aSeries[e] and aSeries[d] < aSeries[c] and 
           (aSeries[b] <= aSeries[d] or not strict) and aSeries[b] < aSeries[a]
        found
    entry = found ? aSeries[c] : na
    stopLoss = found ? aSeries[b] * ((100 - stopLossPercentage) / 100) : na
    target = found ? entry + (entry - stopLoss) * riskRewardRatio : na
    [found, entry, stopLoss, target, a, b, c, d, e]

// M Pattern Detection
data_M(aSeries, aRange, anOffset, strict) =>
    e = 0
    d = 0
    c = 0
    b = 0
    a = 0
    valueE = aSeries[0]
    valueD = aSeries[0]
    valueC = aSeries[0]
    valueB = aSeries[0]
    valueA = aSeries[0]
    found = false

    for offset = 0 to anOffset by 1
        if found
            break
        e := 0
        d := 0
        c := 0
        b := 0
        a := 0
        valueE := aSeries[0]
        valueC := aSeries[0]
        valueD := aSeries[0]
        valueB := aSeries[0]
        valueA := aSeries[0]

        for i = 1 to aRange - 1 by 1
            // find d
            if aSeries[i + offset] > aSeries[i + offset - 1] and valueC == aSeries[0]
                d := i + offset
                valueD := aSeries[i + offset]
                continue
            if d == 0
                break
            // find c
            if aSeries[i + offset] < aSeries[i + offset - 1] and valueB == aSeries[0]
                c := i + offset
                valueC := aSeries[i + offset]
                continue
            if c == 0
                break
            if aSeries[i + offset] > aSeries[i + offset - 1] and valueA == aSeries[0]
                b := i + offset
                valueB := aSeries[i + offset]
                continue
            if b == 0
                break
            if aSeries[i + offset] < aSeries[i + offset - 1]
                a := i + offset
                valueA := aSeries[i + offset]
                continue
            if a == 0
                break
        // M found if we have found point A, and point B has a greater value than point D                
        found := a > 0 and a != b and c != 0 and d != 0 and aSeries[e] < aSeries[c] and 
           aSeries[d] > aSeries[e] and aSeries[d] > aSeries[c] and 
           (aSeries[b] >= aSeries[d] or not strict) and aSeries[b] > aSeries[a]
        found
    entry = found ? aSeries[c] : na
    stopLoss = found ? aSeries[b] * ((100 + stopLossPercentage) / 100) : na
    target = found ? entry - (stopLoss - entry) * riskRewardRatio : na
    [found, entry, stopLoss, target, a, b, c, d, e]

// Helper functions
find_W(aSeries, aRange, anOffset, strict) =>
    [found, entry, stopLoss, target, a, b, c, d, e] = data_W(aSeries, aRange, anOffset, strict)
    found

find_M(aSeries, aRange, anOffset, strict) =>
    [found, entry, stopLoss, target, a, b, c, d, e] = data_M(aSeries, aRange, anOffset, strict)
    found

// Direction Movement Index
[DIplus, DIminus] = dirmov(lengthDMI)

// Calculate if price is below/above SMA
HighAboveSMA = includeSMA == false or series_a_above_series_b(high, SMAs, rangePrice)
LowBelowSMA = includeSMA == false or series_a_below_series_b(low, SMAs, rangePrice)

// Pattern confirmations
[W_found, W_entry, W_stopLoss, W_target, W_pointA, W_pointB, W_pointC, W_pointD, W_pointE] = data_W(src, rangePrice, offsetPrice, strictPrice)
[M_found, M_entry, M_stopLoss, M_target, M_pointA, M_pointB, M_pointC, M_pointD, M_pointE] = data_M(src, rangePrice, offsetPrice, strictPrice)

priceW = includePrice == false or W_found
priceM = includePrice == false or M_found

OBVw = includeOBV == false or find_W(OBVs, rangeOBV, offsetOBV, strictOBV)
OBVm = includeOBV == false or find_M(OBVs, rangeOBV, offsetOBV, strictOBV)

MFIw = includeMFI == false or find_W(MFIs, rangeMFI, offsetMFI, strictMFI)
MFIm = includeMFI == false or find_M(MFIs, rangeMFI, offsetMFI, strictMFI)

// RSI patterns (inverted logic)
RSIw = includeRSI == false or find_M(RSIs, rangeRSI, offsetRSI, strictRSI)
RSIm = includeRSI == false or find_W(RSIs, rangeRSI, offsetRSI, strictRSI)

Wlyw = includeWly == false or find_W(WLYs, rangeWly, offsetWly, strictWly)
Wlym = includeWly == false or find_M(WLYs, rangeWly, offsetWly, strictWly)

DMIw = includeDMI == false or find_W(DIplus, rangeDMI, offsetDMI, strictDMI) and find_M(DIminus, rangeDMI, offsetDMI, strictDMI)
DMIm = includeDMI == false or find_M(DIplus, rangeDMI, offsetDMI, strictDMI) and find_W(DIminus, rangeDMI, offsetDMI, strictDMI)

// RLZ filters
RLZw = includeWithinRLZ == false and includeBelowRLZ == false or 
   includeWithinRLZ == true and longWithinRLZ or 
   includeBelowRLZ == true and longBelowRLZ

RLZm = includeWithinRLZ == false and includeBelowRLZ == false or 
   includeWithinRLZ == true and shortWithinRLZ or 
   includeBelowRLZ == true and shortAboveRLZ

// Trading conditions
longCondition = LowBelowSMA and priceW and OBVw and MFIw and RSIw and Wlyw and DMIw and 
   withinPeriod and (includeWillyStupid == false or emaWly < -80) and RLZw

shortCondition = HighAboveSMA and priceM and OBVm and MFIm and RSIm and Wlym and DMIm and 
   withinPeriod and (includeWillyStupid == false or emaWly > -20) and RLZm

// Position sizing calculation
calculatePositionSize(entryPrice, stopPrice, riskAmount) =>
    if na(entryPrice) or na(stopPrice) or entryPrice == stopPrice
        0
    else
        riskPerPoint = abs(entryPrice - stopPrice)
        positionSize = riskAmount / riskPerPoint
        positionSize

// Risk management
accountValue = strategy.initial_capital + strategy.netprofit
riskAmount = accountValue * riskPerTrade

// Long strategy logic
if longCondition and not longCondition[1] and strategy.position_size == 0
    entryPrice = close
    stopPrice = W_stopLoss
    positionSize = calculatePositionSize(entryPrice, stopPrice, riskAmount)
    
    if positionSize > 0
        strategy.entry("Long", strategy.long, qty=positionSize)
        strategy.exit("Long Exit", "Long", stop=stopPrice, limit=W_target)

// Short strategy logic
if shortCondition and not shortCondition[1] and strategy.position_size == 0
    entryPrice = close
    stopPrice = M_stopLoss
    positionSize = calculatePositionSize(entryPrice, stopPrice, riskAmount)
    
    if positionSize > 0
        strategy.entry("Short", strategy.short, qty=positionSize)
        strategy.exit("Short Exit", "Short", stop=stopPrice, limit=M_target)

// Plot signals
plotshape(longCondition and not longCondition[1], title="Davo Long", style=shape.triangleup, location=location.belowbar, color=color.lime, text="LONG")
plotshape(shortCondition and not shortCondition[1], title="Davo Short", style=shape.triangledown, location=location.abovebar, color=color.red, text="SHORT")

// Plot entry and exit levels
plot(strategy.position_size > 0 ? strategy.position_avg_price : na, title="Entry Price", color=color.white, linewidth=2)
plot(strategy.position_size > 0 and longCondition[1] ? W_stopLoss : na, title="Long Stop", color=color.red, linewidth=1)
plot(strategy.position_size > 0 and longCondition[1] ? W_target : na, title="Long Target", color=color.lime, linewidth=1)
plot(strategy.position_size < 0 and shortCondition[1] ? M_stopLoss : na, title="Short Stop", color=color.red, linewidth=1)
plot(strategy.position_size < 0 and shortCondition[1] ? M_target : na, title="Short Target", color=color.lime, linewidth=1)

// Alerts
alertcondition(longCondition and not longCondition[1], title="Davo Long Alert", message="Davo Long Signal - Entry: {{close}}, Stop: {{plot_01}}, Target: {{plot_02}}")
alertcondition(shortCondition and not shortCondition[1], title="Davo Short Alert", message="Davo Short Signal - Entry: {{close}}, Stop: {{plot_01}}, Target: {{plot_02}}")

// Performance metrics
if barstate.islast
    runtime.error("Strategy Performance: " + 
        "Total Trades: " + str.tostring(strategy.closedtrades) + 
        " | Win Rate: " + str.tostring(strategy.wintrades / strategy.closedtrades * 100, "#.##") + "%" +
        " | Net Profit: $" + str.tostring(strategy.netprofit, "#.##") +
        " | Max Drawdown: $" + str.tostring(strategy.max_drawdown, "#.##"))

Overview

Each source has strict matching, maximum width and offset settings, and patterns may span more than five bars. The supplied code is cut off before the order rules, so entry, exit, stop and sizing details are not visible. It draws on the price chart.

Details

Published by

GreyssonEnterprises on GitHub

Type

Strategy, Pine Script v4

Draws

On the price chart

Category

Oscillators & momentum, Divergence

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Sourcesourceclosesrc
Use pricebooltrueincludePrice
StrictbooltruestrictPrice
Max. width of price W/Mint9rangePrice
Max. offset of price W/Mint0offsetPrice
Use OBVbooltrueincludeOBV
StrictbooltruestrictOBV
Max. width of OBV W/Mint9rangeOBV
Max. offset of OBV W/Mint0offsetOBV
Use WillybooltrueincludeWly
Use Willy stupidboolfalseincludeWillyStupid
StrictbooltruestrictWly
Show all 40 settings
SettingTypeDefaultVariable
Max. width of Willy W/Mint9rangeWly
Max. offset of Willy W/Mint0offsetWly
Willy lengthint21lengthWly
Willy length emaint13lengthWlyEma
Use MFIboolfalseincludeMFI
StrictbooltruestrictMFI
Max. width of MFI W/Mint9rangeMFI
Max. offset of MFI W/Mint0offsetMFI
MFI lengthint14lengthMFI
Use RSIboolfalseincludeRSI
StrictbooltruestrictRSI
Max. width of RSI W/Mint9rangeRSI
Max. offset of RSI W/Mint0offsetRSI
RSI lengthint14lengthRSI
Use DMI (DI+ & DI-)boolfalseincludeDMI
StrictbooltruestrictDMI
Max. width of DMI W/Mint9rangeDMI
Max. offset of DMI W/Mint0offsetDMI
DMI lengthint14lengthDMI
Price within RLZboolfalseincludeWithinRLZ
Price above/below RLZboolfalseincludeBelowRLZ
Upper bound of RLZ (fib)float61.8upperBoundRLZ
Lower bound of RLZ (fib)float78.6lowerBoundRLZ
Lookback period (bars)int200lengthPeriodRLZ
Price above/below SMAboolfalseincludeSMA
SMA lengthint20lengthSMA
Limit period (increases performance)booltruelimitPeriod
Length of period (hours)int240lengthPeriod
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

ETH_buy_3commas

by hasnocool
106 stars

This strategy overlays a Cipher B style WaveTrend study on the price chart and is titled for Ethereum buy alerts aimed at 3Commas. It calculates a WaveTrend channel and a short moving average, and can mark buy, sell, gold, and divergence dots. Settings change

Strategy v4 Oscillators & momentumDivergence
Updated 2 years ago · GPL-3.0 GitHub repository of ETH_buy_3commas
24 stars

This overlay strategy combines a Cipher B WaveTrend oscillator with two optional moving averages on the price chart. It exposes WaveTrend channel and average lengths, overbought and oversold levels, buy, sell and gold dots, and regular or hidden divergence mar

Strategy v5 Oscillators & momentumMoving averages
Updated 4 years ago · MPL-2.0 GitHub repository of Cipher B + EMAs Strategy

Divergenced A002

by ruckard
13 stars

Divergenced A002 is a momentum divergence strategy designed to identify entry opportunities using Squeeze Momentum Indicator shifts alongside price action. It enters long when momentum reaches higher lows during lower price lows and enters short on opposite di

Strategy v5 Oscillators & momentumDivergence
Updated 1 year ago · None stated GitHub repository of Divergenced A002

RSI Divergence

by muammeryldrm42
7 stars

This strategy detects bullish and bearish RSI divergences using price and RSI pivot points. A bullish divergence triggers a long entry when price forms a lower low while RSI forms a higher low below 40. A bearish divergence triggers a short entry when price fo

Strategy v5 Oscillators & momentumDivergence
Updated 3 months ago · MIT GitHub repository of RSI Divergence

This strategy executes long positions by combining a 200-period EMA trend filter, Stochastic RSI oversold crosses, and Williams Alligator retracements, supplemented by RSI divergence detection. It triggers long entries when the price trades above the 200 EMA w

Strategy v4 TrendOscillators & momentum
Updated 3 years ago · Apache-2.0 GitHub repository of 200 EMA + Alligator + Stochastic Long Strategy
4 stars

Divergence Strategy scans multiple technical oscillators to detect regular and hidden divergences against price action. It evaluates customizable indicators including MACD, RSI, Stochastic, CCI, Momentum, OBV, and Money Flow Index to trigger strategy entries o

Strategy v4 DivergenceOscillators & momentum
Updated 4 years ago · None stated GitHub repository of Divergence Strategy

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers