Crypto scalping strategy with backtesting by Pine script

Amir Hoss
6 min readApr 28, 2023

--

Requirements: Hull MA, EMA indicators

This Pine script defines a trading strategy that uses the Hull Moving Average (HullMA) and Exponential Moving Average (EMA) indicators.

//@version=5
// © AmirHome www.AmirHome.com

strategy("AH HullMA Ema", overlay=true, margin_long=100, margin_short=100)

FUNCTIONS

The script also includes two functions:

select_auto_resolution() =>
timeframe.isseconds ? '120' : (timeframe.isminutes and timeframe.multiplier <= 1) ? '5' : (timeframe.isminutes and timeframe.multiplier <= 5) ? '30' : (timeframe.isminutes and timeframe.multiplier <= 30) ? '60' : (timeframe.isminutes and timeframe.multiplier <= 60) ? '240' : (timeframe.isminutes and timeframe.multiplier <= 240) ? 'D' : timeframe.isdaily ? 'W' : timeframe.isweekly ? 'M' : timeframe.ismonthly and timeframe.multiplier < 3 ? '3M' : '12M'

fn_hullma(src, period) =>
n2ma = 2 * ta.wma(src, math.round(period / 2))
nma = ta.wma(src, period)
diff = n2ma - nma
sqn = math.round(math.sqrt(period))

n1 = ta.wma(diff, sqn)
n1

select_auto_resolution(): This function returns a string representing the recommended timeframe to use for the current chart resolution. It uses conditional statements to determine the timeframe based on the current chart resolution.

fn_hullma(src, period): This function calculates the Hull Moving Average for a given input source (src) and period. It first calculates two weighted moving averages, then subtracts them to create a difference value. The difference is then smoothed using another weighted moving average with a square root of the period as the length. Finally, the smoothed difference is added to the second moving average to create the Hull Moving Average value.
Overall, this script defines a trading strategy that uses the Hull Moving Average and Exponential Moving Average indicators and includes helper functions for determining the recommended timeframe and calculating the Hull Moving Average.

INPUTS

This Pine code defines a TradingView strategy that uses two types of moving averages to generate signals: Hull Moving Average (HullMA) and Exponential Moving Average (EMA).

//  I N P U T S    and    C O N S T A N T S

