#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © millerrh
#strategy("Qullamaggie Breakout V2", overlay=true, initial_capital=100000, currency='USD', calc_on_every_tick = true,
# Converted by [email protected] - 01/2023
input PivotPrd = 3;
input showPivotPoints = no; # "Show Historical Pivot Points?"
input htf = AggregationPeriod.DAY; #"Timeframe of Moving Averages",
input maType = {default SMA, EMA}; # "Moving Average Type"
input ma1Length = 10; # "1st Moving Average: ???Length"
input ma2Length = 20; # "2nd Moving Average: ???Length"
input ma3Length = 50; # "3rd Moving Average: ???Length"
input useMaFilter = yes; # "Use 3rd Moving Average for Filtering?"
input trailMaInput = {default "1st Moving Average", "2nd Moving Average"}; # Trailing Stop
input trailMaTF = {default "Same as Moving Averages", "Same as Chart"};
input useAdrFilter = no; # "Use ADR for Filtering?"
input adrPerc = 120; # "% of ADR Value"
def na = Double.NaN;
def n = BarNumber();
def last = isNaN(close);
script nz {
input data = close;
input repl = 0;
def ret_val = if !IsNaN(data) then data else repl;
plot return = ret_val;
}
script fixnan {
input source = close;
def fix = if !IsNaN(source) then source else fix[1];
plot result = fix;
}
#barssince(Condition) =>
script barssince {
input Condition = 0;
def barssince = if Condition then 1 else barssince[1] + 1;
plot return = barssince;
}
script FindPivots {
input dat = close; # default data or study being evaluated
input HL = 0; # default high or low pivot designation, -1 low, +1 high
input lbL = 5; # default Pivot Lookback Left
input lbR = 1; # default Pivot Lookback Right
##############
def _nan; # used for non-number returns
def _BN; # the current barnumber
def _VStop; # confirms that the lookforward period continues the pivot trend
def _V; # the Value at the actual pivot point
##############
_BN = BarNumber();
_nan = Double.NaN;
_VStop = if !isNaN(dat) and lbr > 0 and lbl > 0 then
fold a = 1 to lbR + 1 with b=1 while b do
if HL > 0 then dat > GetValue(dat,-a) else dat < GetValue(dat,-a) else _nan;
if (HL > 0) {
_V = if _BN > lbL and dat == Highest(dat, lbL+1) and _VStop
then dat else _nan;
} else {
_V = if _BN > lbL and dat == Lowest(dat, lbL+1) and _VStop
then dat else _nan;
}
plot result = if !IsNaN(_V) and _VStop then _V else _nan;
}
def closeHtf = close(Period = htf);
def lowHtf = low(Period = htf);
def adrHigh = high(Period = AggregationPeriod.DAY);
def adrLow = low(Period = AggregationPeriod.DAY);
#// MA Calculations (can likely move this to a tuple for a single security call!!)
script ma {
input maType = "EMA";
input src = close;
input length = 10;
def ma = if maType == "EMA" then ExpAverage(src, length) else SimpleMovingAvg(src, length);
plot return = ma;
}
def ma1 = ma(maType, closeHtf, ma1Length);
def ma2 = ma(maType, closeHtf, ma2Length);
def ma3 = ma(maType, closeHtf, ma3Length);
plot mov1 = ma1;#, color=ma1Color, style=plot.style_line, title="MA1", linewidth=2)
mov1.SetDefaultColor(Color.MAGENTA);
plot mov2 = ma2;#, color=ma2Color, style=plot.style_line, title="MA2", linewidth=2)
mov2.SetDefaultColor(Color.YELLOW);
plot mov3 = ma3;#, color=ma3Color, style=plot.style_line, title="MA3", linewidth=2)
mov3.SetDefaultColor(Color.WHITE);
def adrValue = SimpleMovingAvg((adrHigh - adrLow)/ AbsValue(adrLow) * 100, 21);
def adrCompare = (adrPerc * adrValue) / 100;
def ph = findpivots(high, 1, PivotPrd, PivotPrd);
def pl = findpivots(low, -1, PivotPrd, PivotPrd);
#//Removes color when there is a change to ensure only the levels are shown (i.e. no diagonal lines connecting the levels)
def pvthis = fixnan(ph);
def pvtlos = fixnan(pl);
def hipc = if (pvthis-pvthis[1]) != 0 then 0 else 1;# color.new(color.maroon, 0);
def lopc = if (pvtlos-pvtlos[1]) != 0 then 0 else 1;# color.new(color.green, 0);
#// Display Pivot lines
plot TopLevels = if !showPivotPoints or !hipc or last then na else pvthis;# -lbHigh, title="Top Levels")
TopLevels.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
TopLevels.SetDefaultColor(Color.RED);
plot TopLevel2 = if !showPivotPoints or !hipc or last then na else pvthis[PivotPrd];#, "Top Levels 2")
TopLevel2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
TopLevel2.SetDefaultColor(Color.DARK_RED);
plot BottomLevels = if !showPivotPoints or !lopc or last then na else pvtlos;#offset=-lbLow, title="Bottom Levels")
BottomLevels.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BottomLevels.SetDefaultColor(Color.GREEN);
plot BottomLevel2 = if !showPivotPoints or !lopc or last then na else pvtlos[PivotPrd];# title="Bottom Levels 2")
BottomLevel2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BottomLevel2.SetDefaultColor(Color.DARK_GREEN);
#// BUY AND SELL CONDITIONS
def buyLevel = if !isNaN(ph) then high[PivotPrd] else buyLevel[1];# //Buy level at Swing High
#// Conditions for entry
def stopLevel;
def buyDif = buyLevel - stopLevel[1];
def buyConditions = (if useMaFilter then buyLevel > ma3 else yes) and
(if useAdrFilter then buyDif < adrCompare else yes);
def buySignal = if ((high > buyLevel) and buyConditions) then buySignal[1] + 1 else 0;
#// Trailing stop points - when price punctures the moving average, move stop to the low of that candle - Define as function/tuple to only use one security call
def trailMa = if trailMaInput == trailMaInput."1st Moving Average" then ma1 else ma2;
def crossLow = if trailMaTF == trailMaTF."Same as Moving Averages" then lowHtf else low;
def maCrossEvent = if (low < trailMa) then maCrossEvent[1] + 1 else 0;
def maCross = if maCrossEvent==1 then low else maCross[1];
def maCrossLevel = fixnan(maCross);
def maCrossPc = if (maCrossLevel - maCrossLevel[1]) != 0 then na else 1;#: color.new(color.blue, 0) //Removes color when there is a change to ensure only the levels are shown (i.e. no diagonal lines connecting the levels)
plot MaStopLevel = if !showPivotPoints or isNaN(maCrossPc) or last then na else maCrossLevel;#, color = maCrossPc, linewidth=1, offset=0, title="Ma Stop Levels")
MaStopLevel.SetDefaultColor(Color.CYAN);
addlabel(1 , lowHtf, Color.WHITE);
#// == STOP AND PRICE LEVELS ==
def stop;
def inPosition = buySignal>0;#buyConditions;
def position_avg_price = if buySignal==1 then close else position_avg_price[1];
def buyLevel1 = if inPosition then buyLevel else buyLevel1[1];
def stopDefine = if !isNaN(pl) then low[PivotPrd] else stopDefine[1];# //Stop Level at Swing Low
def inProfit = position_avg_price <= stopDefine[1];
stopLevel = if inPosition and !inProfit then stopDefine else
if inPosition and inProfit then stopLevel[1] else stopDefine;# // Trail stop loss until in profit
def trailStopLevel;# = float(na)
def notInPosition = stop[1];
def inPositionBars = barssince(notInPosition);
def maCrossBars = barssince(maCrossEvent);
def trailCross = inPositionBars > maCrossBars;
trailStopLevel = if inPosition and trailCross then maCrossLevel else na;
plot HistStopLevels = if !inPosition or stopLevel==0 then na else fixNaN(stopLevel);#, style=plot.style_linebr, color=colorStop, linewidth = 2, title = "Historical Stop Levels", trackprice=false)
HistStopLevels.SetDefaultColor(Color.BLUE);
plot HistTrailLevels = if inPosition then trailStopLevel else na;#, style=plot.style_linebr, color=colorTrail, linewidth
stop = if stopLevel > trailStopLevel then stopLevel else
if close[1] > trailStopLevel and close[1] > trailMa then trailStopLevel else stopLevel;
AddChartBubble(buySignal==1, low, "BUY", Color.GREEN, no);