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.
//@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.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Source
source
close
src
Use price
bool
true
includePrice
Strict
bool
true
strictPrice
Max. width of price W/M
int
9
rangePrice
Max. offset of price W/M
int
0
offsetPrice
Use OBV
bool
true
includeOBV
Strict
bool
true
strictOBV
Max. width of OBV W/M
int
9
rangeOBV
Max. offset of OBV W/M
int
0
offsetOBV
Use Willy
bool
true
includeWly
Use Willy stupid
bool
false
includeWillyStupid
Strict
bool
true
strictWly
Show all 40 settings
Setting
Type
Default
Variable
Max. width of Willy W/M
int
9
rangeWly
Max. offset of Willy W/M
int
0
offsetWly
Willy length
int
21
lengthWly
Willy length ema
int
13
lengthWlyEma
Use MFI
bool
false
includeMFI
Strict
bool
true
strictMFI
Max. width of MFI W/M
int
9
rangeMFI
Max. offset of MFI W/M
int
0
offsetMFI
MFI length
int
14
lengthMFI
Use RSI
bool
false
includeRSI
Strict
bool
true
strictRSI
Max. width of RSI W/M
int
9
rangeRSI
Max. offset of RSI W/M
int
0
offsetRSI
RSI length
int
14
lengthRSI
Use DMI (DI+ & DI-)
bool
false
includeDMI
Strict
bool
true
strictDMI
Max. width of DMI W/M
int
9
rangeDMI
Max. offset of DMI W/M
int
0
offsetDMI
DMI length
int
14
lengthDMI
Price within RLZ
bool
false
includeWithinRLZ
Price above/below RLZ
bool
false
includeBelowRLZ
Upper bound of RLZ (fib)
float
61.8
upperBoundRLZ
Lower bound of RLZ (fib)
float
78.6
lowerBoundRLZ
Lookback period (bars)
int
200
lengthPeriodRLZ
Price above/below SMA
bool
false
includeSMA
SMA length
int
20
lengthSMA
Limit period (increases performance)
bool
true
limitPeriod
Length of period (hours)
int
240
lengthPeriod
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.
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
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
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
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
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
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