"NoSKi Hammer/Star /w angle of ema Backtester % 
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © noski1

//@version=5
strategy(title='"NoSKi Hammer Star Backtester %', shorttitle='Noski HnS BT %', overlay=true, 
 commission_type=strategy.commission.percent, commission_value=0.075, initial_capital = 10000, currency=currency.USD, default_qty_type= strategy.percent_of_equity, default_qty_value=100)


// Import Zen library
import ZenAndTheArtOfTrading/ZenLibrary/5 as zen
// --------------------------------------------------------------------------------
//------- Inputs--------//
// --------------------------------------------------------------------------------
//Time Period
FromMonth = input.int(defval=1, title='From Month', minval=1, maxval=12)
FromDay = input.int(defval=9, title='From Day', minval=1, maxval=31)
FromYear = input.int(defval=2019, title='From Year', minval=2018)
ToMonth = input.int(defval=1, title='To Month', minval=1, maxval=12)
ToDay = input.int(defval=1, title='To Day', minval=1, maxval=31)
ToYear = input.int(defval=9999, title='To Year', minval=2017)
start = timestamp(FromYear, FromMonth, FromDay, 00, 00)
finish = timestamp(ToYear, ToMonth, ToDay, 23, 59)
window() =>
    time >= start and time <= finish ? true : false
    
// Take Profit SL inputs
tp_inp = input.int(14, title='Take Profit %', group = "Take Profit/Stop Loss Settings")/100 //input.int(defval = 1, title = "Take Profit %", minval = 1)/100
sl_inp = input.int(2, title='Stop Loss %', group = "Take Profit/Stop Loss Settings")/100 //input.int(defval = 1, title = "Stop Loss %", minval = 1)/100    
//Once order at a time
order = input.bool(title="One Position at a time", defval=true, group="Order Sizing")
//Hammer and star inputs
fibLevel    = input.float(title="Fib Level", defval=0.333, group="Hammer and Stars")
colorFilter = input.bool(title="Color Filter", defval=false, group="Hammer and Stars")
aatrFilter   = input.float(title="ATR Filter", defval=0.1, group="Hammer and Stars")
//angle inputs
src = input(title='Source', defval=close, group="Angle of EMA")
guide_pos = input.float(title='Guides Position', defval=45, group="Angle of EMA")
guide_neg = input(title='Guides Position', defval=-45, group="Angle of EMA")
//price2bar_ratio = input(title='Price To Bar Ratio', defval=20.0, group="Angle of EMA")  // Should be the same as that of the Chart
p2br = input(title='Price To Bar Ratio', defval=20.0, group="Angle of EMA")  // Should be the same as that of the Chart
threshold = input(title='Threshold', defval=1.0, group="Angle of EMA")
show_bg = input(title='Show Negative Slope Zone', defval=true, group="Angle of EMA")
smal = input(title='Average angle over how many bars', defval=20, group="Angle of EMA")
emafilter   = input.int(title="EMA length", defval=20, group= "EMA")
//Swing High/Low filter
var g_hl     = "High/Low Filter"
lookback     = input.int(title="Swing High/Low Lookback", defval=10, tooltip="How many bars to look back for swing high/low", group=g_hl)
useHlFilter  = input.bool(title="Use Swing High/Low Filter?", defval=false, tooltip="Turns on/off the swing high/low filter", group=g_hl)
// Filter Settings
var g_filter        = "Entry Candle ATR Size"
atrMinFilterSize    = input.float(title=">= ATR Filter", defval=0.0, minval=0.0, group=g_filter, tooltip="Minimum size of entry candle compared to ATR")
atrMaxFilterSize    = input.float(title="<= ATR Filter", defval=3.0, minval=0.0, group=g_filter, tooltip="Maximum size of entry candle compared to ATR")
//emaFilter           = input.int(title="EMA Filter", defval=0, group=g_filter, tooltip="EMA length to filter trades - set to zero to disable")


price2bar_ratio = request.security(syminfo.tickerid, "D", close) * 0.000025 * p2br

// --------------------------------------------------------------------------------
// Hammer and Candles
// --------------------------------------------------------------------------------
// Check our ATR filter
atr = ta.atr(14)
candleSize = high - low
atrFilterCheck = candleSize >= atr * aatrFilter

