#### JoeDV

##### Member

**Smoothed Heikin-Ashi with ATR Trail + P/L (Study)**

I put this in Strategies since it's a study that has the P/L built in. It's a combination of things I've found on here over the years (so if you were the original author, just let me know and I'll give credit). It combines a smoothed Heikin-Ashi with an ATR Trail to come up with the buy/sell signals. Not saying it works well or not, just putting it here if someone wants to play around with it. I swing trade so have really only looked at it on a daily timeframe. I'm guessing it would be too slow for day-trading, though you might be able to tweak the settings to make it work.

Ruby:

```
#hint: Smoothed Heiken Ashi and ATR studies
input period = 20;
input hideCandles = no;
input candleSmoothing = {default Valcu, Vervoort};
input movingAverageType = {Simple, default Exponential, Weighted, Hull, Variable, TEMA};
def openMA;
def closeMA;
def highMA;
def lowMA;
switch (movingAverageType) {
case Simple:
openMA = compoundValue(1, Average(open, period), open);
closeMA = compoundValue(1, Average(close, period), close);
highMA = compoundValue(1, Average(high, period), high);
lowMA = compoundValue(1, Average(low, period), low);
case Exponential:
openMA = compoundValue(1, ExpAverage(open, period), open);
closeMA = compoundValue(1, ExpAverage(close, period), close);
highMA = compoundValue(1, ExpAverage(high, period), high);
lowMA = compoundValue(1, ExpAverage(low, period), low);
case Weighted:
openMA = compoundValue(1, WMA(open, period), open);
closeMA = compoundValue(1, WMA(close, period), close);
highMA = compoundValue(1, WMA(high, period), high);
lowMA = compoundValue(1, WMA(low, period), low);
Case Hull:
openMA = compoundValue(1, HullMovingAvg(open, period), open);
closeMA = compoundValue(1, HullMovingAvg(close, period), close);
highMA = compoundValue(1, HullMovingAvg(high, period), high);
lowMA = compoundValue(1, HullMovingAvg(low, period), low);
case variable:
openMA = compoundValue(1, VariableMA(open, period), open);
closeMA = compoundValue(1, VariableMA(close, period), close);
highMA = compoundValue(1, VariableMA(high, period), high);
lowMA = compoundValue(1, VariableMA(low, period), low);
case TEMA:
openMA = compoundValue(1, TEMA(open, period), open);
closeMA = compoundValue(1, TEMA(close, period), close);
highMA = compoundValue(1, TEMA(high, period), high);
lowMA = compoundValue(1, TEMA(low, period), low);
}
hidePricePlot(hideCandles);
def haOpen;
def haClose;
switch(candleSmoothing) {
case Valcu:
haOpen = CompoundValue(1, ( (haOpen[1] + (openMA[1] + highMA[1] + lowMA[1] + closeMA[1]) /4.0)/2.0), open);
haClose = ((OpenMA + HighMA + LowMA + CloseMA)/4.0) ;
case Vervoort:
haOpen = CompoundValue(1, ( (haOpen[1] + (openMA[1] + highMA[1] + lowMA[1] + closeMA[1]) /4.0)/2.0), open);
haClose = ((((OpenMA + HighMA + LowMA + CloseMA)/4.0) + haOpen + Max(HighMA, haOpen) + Min(LowMA, haOpen))/4.0);
}
plot o = haOpen + 0;
o.hide();
### Wicks and Shadows
def haLow = min(lowMA, haOpen);
def haHigh = max(highMA,haOpen);
#Red Candlesticks -----------------------------------------------------------------|
def haOpen_fall = if haOpen>haClose
then haOpen
else double.nan;
def haHigh_fall = if haOpen>=haClose
then haHigh
else double.nan;
def haLow_fall = if haOpen>=haClose
then haLow
else double.nan;
def haClose_fall = if haOpen>=haClose
then haClose
else double.nan;
AddChart(growColor = Color.plum, fallColor = Color.blue, neutralColor = Color.current, high = haHigh_fall, low = haLow_fall, open = haOpen_fall, close = haClose_fall , type = ChartType.CANDLE);
def haOpen_rise = if haOpen<haClose
then haClose
else double.nan;
def haHigh_rise = if haOpen<=haClose
then haHigh
else double.nan;
def haLow_rise = if haOpen<=haClose
then haLow
else double.nan;
def haClose_rise = if haOpen<=haClose
then haOpen
else double.nan;
AddChart(growColor = Color.blue, fallColor = Color.plum, neutralColor = Color.current, high = haHigh_rise, low = haLow_rise, open = haOpen_rise, close = HAclose_rise, type = ChartType.CANDLE);
#############################################################################
#############################################################
### Determine a flat market
#############################################################
input TradeInFlatRange = Yes;
input BarsForFlatRange = 15;
input BarsReqToStayInRange = 13;
def HH = Highest(high[1], BarsForFlatRange);
def LL = Lowest(low[1], BarsForFlatRange);
def maxH = Highest(HH, BarsReqToStayInRange);
def maxL = Lowest(LL, BarsReqToStayInRange);
def HHn = if maxH == maxH[1] or maxL == maxL then maxH else HHn[1];
def LLn = if maxH == maxH[1] or maxL == maxL then maxL else LLn[1];
def Bh = if high <= HHn and HHn == HHn[1] then HHn else Double.NaN;
def Bl = if low >= LLn and LLn == LLn[1] then LLn else Double.NaN;
def CountH = if IsNaN(Bh) or IsNaN(Bl) then 2 else CountH[1] + 1;
def CountL = if IsNaN(Bh) or IsNaN(Bl) then 2 else CountL[1] + 1;
def ExpH = if BarNumber() == 1 then Double.NaN else
if CountH[-BarsReqToStayInRange] >= BarsReqToStayInRange then HHn[-BarsReqToStayInRange] else
if high <= ExpH[1] then ExpH[1] else Double.NaN;
def ExpL = if BarNumber() == 1 then Double.NaN else
if CountL[-BarsReqToStayInRange] >= BarsReqToStayInRange then LLn[-BarsReqToStayInRange] else
if low >= ExpL[1] then ExpL[1] else Double.NaN;
plot BoxHigh = if !isnan(expL) and !isnan(ExpH) then ExpH else double.nan;
plot BoxLow = if !isnan(expL) and !isnan(ExpH) then ExpL else double.nan;
addcloud( BoxHigh, BoxLow, color.gray, color.gray);
def Flat = if (!isNan(BoxHigh[1]) and !isNan(BoxLow[1])) AND !TradeInFlatRange then 1 else 0;
#addChartBubble(Flat==1 and isNan(Flat[1]),BoxHigh[1],"Flat Market",color.gray,yes);
input trailType = {default modified, unmodified};
input ATRPeriod = 5;
input ATRFactor = 3.0;
input firstTrade = {default long, short};
input averageType = AverageType.WILDERS;
Assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);
def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
then high - close[1]
else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
then close[1] - low
else (close[1] - low) - 0.5 * (low[1] - high);
def trueRange;
switch (trailType) {
case modified:
trueRange = Max(HiLo, Max(HRef, LRef));
case unmodified:
trueRange = TrueRange(high, close, low);
}
def loss = ATRFactor * MovingAverage(averageType, trueRange, ATRPeriod);
def state = {default init, long, short};
def trail;
switch (state[1]) {
case init:
if (!IsNaN(loss)) {
switch (firstTrade) {
case long:
state = state.long;
trail = close - loss;
case short:
state = state.short;
trail = close + loss;
}
} else {
state = state.init;
trail = Double.NaN;
}
case long:
if (close > trail[1]) {
state = state.long;
trail = Max(trail[1], close - loss);
} else {
state = state.short;
trail = close + loss;
}
case short:
if (close < trail[1]) {
state = state.short;
trail = Min(trail[1], close + loss);
} else {
state = state.long;
trail = close - loss;
}
}
#def BuySignal = Crosses(state == state.long, 0, CrossingDirection.ABOVE);
#def SellSignal = Crosses(state == state.short, 0, CrossingDirection.ABOVE);
plot TrailingStop = trail;
TrailingStop.SetPaintingStrategy(PaintingStrategy.line);
TrailingStop.DefineColor("Buy", color.blue);
TrailingStop.DefineColor("Sell", color.plum);
TrailingStop.AssignValueColor(if state == state.long
then TrailingStop.Color("Buy")
else TrailingStop.Color("Sell"));
############################################
## Define BuySignal and SellSignal above
## or uncomment them out below and set
## them to your buy/sell conditions
##
## If using stops, define them below
############################################
###------------------------------------------------------------------------------------------
input showSignals = yes;
input showLabels = yes;
input showBubbles = yes;
input useStops = no;
input useAlerts = no;
###------------------------------------------------------------------------------------------
############################################
## Create Signals -
## FILL IN THIS SECTION IF NOT DEFINED ABOVE
##
############################################
def BuySignal = state == state.long AND (haOpen < haClose) and (haOpen[1] < haClose[1]) and !Flat ; # insert condition to create long position
def SellSignal = state == state.short AND (haOpen > haClose) and (haOpen[1] > haClose[1]) and !Flat; # insert condition to create short position
def BuyStop = if !useStops then 0 else if state == state.long AND (haOpen > haClose) and Flat then 1 else 0 ; # insert condition to stop in place of the 0<0
def SellStop = if !useStops then 0 else if state == state.short AND (haOpen < haClose) and Flat then 1 else 0 ; # insert condition to stop in place of the 0>0
#######################################
## Maintain the position of trades
#######################################
def CurrentPosition; # holds whether flat = 0 long = 1 short = -1
if (BarNumber()==1) OR isNaN(CurrentPosition[1]) {
CurrentPosition = 0;
}else{
if CurrentPosition[1] == 0 { # FLAT
if (BuySignal) {
CurrentPosition = 1;
} else if (SellSignal){
CurrentPosition = -1;
} else {
CurrentPosition = CurrentPosition[1];
}
} else if CurrentPosition[1] == 1 { # LONG
if (SellSignal){
CurrentPosition = -1;
} else if (BuyStop and useStops){
CurrentPosition = 0;
} else {
CurrentPosition = CurrentPosition[1];
}
} else if CurrentPosition[1] == -1 { # SHORT
if (BuySignal){
CurrentPosition = 1;
} else if (SellStop and useStops){
CurrentPosition = 0;
} else {
CurrentPosition = CurrentPosition[1];
}
} else {
CurrentPosition = CurrentPosition[1];
}
}
def isLong = if CurrentPosition == 1 then 1 else 0;
def isShort = if CurrentPosition == -1 then 1 else 0;
def isFlat = if CurrentPosition == 0 then 1 else 0;
# If not already long and get a BuySignal
Plot BuySig = if (!isLong[1] and BuySignal and showSignals) then 1 else 0;
BuySig.AssignValueColor(color.cyan);
BuySig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
BuySig.SetLineWeight(5);
Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding);
Alert(BuySig and useAlerts, "Buy Signal",Alert.bar,sound.Ding);
# If not already short and get a SellSignal
Plot SellSig = if (!isShort[1] and SellSignal and showSignals) then 1 else 0;
SellSig.AssignValueColor(color.cyan);
SellSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
SellSig.SetLineWeight(5);
Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding);
Alert(SellSig and useAlerts, "Sell Signal",Alert.bar,sound.Ding);
# If long and get a BuyStop
Plot BuyStpSig = if (BuyStop and isLong[1] and showSignals and useStops) then 1 else 0;
BuyStpSig.AssignValueColor(color.light_gray);
BuyStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
BuyStpSig.SetLineWeight(3);
# If short and get a SellStop
Plot SellStpSig = if (SellStop and isShort[1] and showSignals and useStops) then 1 else 0;
SellStpSig.AssignValueColor(color.light_gray);
SellStpSig.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
SellStpSig.SetLineWeight(3);
#######################################
## Orders
#######################################
def isOrder = if CurrentPosition == CurrentPosition[1] then 0 else 1; # Position changed so it's a new order
# If there is an order, then the price is the next days close
def orderPrice = if (isOrder and (BuySignal or SellSignal)) then close else orderPrice[1];
#######################################
## Price and Profit
#######################################
def profitLoss;
if (!isOrder or orderPRice[1]==0){
profitLoss = 0;
} else if ((isOrder and isLong[1]) and (SellSig or BuyStpSig)){
profitLoss = close - orderPrice[1];
} else if ((isOrder and isShort[1]) and (BuySig or SellStpSig)) {
profitLoss = orderPrice[1] - close;
} else {
profitLoss = 0;
}
# Total Profit or Loss
def profitLossSum = compoundValue(1, if isNaN(isOrder) or barnumber()==1 then 0 else if isOrder then profitLossSum[1] + profitLoss else profitLossSum[1], 0);
# How many trades won or lost
def profitWinners = compoundValue(1, if isNaN(profitWinners[1]) or barnumber()==1 then 0 else if isOrder and profitLoss > 0 then profitWinners[1] + 1 else profitWinners[1], 0);
def profitLosers = compoundValue(1, if isNaN(profitLosers[1]) or barnumber()==1 then 0 else if isOrder and profitLoss < 0 then profitLosers[1] + 1 else profitLosers[1], 0);
def profitPush = compoundValue(1, if isNaN(profitPush[1]) or barnumber()==1 then 0 else if isOrder and profitLoss == 0 then profitPush[1] + 1 else profitPush[1], 0);
def orderCount = (profitWinners + profitLosers + profitPush) - 1;
# Current Open Trade Profit or Loss
def TradePL = If isLong then Round(((close - orderprice)/TickSize())*TickValue()) else if isShort then Round(((orderPrice - close)/TickSize())*TickValue()) else 0;
# Convert to actual dollars based on Tick Value for bubbles
def dollarProfitLoss = if orderPRice[1]==0 or isNaN(orderPrice[1]) then 0 else round((profitLoss/Ticksize())*Tickvalue());
# Closed Orders dollar P/L
def dollarPLSum = round((profitLossSum/Ticksize())*Tickvalue());
# Split profits or losses by long and short trades
def profitLong = compoundValue(1, if isNan(profitLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then profitLong[1]+dollarProfitLoss else profitLong[1],0);
def profitShort = compoundValue(1, if isNan(profitShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then profitShort[1]+dollarProfitLoss else profitShort[1],0);
def countLong = compoundValue(1, if isNaN(countLong[1]) or barnumber()==1 then 0 else if isOrder and isLong[1] then countLong[1]+1 else countLong[1],0);
def countShort = compoundValue(1, if isNaN(countShort[1]) or barnumber()==1 then 0 else if isOrder and isShort[1] then countShort[1]+1 else countShort[1],0);
# What was the biggest winning and losing trade
def biggestWin = compoundValue(1, if isNaN(biggestWin[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss > 0) and (dollarProfitLoss > biggestWin[1]) then dollarProfitLoss else biggestWin[1], 0);
def biggestLoss = compoundValue(1, if isNaN(biggestLoss[1]) or barnumber()==1 then 0 else if isOrder and (dollarProfitLoss < 0) and (dollarProfitLoss < biggestLoss[1]) then dollarProfitLoss else biggestLoss[1], 0);
# What percent were winners
def PCTWin = round((profitWinners/orderCount)*100,2);
# Average trade
def avgTrade = round((dollarPLSum/orderCount),2);
#######################################
## Create Labels
#######################################
AddLabel(showLabels, GetSymbol()+" Tick Size: "+TickSize()+" Value: "+TickValue(), color.white);
AddLabel(showLabels, "Closed Orders: " + orderCount + " P/L: " + AsDollars(dollarPLSum), if dollarPLSum > 0 then Color.GREEN else if dollarPLSum< 0 then Color.RED else Color.GRAY);
AddLabel(if !IsNan(orderPrice) and showLabels then 1 else 0, "Closed+Open P/L: "+ AsDollars(TradePL+dollarPLSum), if ((TradePL+dollarPLSum) > 0) then color.green else if ((TradePL+dollarPLSum) < 0) then color.red else color.gray);
AddLabel(showLabels, "Avg per Trade: "+ AsDollars(avgTrade), if avgTrade > 0 then Color.Green else if avgTrade < 0 then Color.RED else Color.GRAY);
AddLabel(showLabels, "Winners: "+ PCTWin +"%",if PCTWin > 50 then color.green else if PCTWin > 40 then color.yellow else color.gray);
AddLabel(showLabels, "MaxUp: "+ AsDollars(biggestWin) +" MaxDown: "+AsDollars(biggestLoss), color.white);
AddLabel(showLabels, "Long Profit: " +AsDollars(profitLong), if profitLong > 0 then color.green else if profitLong < 0 then color.red else color.gray);
AddLabel(showLabels, "Short Profit: " +AsDollars(profitShort), if profitShort > 0 then color.green else if profitShort < 0 then color.red else color.gray);
AddLabel(if !IsNan(CurrentPosition) and showLabels then 1 else 0, "Open: "+ (If isLong then "Bought" else "Sold") + " @ "+orderPrice, color.white);
AddLabel(if !IsNan(orderPrice) and showLabels then 1 else 0, "Open Trade P/L: "+ AsDollars(TradePL), if (TradePL > 0) then color.green else if (TradePl < 0) then color.red else color.gray);
#######################################
## Chart Bubbles for Profit/Loss
#######################################
AddChartBubble(showSignals and showBubbles and isOrder and isLong[1], low, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 0);
AddChartBubble(showSignals and showBubbles and isOrder and isShort[1], high, "$"+dollarProfitLoss, if dollarProfitLoss == 0 then Color.LIGHT_GRAY else if dollarProfitLoss > 0 then Color.GREEN else color.Red, 1);
#AssignPriceColor(if CurrentPosition == 1 then color.green else if CurrentPosition == -1 then color.red else color.gray);
```

and yes, I picked one where it works really well on a daily 1yr. Some aren't so pretty.

Here's one that's not as pretty, but not awful either, also a 1yr daily

Last edited by a moderator: