MA-EMA Crossover LT
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/

// This is a Trend Following strategy. Strategy Logic as follows - 
// Very simple MA and EMA crossover for Entry (Short or Long)
// Re-entry is on EMA crossover 
// Dynamic Zones are used for Stop Loss exit - Dynamic Zone is simply a % of "X" period price range. I use 128 periods for checking range.
// Dynamic Zones script is taken from @allanster https://tradingview.com/script/AoChfBer-How-To-Use-Dynamic-Zones. It's beautiful, neat script.
// I have found that it gives good results (at least on-paper results) on 3 hours timeframe or Daily timeframes.
// I have kept certain default parameters like quantity, trade type long/short, etc since they were convinient for the kind of stocks I was checking. 
// One can change many of these parameters to optimise the results. 
// There are still some changes to be done to script as follows - //12Apr20
// 1. If on Long Entry, the entry point is below the dynamic zone line, then the stop loss is calculated above the entry point. I will fix it one of these days. 
// 2. Additional re-entry logic or take-profit logic in case the stock runs much ahead
// 3. I need to write a Alerts script that would have 10s of stocks built into one script.  
// 4. Any other feedback
// Please note I am not a programmer by profession. I am just trying to code a few simple trading ideas for my personal use.
// So, any suggestions / help in changing / optimizing code is most welcome. 
 

//@version=4

strategy("MA-EMA Crossover LT", shorttitle="MA-EMA XO", max_bars_back = 200, overlay=true, precision=9, default_qty_type=strategy.fixed,default_qty_value=100)


//==================== STRATEGY CODE ======================

tradeType = input("BOTH", title="Trade Type ", options=["LONG", "SHORT", "BOTH"])

// === BACKTEST RANGE ===
FromMonth = 01//input(defval=01, title="From Month", minval=1)
FromDay = 01//input(defval=01, title="From Day", minval=1)
FromYear = input(defval=2017, title="From Year", minval=2000)
ToMonth = 12//input(defval=12, title="To Month", minval=1)
ToDay = 31//input(defval=31, title="To Day", minval=1)
ToYear = input(defval=9999, title="To Year", minval=2000)

testPeriod() =>
    time > timestamp(FromYear, FromMonth, FromDay, 00, 00) and 
       time < timestamp(ToYear, ToMonth, ToDay, 23, 59)

stopLossPercent = input(1.00, "Stop Loss Percent")
profitPercent_long = input(3.50, "Profit Percent LONG")
profitPercent_short = input(3.0, "Profit Percent SHORT")

atr_multi_PT = input(1.50, "ATR Multiple for PT")
atr_multi_SL = input(1.50, "ATR Multiple for SL")
//////////////////////////////

isLongOpen = false
isShortOpen = false

//Order open on previous ticker?
isLongOpen := nz(isLongOpen[1])
isShortOpen := nz(isShortOpen[1])

/////////////////////
//Trailing and Profit variables
trigger = 0.0
trigger := na

profitTrigger = 0.0
profitTrigger := na

//obtain values from last ticker
entryPrice = 0.0
entryPrice := nz(entryPrice[1])

stopLossLevel = 0.0
stopLossLevel := nz(stopLossLevel[1])

profitPriceLevel = 0.0
profitPriceLevel := nz(profitPriceLevel[1])


//If in active trade, lets load with current value    
if isLongOpen
    profitTrigger := profitPriceLevel ? high : na
    trigger := stopLossLevel ? ohlc4 : na
    trigger
if isShortOpen
    profitTrigger := profitPriceLevel ? low : na
    trigger := stopLossLevel ? ohlc4 : na
    trigger

isStopLoss = isLongOpen ? trigger < stopLossLevel : 
   isShortOpen ? trigger > stopLossLevel : na
isProfitCatch = isLongOpen ? profitTrigger > profitPriceLevel : 
   isShortOpen ? profitTrigger < profitPriceLevel : na

//===================      Optional Entry Condition    ============
src    = close
len = input(defval = 128, title = "DZ Length", type = input.integer, minval = 1)
// use_dz = input(false, title="Use Dynamic Zone")
pcntAbove = input(defval = 40, title = "Hi is Above X% of Sample", type = input.float, minval = 0, maxval = 100, step = 1.0)
pcntBelow = input(defval = 60, title = "Lo is Below X% of Sample", type = input.float, minval = 0, maxval = 100, step = 1.0)

smplAbove = percentile_nearest_rank(src, len, pcntAbove)
smplBelow = percentile_nearest_rank(src, len, 100 - pcntBelow)