AUTO_TIMEFRAME_TOOLTIP = 'When the Auto option is selected, the timeframe of the indicator is chosen automatically based on the chart timeframe. The Timeframe dropdown is ignored. The automated timeframes are: \n \'1 day\' for any chart timeframes below \'1 day\' \n \'1 week\' for any timeframes starting from \'1 day\' up to \'1 week\' \n \'1 month\' for any timeframes starting from \'1 week\' up to \'1 month\' \n \'3 months\' for any timeframes starting from \'1 month\' up to \'3 months\' \n \'12 months\' for any timeframes above \'3 months\''
DEFAULT_RESOLUTION = '1D'
DEFAULT_TRANSPARENCY = 55
DEFAULT_COLOR_GROWTH = color.new(#26A69A, DEFAULT_TRANSPARENCY)
DEFAULT_COLOR_FALL = color.new(#EF5350, DEFAULT_TRANSPARENCY)
DEFAULT_AUTO_RESOLUTION = false
DEFAULT_COLOR_BUY = color.green
DEFAULT_COLOR_SELL = color.red

auto_resolution = input.bool(DEFAULT_AUTO_RESOLUTION, title='AutoTimeframe', tooltip=AUTO_TIMEFRAME_TOOLTIP)
resolution_input = input.timeframe(DEFAULT_RESOLUTION, title='Timeframe')
resolution = auto_resolution == true ? select_auto_resolution() : resolution_input

color_growth = input.color(DEFAULT_COLOR_GROWTH, title='up', inline='Body')
color_fall = input.color(DEFAULT_COLOR_FALL, title='down', inline='Body')

// --Hull MA Ema--
show_hullma = input.bool(title='Show HullaMA', defval=true)
period_hullma = input(title='Period HullMA', defval=50)
src_hullma = input(close, title="Source HullMA")

// --Moving Average Exponential--
// offset = input.int(title="Offset", defval=0, minval=-500, maxval=500)
show_ema = input.bool(title='Show EMA', defval=true)
len_ema = input.int(200, minval=1, title="Length EMA")
src_ema = input(close, title="Source EMA")

// --Debug--
debug = input.bool(title='Debug', defval=false, tooltip = 'Show Background color and Labels')

// -- Timeframe plot
tfPlot = input.bool(title='Show Timeframe plots', defval=false)

Finally, the code defines several input variables, including options to show or hide the HullMA and EMA, as well as the source price for each moving average. There is also an option to toggle debug mode.

STRATEGY BASICS

This Pine code is a trading strategy that combines Hull Moving Average (HullMA) and Exponential Moving Average (EMA) indicators. The code first defines two functions: select_auto_resolution() and fn_hullma().

// --Call Function HullMA--
n1 = fn_hullma(src_hullma, period_hullma)
n2 = fn_hullma(src_hullma[1], period_hullma)

// --Set color and Plot HullMA--
colorHullMA = n1 > n2 ? color_growth : color_fall
plot(show_hullma ? n1 : na, color=colorHullMA, linewidth=2)


// --Moving Average Exponential--
ema = ta.ema(src_ema, len_ema)
plot(show_ema ? ema : na, title="EMA", color=color.purple, offset=0)



// T I M E F R A M E

ema_parent = ta.ema(src_ema, len_ema)
tf_ema_parent = request.security(syminfo.tickerid, resolution, ema_parent, gaps=barmerge.gaps_on)
plot(show_ema ? tf_ema_parent : na, color=color.rgb(123, 30, 139), title="Timeframe MA", linewidth=2, display = tfPlot? display.all : display.none)

// --Call Function HullMA--
n1_parent = fn_hullma(src_hullma, period_hullma)
n2_parent = fn_hullma(src_hullma[1], period_hullma)
tf_n1_parent = request.security(syminfo.tickerid, resolution, n1_parent)//, gaps=barmerge.gaps_on)
tf_n2_parent = request.security(syminfo.tickerid, resolution, n2_parent)//, gaps=barmerge.gaps_on)

// --Set color and Plot HullMA--
bool tf_crossover = (tf_n1_parent > tf_n2_parent) ? true : false
colorHullMA_parent = tf_crossover ? color_growth : color_fall
plot(show_hullma ? tf_n1_parent : na, color=colorHullMA_parent, linewidth=3, display = tfPlot? display.all : display.none)

select_auto_resolution() is a function that returns the appropriate timeframe for the chart based on the current timeframe. It uses a series of if-else statements to determine the timeframe based on the current timeframe’s multiplier.

fn_hullma() is a function that takes two arguments: src and period. It calculates the HullMA value using the Weighted Moving Average (WMA) formula and returns the result.

The code then defines variables for the HullMA and EMA indicators using the fn_hullma() and ta.ema() functions, respectively. The colors for the HullMA and EMA lines are also set.

The code also includes a section for the timeframe of the EMA indicator. It defines the EMA for the parent timeframe and plots it using the request.security() function. The HullMA values for the parent timeframe are also calculated and plotted using the same function. The colors for the HullMA line are determined by whether or not there is a crossover between the two HullMA lines.

Overall, this code implements a trading strategy that uses two moving average indicators and can be adjusted for different timeframes.

ENTRY AND EXIT SIGNALS

This part of the Pine code defines the trading conditions for the strategy based on the Hull Moving Average (HullMA) and Exponential Moving Average (EMA) crossovers.

crossover = (n1 > n2) and (low > ema)
longCondition = (crossover and not crossover[1] and not crossover[2] and not crossover[3] and not crossover[4] and not crossover[5] and not crossover[6]) ? true : false

crossunder = (n1 < n2) and ( high < ema)
shortCondition = (crossunder and not crossunder[1] and not crossunder[2] and not crossunder[3] and not crossunder[4] and not crossunder[5] and not crossunder[6]) ? true : false

if longCondition
label.new(bar_index, high, 'Buy\n '+str.tostring(close, '#.##'), color=color.new(DEFAULT_COLOR_BUY,89), style=label.style_label_down, yloc=yloc.abovebar)
if shortCondition
label.new(bar_index, low, 'Sell\n '+str.tostring(close, '#.##'), color=color.new(DEFAULT_COLOR_SELL,89), style=label.style_label_up, yloc=yloc.belowbar)

if (longCondition and tf_crossover)
strategy.entry('long', strategy.long, comment = str.tostring(close, '#.##'))
// --Define condition to exit long position--
exitLongCondition = ta.crossunder(n1, n2)
if (exitLongCondition)
strategy.close('long', comment = str.tostring(close, '#.##'))


if (shortCondition and not tf_crossover)
strategy.entry('short', strategy.short, comment = str.tostring(close, '#.##'))
// --Define condition to exit short position--
exitShortCondition = ta.crossover(n1, n2)
if (exitShortCondition)
strategy.close('short', comment = str.tostring(close, '#.##'))

First, it checks for a bullish crossover where the HullMA is above the EMA and the price is above the EMA. This is represented by the boolean variable crossover. Then, it checks if the current bar meets the long entry conditions, which means that the crossover just occurred and there were no crossovers in the past 6 bars (indicated by the not crossover[1] and so on conditions). If these conditions are met, it sets longCondition to true.

Similarly, it checks for a bearish crossover where the HullMA is below the EMA and the price is below the EMA. This is represented by the boolean variable crossunder. Then, it checks if the current bar meets the short entry conditions, which means that the crossunder just occurred and there were no crossunders in the past 6 bars. If these conditions are met, it sets shortCondition to true.

If longCondition is true and the longer-term trend is also bullish (indicated by tf_crossover), the strategy enters a long position. The strategy.entry function is used for this purpose.

For exit conditions, the code defines exitLongCondition as a crossunder of the HullMA and EMA, which would trigger the closing of a long position. Similarly, exitShortCondition is defined as a crossover of the HullMA and EMA, which would trigger the closing of a short position. The strategy.close function is used to close a position.

BACKTESTING AND OPTIMIZATION

Resources

GitHub Code
https://youtu.be/AQJoia9fnyY
https://www.tradingview.com/v/vGan9DRX/

--

--

Amir Hoss

✔Senior PHP Developer✔Mobile Developer✔MySQL Administrator [myWebsite:https://amirhome.com]