// Calculate fibonacci level for current candle
bullFib = (low - high) * fibLevel + high
bearFib = (high - low) * fibLevel + low

// Determine which price source closes or opens highest/lowest
lowestBody  = close < open ? close : open
highestBody = close > open ? close : open

// Determine if we have a valid hammer or shooting star candle
hammerCandle = lowestBody >= bullFib and (not colorFilter or close > open) and atrFilterCheck
starCandle   = highestBody <= bearFib and (not colorFilter or close < open) and atrFilterCheck

// Get swing high/low filter
swingHighFilter = not useHlFilter or (high == ta.highest(high, lookback) or high[1] == ta.highest(high, lookback))
swingLowFilter  = not useHlFilter or (low == ta.lowest(low, lookback) or low[1] == ta.lowest(low, lookback))

// --------------------------------------------------------------------------------
// EMA Angle Functions
// --------------------------------------------------------------------------------
ema = ta.ema(close, emafilter)
get_slope(ema, price2bar_ratio) =>
    180.0 / (2 * math.asin(1)) * math.atan(ta.change(ema) / price2bar_ratio)

// Logic

slope = get_slope(ema, price2bar_ratio)

rise = false
rise := slope - slope[1] > threshold ? true : slope - slope[1] < -threshold ? false : nz(rise[1])

prefall = false
prefall := not rise or slope - slope[1] > 0 ? false : rise and slope - slope[1] < 0 ? true : nz(prefall[1])

prerise = false
prerise := rise or slope - slope[1] < 0 ? false : not rise and slope - slope[1] > 0 ? true : nz(prerise[1])

sma = ta.sma(slope, smal)

// Angle Buy Sell Filter
emapos = sma > guide_pos
emaneg = sma < guide_neg

// --------------------------------------------------------------------------------
// ATR Settings
// --------------------------------------------------------------------------------

// Check ATR filter
atrMinFilter = high - low >= (atrMinFilterSize * atr) or atrMinFilterSize == 0.0
atrMaxFilter = high - low <= (atrMaxFilterSize * atr) or atrMaxFilterSize == 0.0
atrFilter = atrMinFilter and atrMaxFilter and not na(atr)



var int inTrade = 0


order1 = not order or inTrade ==0 
// --------------------------------------------------------------------------------
// Combined Buy and Sell signals
// --------------------------------------------------------------------------------
buy = hammerCandle and emapos and atrFilter and swingLowFilter and barstate.isconfirmed and order1// inTrade == 0
sell = starCandle and emaneg and atrFilter and swingHighFilter and barstate.isconfirmed and order1//inTrade == 0


inpStopLoss = strategy.position_avg_price * (1 - sl_inp)
inpTakeProfit = strategy.position_avg_price * (1 + tp_inp)


if strategy.position_size < 0
    inpStopLoss := strategy.position_avg_price * (1 + sl_inp)
    inpTakeProfit := strategy.position_avg_price * (1 - tp_inp)    

// --------------------------------------------------------------------------------
// View
// --------------------------------------------------------------------------------

plotshape(buy, style=shape.triangleup, location=location.belowbar, color=color.new(color.green, 0), text = "Long", title='Long', textcolor = color.green)
plotshape(sell, style=shape.triangledown, location=location.abovebar, color=color.new(color.red, 0), text = "Short", title='Short', textcolor = color.red)

bgcolor(sma > guide_pos ? color.new(color.green, 85) : na)  // highlighting bg when ema angle > 45
bgcolor(sma < guide_neg ? color.new(color.red, 85) : na)


plot(ema, title="EMA", color=color.yellow, linewidth=2)

strategy.entry("Long", direction= strategy.long, when= buy and window())
strategy.entry("Short", direction= strategy.short, when= sell and window())


strategy.exit("Long Exit", from_entry="Long", when=strategy.position_size > 0, limit = inpTakeProfit, stop = inpStopLoss)
strategy.exit("Short Exit", from_entry="Short", when=strategy.position_size < 0, limit = inpTakeProfit, stop = inpStopLoss)