//
// System Rules:
// Indicators: MACD indicator (default values), ATR (14), EMA (200)
// 1. Price must be trading above/below the 200 EMA
// 2. Only 1 bar can close above/below the 200 EMA over the past 5 bars
// 3. We take the FIRST MACD cross and ignore subsequent signals until TP/SL is hit
// 4. Stop Loss = 0.5 ATR above/below the recent swing high/low (7 bars lookback)
// 5. First take profit = 1:1 (25%)
// 6. Second take profit = 2:1 (100%)
// 7. Move stop loss to break-even after 1st target is hit
//
// @version=5
strategy("[2022] MACD Cross Strategy", overlay=true,
currency="USD",
calc_on_order_fills=true,
use_bar_magnifier=true,
initial_capital=10000,
default_qty_type=strategy.percent_of_equity,
default_qty_value=100, // 100% of balance invested on each trade
commission_type=strategy.commission.cash_per_contract)
//commission_value=0.005) // Interactive Brokers rate
// Import ZenLibrary
import ZenAndTheArtOfTrading/ZenLibrary/5 as zen
// Get user input
var g_system = "System Entry Settings"
i_ema_filter = input.int(title="EMA Filter Length", defval=200, group=g_system)
i_ema_filter2 = input.int(title="EMA Max Bars Above/Below", defval=1, group=g_system)
i_stop_multi = input.float(title="Stop Loss Multiplier", defval=0.5, step=0.5, group=g_system)
i_stop_lookback = input.int(title="Stop Loss Lookback", defval=7, group=g_system)
var g_risk = "System Risk Settings"
i_rr1 = input.float(title="Risk:Reward Target 1", defval=1.0, group=g_risk)
i_rr2 = input.float(title="Risk:Reward Target 2", defval=2.0, group=g_risk)
i_target1 = input.float(title="Profit % Target 1", defval=25, group=g_risk)
i_riskPerTrade = input.float(title="Forex Risk Per Trade %", defval=1.0)
var g_macd = "MACD Settings"
i_price_src = input.source(title="Price Source", defval=close, group=g_macd)
i_fast_length = input.int(title="Fast Length", defval=12, group=g_macd)
i_slow_length = input.int(title="Slow Length", defval=26, group=g_macd)
i_signal_length = input.int(title="Signal Smoothing", minval=1, maxval=50, defval=9, group=g_macd)
i_sma_source = input.string(title="Oscillator MA Type", defval="EMA", options=["SMA", "EMA"],
group=g_macd)
i_sma_signal = input.string(title="Signal Line MA Type", defval="EMA", options=["SMA", "EMA"],
group=g_macd)
//------------- DETERMINE CURRENCY CONVERSION RATE -------------//
// Check if our account currency is the same as the base or quote currency or neither (for risk $
conversion purposes)
accountSameAsCounterCurrency = strategy.account_currency == syminfo.currency
accountSameAsBaseCurrency = strategy.account_currency == syminfo.basecurrency
accountNeitherCurrency = not accountSameAsCounterCurrency and not accountSameAsBaseCurrency
// Get currency conversion rates if applicable
conversionCurrencyPair = accountSameAsCounterCurrency ? syminfo.tickerid :
strategy.account_currency + syminfo.currency
conversionCurrencyRate = accountSameAsBaseCurrency or accountNeitherCurrency ?
request.security(conversionCurrencyPair, "D", close, ignore_invalid_symbol=true) : 1.0
// Display the current conversion currency ticker (for debug purposes)
if barstate.islastconfirmedhistory
table t = table.new(position.top_right, 1, 2, color.black)
table.cell(t, 0, 0, "Conversion: " + conversionCurrencyPair + " (" + str.tostring(conversionCurrencyRate)
+ ")", text_color=color.white, text_size=size.small)
table.cell(t, 0, 1, "Account: $" + str.tostring(zen.truncate(strategy.equity)), text_color=color.white,
text_size=size.small)
//------------- END CURRENCY CONVERSION RATE CODE -------------//
// Calculate MACD
[macdLine, signalLine, histLine] = ta.macd(i_price_src, i_fast_length, i_slow_length, i_signal_length)
// Get indicator values
ema = ta.ema(close, i_ema_filter)
atr = ta.atr(14)
// Check for zero-point crosses
crossUp = ta.crossover(signalLine, macdLine)
crossDown = ta.crossunder(signalLine, macdLine)
// Check general system filters
tradeFilters = not na(ema) and not na(atr)
// Check trend conditions
upTrend = close > ema
downTrend = close < ema
// Check trade conditions
longConditions = tradeFilters and macdLine[1] < 0 and signalLine[1] < 0
shortConditions = tradeFilters and macdLine[1] > 0 and signalLine[1] > 0
// Confirm long & short setups
longSignal = longConditions and upTrend and crossDown
shortSignal = shortConditions and downTrend and crossUp
// Calculate stop loss
longStop = ta.lowest(low, i_stop_lookback) - (atr * i_stop_multi)
shortStop = ta.highest(high, i_stop_lookback) + (atr * i_stop_multi)
// Save stops & targets
var float tradeStop = na
var float tradeTarget1 = na
var float tradeTarget2 = na
var float tradeSize = na
// Count bars above/below MA
int barsAboveMA = 0
int barsBelowMA = 0
for i = 1 to 5
if close[i] < ema[i]
barsBelowMA += 1
if close[i] > ema[i]
barsAboveMA += 1
// Combine signal filters
longTrade = longSignal and barsBelowMA <= i_ema_filter2 and strategy.position_size == 0
shortTrade = shortSignal and barsAboveMA <= i_ema_filter2 and strategy.position_size == 0
// Handle long trade entry (enter position, reset stops & targets)
if longTrade
if syminfo.type == "forex"
tradeStop := longStop
stopDistance = close - tradeStop
tradeTarget1 := close + (stopDistance * i_rr1)
tradeTarget2 := close + (stopDistance * i_rr2)
tradeSize := na
positionSize = zen.av_getPositionSize(strategy.equity, i_riskPerTrade, zen.toWhole(stopDistance) *
10, conversionCurrencyRate)
strategy.entry(id="Long", direction=strategy.long, qty=positionSize)
else
strategy.entry(id="Long", direction=strategy.long)
tradeStop := na
tradeTarget1 := na
tradeTarget2 := na
// Handle short trade entry (enter position, reset stops & targets)
if shortTrade
if syminfo.type == "forex"
tradeStop := shortStop
stopDistance = tradeStop - close
tradeTarget1 := close - (stopDistance * i_rr1)
tradeTarget2 := close - (stopDistance * i_rr2)
tradeSize := na
positionSize = zen.av_getPositionSize(strategy.equity, i_riskPerTrade, zen.toWhole(shortStop - close)
* 10, conversionCurrencyRate)
strategy.entry(id="Short", direction=strategy.short, qty=positionSize)
else
strategy.entry(id="Short", direction=strategy.short)
tradeStop := na
tradeTarget1 := na
tradeTarget2 := na
// Handle forex trade size tracking variable
if syminfo.type == "forex" and strategy.position_size != 0 and na(tradeSize)
tradeSize := strategy.position_size
// Handle long stops & target calculation
if strategy.position_size > 0 and na(tradeStop) and syminfo.type != "forex"
tradeStop := longStop
stopDistance = strategy.position_avg_price - tradeStop
tradeTarget1 := strategy.position_avg_price + (stopDistance * i_rr1)
tradeTarget2 := strategy.position_avg_price + (stopDistance * i_rr2)
tradeSize := strategy.position_size
// Handle short stops & target calculation
if strategy.position_size < 0 and na(tradeStop) and syminfo.type != "forex"
tradeStop := shortStop
stopDistance = tradeStop - strategy.position_avg_price
tradeTarget1 := strategy.position_avg_price - (stopDistance * i_rr1)
tradeTarget2 := strategy.position_avg_price - (stopDistance * i_rr2)
tradeSize := strategy.position_size
// Handle trade exits
strategy.exit(id="Long Exit #1", from_entry="Long", limit=tradeTarget1, stop=tradeStop,
qty_percent=i_target1)
strategy.exit(id="Long Exit #2", from_entry="Long", limit=tradeTarget2, stop=tradeStop,
qty_percent=100)
strategy.exit(id="Short Exit #1", from_entry="Short", limit=tradeTarget1, stop=tradeStop,
qty_percent=i_target1)
strategy.exit(id="Short Exit #2", from_entry="Short", limit=tradeTarget2, stop=tradeStop,
qty_percent=100)
// Handle both long & short trade break-even stops (do this AFTER first position has exited above ^)
if strategy.position_size != tradeSize
tradeStop := strategy.position_avg_price
tradeTarget1 := na
// Draw conditional data
plot(ema, color=close > ema ? color.green : color.red, linewidth=2, title="EMA")
plotshape(longTrade, style=shape.triangleup, color=color.green, location=location.belowbar,
title="Long Setup")
plotshape(shortTrade, style=shape.triangledown, color=color.red, location=location.abovebar,
title="Short Setup")
// Draw stops & targets
plot(strategy.position_size != 0 ? tradeStop : na, color=color.red, style=plot.style_linebr, title="Stop
Loss")
plot(strategy.position_size != 0 ? tradeTarget1 : na, color=color.green, style=plot.style_linebr, title="Profit
Target 1")
plot(strategy.position_size != 0 ? tradeTarget2 : na, color=color.green, style=plot.style_linebr, title="Profit
Target 2")