This strategy identifies price trends by combining Average True Range (ATR) and Commodity Channel Index (CCI), and uses overbought/oversold levels as entry and exit signals. ATR calculates the upper and lower bands, while CCI determines the trend direction. It goes short when CCI crosses below overbought level, and goes long when CCI crosses above oversold level, thus following trends.
This strategy combines trend identification and channel breakout, which effectively follows trends.
Overall this is a simple and practical trend following strategy. Its advantage is clear logic and ease of implementation for quickly capitalizing on trends. But parameters like stop loss range require optimization based on market conditions. Combining with other indicators can further enhance the strategy. As a beginner trend following strategy, it is worth learning and referencing.
/*backtest start: 2023-08-26 00:00:00 end: 2023-09-25 00:00:00 period: 3h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=4 strategy("Trend Trader Karan",overlay=true) res = input(title="Resolution", type=input.resolution, defval="60",confirm = true) ProfitPerc = input(title=" Take Profit (%)",type=input.float, minval=0.0, step=0.1, defval=1.4) * 0.01 stoploss = input(title=" Stop Loss (%)",type=input.float, minval=0.0, step=0.1, defval=0.7) * 0.01 CCI = input(10,title = "CCI") ATR = input(2,title = "ATR") Multiplier= 1 original = false thisCCI = cci(close, CCI) lastCCI = nz(thisCCI[1]) calcx()=> bufferDn= high + Multiplier * wma(tr,ATR) bufferUp= low - Multiplier * wma(tr,ATR) if (thisCCI >= 0 and lastCCI < 0) bufferUp := bufferDn[1] if (thisCCI <= 0 and lastCCI > 0) bufferDn := bufferUp[1] if (thisCCI >= 0) if (bufferUp < bufferUp[1]) bufferUp := bufferUp[1] else if (thisCCI <= 0) if (bufferDn > bufferDn[1]) bufferDn := bufferDn[1] x = 0.0 x := thisCCI >= 0 ?bufferUp:thisCCI <= 0 ?bufferDn:x[1] x tempx = calcx() calcswap() => swap = 0.0 swap := tempx>tempx[1]?1:tempx<tempx[1]?-1:swap[1] swap tempswap = calcswap() swap2=tempswap==1?color.green:color.red swap3=thisCCI >=0 ?color.green :color.red swap4=original?swap3:swap2 //display current timeframe's Trend plot(tempx,color=swap4 == color.green ? color.green : swap4,transp=0,linewidth=4) htfx = security(syminfo.tickerid,res,tempx[1],lookahead = barmerge.lookahead_on) htfswap4 = security(syminfo.tickerid,res,swap4[1],lookahead = barmerge.lookahead_on) plot(htfx,color=htfswap4,transp=0,linewidth=3) //plotarrow( ? 1 : swap4[1] == color.yellow and swap4 == color.blue ? -1 :0 , title="Up Entry Arrow", colorup=color.green,colordown = color.blue, maxheight=10, minheight=10, transp=0) plotshape( swap4[1] == color.red and swap4 == color.green ? 1 : na , style = shape.triangleup , color = color.blue , location = location.belowbar , size = size.tiny ) plotshape( swap4[1] == color.green and swap4 == color.red ? 1 : na , style = shape.triangledown , color = color.red , location = location.abovebar , size = size.tiny) buy = swap4[1] == color.red and swap4 == color.green and htfswap4 == color.green sell = swap4[1] == color.green and swap4 == color.red and htfswap4 == color.red if(buy) strategy.entry("buy",true) if(sell) strategy.entry("sell",false) if(swap4[1] == color.red and swap4 == color.green) strategy.close("sell") if(swap4[1] == color.green and swap4 == color.red ) strategy.close("buy") longExitPrice = strategy.position_avg_price * (1 + ProfitPerc) shortExitPrice = strategy.position_avg_price * (1 - ProfitPerc) stop_buy = strategy.position_avg_price * (1 - stoploss) stop_sell = strategy.position_avg_price * (1 + stoploss) if (strategy.position_size > 0) strategy.exit(id="Target", limit=longExitPrice , stop = stop_buy) if (strategy.position_size < 0) strategy.exit(id="Target", limit=shortExitPrice , stop = stop_sell) ///////////////study("EMA ", overlay=true) plot(ema(close, 200), color=#FF7000, linewidth=2, title='200 Day EMA') plot(ema(close, 20), color=#0088FA, linewidth=2, title='20 Day EMA') plot(ema(close, 50), color=#FA00D0, linewidth=2, title='50 Day EMA') //////////////////study("Trend Lines+++", overlay=true) // src = input(low) len0 = input(100) calcSlope(src, len0) => if not barstate.islast [float(na), float(na), float(na)] else sumX = 0.0 sumY = 0.0 sumXSqr = 0.0 sumXY = 0.0 for i = 0 to len0 - 1 val = src[i] per = i + 1.0 sumX := sumX + per sumY := sumY + val sumXSqr := sumXSqr + per * per sumXY := sumXY + val * per slope = (len0 * sumXY - sumX * sumY) / (len0 * sumXSqr - sumX * sumX) average = sumY / len0 intercept = average - slope * sumX / len0 + slope [slope, average, intercept] [s, a, i] = calcSlope(src, len0) startPrice = i + s * (len0 - 1) endPrice = i // var line baseLine = na // if na(baseLine) // baseLine := line.new(bar_index - len0 + 1, startPrice, bar_index, endPrice, width=4, extend=extend.right) // else // line.set_xy1(baseLine, bar_index - len0 + 1, startPrice) // line.set_xy2(baseLine, bar_index, endPrice) // na // mx = input(100, "Range", minval=1) mn = max(2, round(mx / 10) + 1) LN(B, CLR) => s1 = B == 1 ? highest(src, mx) : lowest(src, mx) s2 = B == 1 ? highest(src, mn) : lowest(src, mn) c1 = s1 == src c2 = s2 == src b1 = barssince(c1) b2 = barssince(c2) v1 = valuewhen(c1, s1, 0) v2 = valuewhen(c2, s2, 0) // line.new(bar_index - b1, v1, bar_index - b2, v2, extend=extend.both, color=CLR, width=2) // L1 = LN(1, #ff0088), line.delete(L1[1]) // L2 = LN(0, #00ff88), line.delete(L2[1]) // // Input variables len=input(30,title="loockback length pivots") wicks=input(true,title="Draw lines from wicks (checked) or real bodies (unchecked)?") disp_select=input(true,title="Display only falling 'high' and rising 'low' trendlines?") do_mono=input(false,title="checked = monochrome lines, unchecked = direction colored lines?") limit_extension=input(0,title="Limit extensions of the lines? 0 = infinite, other values x 100 bars",minval=0) do_alerts=input(true,title="show trendline breaks") trendline_nr=input(5,title="number of past trendlines to check for breaks (max = 10)",minval=0,maxval=10) select_breaks=input(true,title="only display 'long' breaks on trendlines connecting 'highs' and 'short' for 'lows'") log_chart=input(false,title="USING A LOG CHART? MAKE SURE TO CHECK THIS BOX!!") // Calculating the 'time value' of one bar bar_time=time-time[1] // Initialising color scheme var color color_rising=do_mono?color.teal:color.lime var color color_falling=do_mono?color.teal:color.fuchsia /////// Function declarations /////// // Declaration of trendline function f_trendline(_input_function,_delay,_only_up,_extend) => // Calculate line coordinates (Ax,Ay) - (Bx,By) var int Ax = 0 var int Bx = 0 var float By = 0.0 var float slope = 0.0 Ay = fixnan(_input_function) if change(Ay)!=0 Ax := time[_delay] By:= Ay[1] Bx := Ax[1] slope:=log_chart?((log(Ay)-log(By))/(Ax-Bx)):((Ay-By)/(Ax-Bx)) else Ax := Ax[1] Bx := Bx[1] By := By[1] // Draw trendlines var line trendline=na var int Axbis=0 var float Aybis=0.0 var bool _xtend=true extension_time = limit_extension*bar_time*100 Axbis := Ax + extension_time Aybis := log_chart?(Ay*exp(extension_time*slope)):(Ay + extension_time*slope) if limit_extension!=0 _xtend:=false if change(Ay)!=0 line_color = slope*time<0?(_only_up?(disp_select?na:color_rising):color_rising):(_only_up?color_falling:(disp_select?na:color_falling)) if not na(line_color) trendline = line.new(Bx,By,Axbis, Aybis, xloc.bar_time, extend=_xtend?extend.right:extend.none, color=line_color, style=line.style_dotted, width=1) [Bx,By,Axbis,Aybis,slope] // Function to get trendline price for X bars ago ("0" = current value) line_get_price(_start_time,_start_price,_slope,_lookback_period,_log_chart) => var float current_price=0.0 elapsed_time = (time-_start_time) current_price := _log_chart?(_start_price*exp((elapsed_time-(_lookback_period*bar_time))*_slope)):(_start_price + (elapsed_time-(_lookback_period*bar_time))*_slope) // Function to check for trendline crosses line_cross(_check_value,_start_time,_start_price,_slope,_log_chart) => var float current_value=0.0 var float previous_value=0.0 // Get current and previous price for the trendline current_value := line_get_price(_start_time,_start_price,_slope,0,_log_chart) previous_value := line_get_price(_start_time,_start_price,_slope,1,_log_chart) // Return 1 for crossover, -1 for crossunder and 0 for no cross detected cross = _check_value[1]<previous_value and _check_value>current_value?1: _check_value[1]>previous_value and _check_value<current_value?-1:0 /////// Start of main script /////// // Calculate pivot points high_point=pivothigh(wicks?high:(close>open?close:open),len,len/2) low_point=pivotlow(wicks?low:(close>open?open:close),len,len/2) // Call trendline function for high and low pivot points [phx1,phy1,phx2,phy2,slope_high]=f_trendline(high_point,len/2,false,true) [plx1,ply1,plx2,ply2,slope_low]=f_trendline(low_point,len/2,true,true) // Initialition of pseudo array to keep track of last 10 high and 10 low trendline values var int high_x0=0, var float high_y0=0.0, var float high_sl0=0.0 var int high_x1=0, var float high_y1=0.0, var float high_sl1=0.0 var int high_x2=0, var float high_y2=0.0, var float high_sl2=0.0 var int high_x3=0, var float high_y3=0.0, var float high_sl3=0.0 var int high_x4=0, var float high_y4=0.0, var float high_sl4=0.0 var int high_x5=0, var float high_y5=0.0, var float high_sl5=0.0 var int high_x6=0, var float high_y6=0.0, var float high_sl6=0.0 var int high_x7=0, var float high_y7=0.0, var float high_sl7=0.0 var int high_x8=0, var float high_y8=0.0, var float high_sl8=0.0 var int high_x9=0, var float high_y9=0.0, var float high_sl9=0.0 var int low_x0=0, var float low_y0=0.0, var float low_sl0=0.0 var int low_x1=0, var float low_y1=0.0, var float low_sl1=0.0 var int low_x2=0, var float low_y2=0.0, var float low_sl2=0.0 var int low_x3=0, var float low_y3=0.0, var float low_sl3=0.0 var int low_x4=0, var float low_y4=0.0, var float low_sl4=0.0 var int low_x5=0, var float low_y5=0.0, var float low_sl5=0.0 var int low_x6=0, var float low_y6=0.0, var float low_sl6=0.0 var int low_x7=0, var float low_y7=0.0, var float low_sl7=0.0 var int low_x8=0, var float low_y8=0.0, var float low_sl8=0.0 var int low_x9=0, var float low_y9=0.0, var float low_sl9=0.0 // If a new trendline is formed, shift all values in the array one place up and forget the last values if change(fixnan(high_point))!=0 high_x9:=high_x8, high_y9:=high_y8, high_sl9:=high_sl8 high_x8:=high_x7, high_y8:=high_y7, high_sl8:=high_sl7 high_x7:=high_x6, high_y7:=high_y6, high_sl7:=high_sl6 high_x6:=high_x5, high_y6:=high_y5, high_sl6:=high_sl5 high_x5:=high_x4, high_y5:=high_y4, high_sl5:=high_sl4 high_x4:=high_x3, high_y4:=high_y3, high_sl4:=high_sl3 high_x3:=high_x2, high_y3:=high_y2, high_sl3:=high_sl2 high_x2:=high_x1, high_y2:=high_y1, high_sl2:=high_sl1 high_x1:=high_x0, high_y1:=high_y0, high_sl1:=high_sl0 high_x0:=phx1, high_y0:=phy1, high_sl0:=slope_high if change(fixnan(low_point))!=0 low_x9:=low_x8, low_y9:=low_y8, low_sl9:=low_sl8 low_x8:=low_x7, low_y8:=low_y7, low_sl8:=low_sl7 low_x7:=low_x6, low_y7:=low_y6, low_sl7:=low_sl6 low_x6:=low_x5, low_y6:=low_y5, low_sl6:=low_sl5 low_x5:=low_x4, low_y5:=low_y4, low_sl5:=low_sl4 low_x4:=low_x3, low_y4:=low_y3, low_sl4:=low_sl3 low_x3:=low_x2, low_y3:=low_y2, low_sl3:=low_sl2 low_x2:=low_x1, low_y2:=low_y1, low_sl2:=low_sl1 low_x1:=low_x0, low_y1:=low_y0, low_sl1:=low_sl0 low_x0:=plx1, low_y0:=ply1, low_sl0:=slope_low // Check Trendline crosses for last X nr. of trendlines cross_high0= disp_select and high_sl0*time>0?0: line_cross(close,high_x0,high_y0,high_sl0,log_chart) cross_low0= disp_select and low_sl0*time<0?0: line_cross(close,low_x0,low_y0,low_sl0,log_chart) cross_high1= disp_select and high_sl1*time>0?0: line_cross(close,high_x1,high_y1,high_sl1,log_chart) cross_low1= disp_select and low_sl1*time<0?0: line_cross(close,low_x1,low_y1,low_sl1,log_chart) cross_high2= disp_select and high_sl2*time>0?0: line_cross(close,high_x2,high_y2,high_sl2,log_chart) cross_low2= disp_select and low_sl2*time<0?0: line_cross(close,low_x2,low_y2,low_sl2,log_chart) cross_high3= disp_select and high_sl3*time>0?0: line_cross(close,high_x3,high_y3,high_sl3,log_chart) cross_low3= disp_select and low_sl3*time<0?0: line_cross(close,low_x3,low_y3,low_sl3,log_chart) cross_high4= disp_select and high_sl4*time>0?0: line_cross(close,high_x4,high_y4,high_sl4,log_chart) cross_low4= disp_select and low_sl4*time<0?0: line_cross(close,low_x4,low_y4,low_sl4,log_chart) cross_high5= disp_select and high_sl5*time>0?0: line_cross(close,high_x5,high_y5,high_sl5,log_chart) cross_low5= disp_select and low_sl5*time<0?0: line_cross(close,low_x5,low_y5,low_sl5,log_chart) cross_high6= disp_select and high_sl6*time>0?0: line_cross(close,high_x6,high_y6,high_sl6,log_chart) cross_low6= disp_select and low_sl6*time<0?0: line_cross(close,low_x6,low_y6,low_sl6,log_chart) cross_high7= disp_select and high_sl7*time>0?0: line_cross(close,high_x7,high_y7,high_sl7,log_chart) cross_low7= disp_select and low_sl7*time<0?0: line_cross(close,low_x7,low_y7,low_sl7,log_chart) cross_high8= disp_select and high_sl8*time>0?0: line_cross(close,high_x8,high_y8,high_sl8,log_chart) cross_low8= disp_select and low_sl8*time<0?0: line_cross(close,low_x8,low_y8,low_sl8,log_chart) cross_high9= disp_select and high_sl9*time>0?0: line_cross(close,high_x9,high_y9,high_sl9,log_chart) cross_low9= disp_select and low_sl9*time<0?0: line_cross(close,low_x9,low_y9,low_sl9,log_chart) long_break= (trendline_nr>9?cross_high9==1 or (select_breaks?false:cross_low9==1):false) or (trendline_nr>8?cross_high8==1 or (select_breaks?false:cross_low8==1):false) or (trendline_nr>7?cross_high7==1 or (select_breaks?false:cross_low7==1):false) or (trendline_nr>6?cross_high6==1 or (select_breaks?false:cross_low6==1):false) or (trendline_nr>5?cross_high5==1 or (select_breaks?false:cross_low5==1):false) or (trendline_nr>4?cross_high4==1 or (select_breaks?false:cross_low4==1):false) or (trendline_nr>3?cross_high3==1 or (select_breaks?false:cross_low3==1):false) or (trendline_nr>2?cross_high2==1 or (select_breaks?false:cross_low2==1):false) or (trendline_nr>1?cross_high1==1 or (select_breaks?false:cross_low1==1):false) or cross_high0==1 or (select_breaks?false:cross_low0==1) short_break= (trendline_nr>9?(select_breaks?false:cross_high9==-1) or cross_low9==-1:false) or (trendline_nr>8?(select_breaks?false:cross_high8==-1) or cross_low8==-1:false) or (trendline_nr>7?(select_breaks?false:cross_high7==-1) or cross_low7==-1:false) or (trendline_nr>6?(select_breaks?false:cross_high6==-1) or cross_low6==-1:false) or (trendline_nr>5?(select_breaks?false:cross_high5==-1) or cross_low5==-1:false) or (trendline_nr>4?(select_breaks?false:cross_high4==-1) or cross_low4==-1:false) or (trendline_nr>3?(select_breaks?false:cross_high3==-1) or cross_low3==-1:false) or (trendline_nr>2?(select_breaks?false:cross_high2==-1) or cross_low2==-1:false) or (trendline_nr>1?(select_breaks?false:cross_high1==-1) or cross_low1==-1:false) or (select_breaks?false:cross_high0==-1) or cross_low0==-1 // Plot and connect pivot points color_high=slope_high*time<0?color_rising:(disp_select?na:color_falling) color_low=slope_low*time>0?color_falling:(disp_select?na:color_rising) plot(high_point,color=color_high,offset=-len/2) plot(low_point,color=color_low,offset=-len/2) // // Function outputs 1 when it's the first bar of the D/W/M/Y is_newbar(res) => ch = 0 if(res == 'Y') t = year(time('D')) ch := change(t) != 0 ? 1 : 0 else t = time(res) ch := change(t) != 0 ? 1 : 0 ch //////////// // INPUTS // //////////// pp_period = input(title = "Period", type=input.string, defval="Day", options = ['Day', 'Week', 'Month', 'Year']) pp_res = pp_period == 'Day' ? 'D' : pp_period == 'Week' ? 'W' : pp_period == 'Month' ? 'M' : 'Y' ///////////////////// // Get HLC from HT // // Calc High high_cur = 0.0 high_cur := is_newbar(pp_res) ? high : max(high_cur[1], high) phigh = 0.0 phigh := is_newbar(pp_res) ? high_cur[1] : phigh[1] // Calc Low low_cur = 0.0 low_cur := is_newbar(pp_res) ? low : min(low_cur[1], low) plow = 0.0 plow := is_newbar(pp_res) ? low_cur[1] : plow[1] // Calc Close pclose = 0.0 pclose := is_newbar(pp_res) ? close[1] : pclose[1]