above     = plot(src > smplAbove ? src : smplAbove, title = "Above Line", color = na)
probOB    = plot(smplAbove, title = "OB", color = color.green)
probOS    = plot(smplBelow, title = "OS", color = color.red)
below     = plot(src < smplBelow ? src : smplBelow, title = "Below Line", color = na)
fill(above,  probOB, color = #00FF00, transp = 80)
fill(below,  probOS, color = #FF0000, transp = 80)

// long_dz = close > smplAbove
// short_dz = close < smplBelow


//==============           Entry Conditions        =====================
timeframe = input("5D", title="MA16 Resolution", type=input.resolution)
_ma = sma(hlc3, 16)
ma=security(syminfo.tickerid, timeframe, _ma, barmerge.gaps_off, barmerge.lookahead_on)

_ema=ema(hlc3,7)
ema=security(syminfo.tickerid, timeframe, _ema, barmerge.gaps_off, barmerge.lookahead_on)


long = ma[1] > ema[1] ? crossover(ema, ma) : abs(ma - ema)/ma > 0.025 ? crossover(close, ema) : false
short = ma[1] < ema[1] ? crossunder(ema,ma) : abs(ma - ema)/ma > 0.025 ? crossunder(close, ema): false //:crossunder(close, ema) 

longEntry = (tradeType == "LONG" or tradeType == "BOTH") and long
shortEntry = (tradeType == "SHORT" or tradeType == "BOTH") and short

//Upon Entry, do this.
if longEntry or shortEntry
    entryPrice := ohlc4
    entryPrice

//set price points for new orders
use_dz_sl = input(true, title="Use DZ SL")
if isLongOpen 
    stopLossLevel := use_dz_sl? max(smplAbove, ma) : ema - 0.25*atr_multi_PT* atr(32) //ma
    profitTrail = ma + atr_multi_PT* atr(32)
    profitPriceLevel :=  max( (1 + 0.01 * profitPercent_long) * entryPrice, profitTrail)
    profitPriceLevel
if isShortOpen 
    stopLossLevel :=  use_dz_sl? min(smplBelow, ma) : ema + 0.25*atr_multi_PT* atr(32) //ma
    profitTrail = ma - atr_multi_PT* atr(32)
    profitPriceLevel := min( (1 - 0.01 * profitPercent_short) * entryPrice, profitTrail)
    profitPriceLevel

shortExit = isShortOpen[1] and (isStopLoss or isProfitCatch or longEntry)
longExit = isLongOpen[1] and (isStopLoss or isProfitCatch or shortEntry)


if (longExit or shortExit) and not(longEntry or shortEntry)
    trigger := na
    profitTrigger := na
    entryPrice := na
    stopLossLevel := na
    profitPriceLevel := na
    // highest := na
    // lowest := na
    // lowest

if testPeriod() and (tradeType == "LONG" or tradeType == "BOTH")
    strategy.entry("long", strategy.long, when=longEntry)
    strategy.close("long", when=longExit)

if testPeriod() and (tradeType == "SHORT" or tradeType == "BOTH")
    strategy.entry("short", strategy.short, when=shortEntry)
    strategy.close("short", when=shortExit)


//If the value changed to invoke a buy, lets set it before we leave
isLongOpen := longEntry ? true : longExit == true ? false : isLongOpen
isShortOpen := shortEntry ? true : shortExit == true ? false : isShortOpen


plotshape(isShortOpen, title="Short Open", color=color.red, style=shape.triangledown, location=location.bottom)
plotshape(isLongOpen, title="Long Open", color=color.green, style=shape.triangleup, location=location.bottom)

plotshape(entryPrice ? entryPrice : na, title="Entry Level", color=color.black, style=shape.cross, location=location.absolute)
plotshape(stopLossLevel ? stopLossLevel : na, title="Stop Loss Level", color=color.orange, style=shape.xcross, location=location.absolute)
plotshape(profitPriceLevel ? profitPriceLevel : na, title="Profit Level", color=color.blue, style=shape.xcross, location=location.absolute)
plotshape(profitTrigger[1] ? isProfitCatch : na, title="Profit Exit Triggered", style=shape.diamond, location=location.abovebar, color=color.blue, size=size.small)
plotshape(trigger[1] ? isStopLoss : na, title="Stop Loss Triggered", style=shape.diamond, location=location.belowbar, color=color.orange, size=size.small)

plot(ma, title="MA 16", color=color.yellow)
plot(ema, title="EMA 7", color=color.blue)