Coppock Curve Indicator & Strategy for ThinkorSwim

BenTen

Administrative
Staff
VIP
Coppock Curve is a momentum indicator designed for long term trend trading. By default, it will show buy signals only on the weekly charts.

You won't be able to view it when switching to shorter timeframes like the daily, hourly, or 15 mins. The Coppock Curve indicator was made to pick trending stocks. Therefore, it will not generate any sell (short) signals.

Let's take a look at the original Coppock Curve code:

Code:
#
# Copyright 2016 Scott J. Johnson (https://scottjjohnson.com)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#
# CoppockIndicator
#
# Charts the Coppock Indicator described here:
#             https://en.wikipedia.org/wiki/Coppock_curve
#
# The Coppock can be used (along with other indicators like the Eureka Signal
# and IBD6000 %Es) to identify points where the stock market trend changes
# from down to up. The Coppock does not identify the beginning of downtrends.
#
# This study is designed to be applied to a major market index (e.g., SPX or
# COMP) with an aggregation period of weeks or months.
#
declare lower;

input RateOfChangeSlowPeriod = 14;
input RateOfChangeFastPeriod = 11;
input WeightedMAPeriod = 10;

def AggregationPeriod = if (getAggregationPeriod() < AggregationPeriod.WEEK) then AggregationPeriod.WEEK else getAggregationPeriod();

def price = close(period = AggregationPeriod);

def ROC1 = if price[RateOfChangeSlowPeriod]!=0 then (price/price[RateOfChangeSlowPeriod]-1)*100 else 0;
def ROC2 = if price[RateOfChangeFastPeriod]!=0 then (price/price[RateOfChangeFastPeriod]-1)*100 else 0;

plot Coppock = WMA(ROC1 + ROC2, WeightedMAPeriod);

Coppock.assignValueColor(if Coppock>Coppock[1] then color.green else color.red);
Coppock.SetDefaultColor(GetColor(1));
Coppock.setLineWeight(2);
Coppock.HideBubble();

plot ZeroLine = 0;

ZeroLine.SetDefaultColor(color.white);
ZeroLine.HideBubble();

AddChartBubble(Coppock[1] < 0 and Coppock > Coppock[1] and Coppock[1] < Coppock[2], Coppock, "Buy", Color.CYAN, no);

Since it did so well on the weekly chart, I decided to modify the Coppock indicator a bit to work on shorter timeframes. And to my surprise, I found a lot of nice signals during backtesting.

Here's what included in the package:
  • Coppock Curve strategy for short term trading
  • Sell Signals (As originally stated, Coppock will look for trending stocks so it doesn't produce sell signals by default. I had to reverse some of the code for it to do so)
  • 4 EMA / 9 SMA crossover for profit taking and stop loss
  • 13 EMA for additional support with profit taking and minimizing losses if a trade goes wrong.

ezI9Je9.png


Attached below is 2 different source code. One for long strategy and other is for short strategy. I have 2 grids available on my screen so it's easier for me to view and identify which signal is which. You're more than welcome to combine into one screen. And don't forget those codes need to be added as a New Strategy, NOT indicator.

thinkScript Code for Buying

Rich (BB code):
input RateOfChangeSlowPeriod = 14;
input RateOfChangeFastPeriod = 11;
input WeightedMAPeriod = 10;

def AggregationPeriod = if (getAggregationPeriod() < AggregationPeriod.HOUR) then AggregationPeriod.HOUR else getAggregationPeriod();

def price = close(period = AggregationPeriod);

def ROC1 = if price[RateOfChangeSlowPeriod]!=0 then (price/price[RateOfChangeSlowPeriod]-1)*100 else 0;
def ROC2 = if price[RateOfChangeFastPeriod]!=0 then (price/price[RateOfChangeFastPeriod]-1)*100 else 0;

def Coppock = WMA(ROC1 + ROC2, WeightedMAPeriod);

def ZeroLine = 0;

def BuyNow = Coppock[1] < 0 and Coppock > Coppock[1] and Coppock[1] < Coppock[2];
plot Buy1 = BuyNow;
Buy1.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
Buy1.SetLineWeight(1);
Buy1.AssignValueColor(Color.WHITE);

def SellNow = Coppock[1] > 0 and Coppock < Coppock[1] and Coppock[1] > Coppock[2];
#plot Sell1 = SellNow;
#Sell1.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DoWN);
#Sell1.SetLineWeight(1);
#Sell1.AssignValueColor(Color.WHITE);

input priceclose = close;
input EMA = 4;
def displaceclose = 0;

input priceclose13 = close;
input EMA13 = 13;
def displaceclose13 = 0;

input pricehigh = close;
input SMA = 9;
def displacehigh = 0;

def AvgExpema = ExpAverage(priceclose[-displaceclose], EMA);
def AvgExpsma = Average(pricehigh[-displacehigh], SMA);
def AvgExp13 = ExpAverage(priceclose13[-displaceclose13], EMA13);

plot ln1 = AvgExp13;
ln1.SetDefaultColor(CreateColor(145, 210, 144));
ln1.SetLineWeight(2);

def US =  AvgExpema crosses above AvgExpsma;
def DS = AvgExpema crosses below AvgExpsma ;

AddOrder(OrderType.BUY_AUTO, condition = Buy1, price = close,1, tickcolor = Color.GREEN, arrowcolor = Color.GREEN, name = "Long");

AddOrder(OrderType.SELL_AUTO, condition = DS, price = close,1, tickcolor = Color.GREEN, arrowcolor = Color.GREEN, name = "Cover");

AddLabel(yes,"4/9 EMA Hidden. 13ema on",color.Yellow);

thinkScript Code for Shorting

Rich (BB code):
input RateOfChangeSlowPeriod = 14;
input RateOfChangeFastPeriod = 11;
input WeightedMAPeriod = 10;

def AggregationPeriod = if (getAggregationPeriod() < AggregationPeriod.HOUR) then AggregationPeriod.HOUR else getAggregationPeriod();

def price = close(period = AggregationPeriod);

def ROC1 = if price[RateOfChangeSlowPeriod]!=0 then (price/price[RateOfChangeSlowPeriod]-1)*100 else 0;
def ROC2 = if price[RateOfChangeFastPeriod]!=0 then (price/price[RateOfChangeFastPeriod]-1)*100 else 0;

def Coppock = WMA(ROC1 + ROC2, WeightedMAPeriod);

def ZeroLine = 0;

def BuyNow = Coppock[1] < 0 and Coppock > Coppock[1] and Coppock[1] < Coppock[2];
#plot Buy1 = BuyNow;
#Buy1.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
#Buy1.SetLineWeight(1);
#Buy1.AssignValueColor(Color.WHITE);

def SellNow = Coppock[1] > 0 and Coppock < Coppock[1] and Coppock[1] > Coppock[2];
plot Sell1 = SellNow;
Sell1.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DoWN);
Sell1.SetLineWeight(1);
Sell1.AssignValueColor(Color.WHITE);

input priceclose = close;
input EMA = 4;
def displaceclose = 0;

input priceclose13 = close;
input EMA13 = 13;
def displaceclose13 = 0;

input pricehigh = close;
input SMA = 9;
def displacehigh = 0;

def AvgExpema = ExpAverage(priceclose[-displaceclose], EMA);
def AvgExpsma = Average(pricehigh[-displacehigh], SMA);
def AvgExp13 = ExpAverage(priceclose13[-displaceclose13], EMA13);

plot ln1 = AvgExp13;
ln1.SetDefaultColor(CreateColor(145, 210, 144));
ln1.SetLineWeight(2);

def US =  AvgExpema crosses above AvgExpsma;
def DS = AvgExpema crosses below AvgExpsma ;

AddOrder(OrderType.SELL_AUTO, condition = Sell1, price = close,1, tickcolor = Color.LIME, arrowcolor = Color.LIME, name = "Short");

AddOrder(OrderType.BUY_AUTO, condition = US, price = close,1, tickcolor = Color.LIME, arrowcolor = Color.LIME, name = "Cover");

AddLabel(yes,"4/9 Crossover Hidden. 13ema on",color.Yellow);

About Profit Taking and Cutting Losses

The Coppock Curve will only generate buy (long) and sell (short) signals. Your job is to take profit when available. I added the 4 EMA and 9 SMA crossover for profit taking and also the 13 EMA.

The buy (long) and sell (short) signals will be generated by the Coppock Curve indicator. As far as knowing when to take profit or cut losses, I added the 4 EMA and 9 SMA crossover for that purpose. If you have a medium to high-risk tolerance, you can wait for the EMA to fire a signal to let you know its time to take profit or cut losses.

If your risk tolerance isn't that high but you still want to maximize your profit, you can use the 13 EMA that I included instead of waiting for the crossover. Ride it until it closed above/below the opposite direction.

Example of 4/9 EMA

ZvR09DS.png


Example of 13 EMA

fD4yizE.png


Notes:
  • Use the 15min
  • Avoid trading ETFs such as SPY, IWM, XLF, etc although ETFs can have its good days as well. But generally I would stick to individual stocks for this strategy.
 
Last edited:

BenTen

Administrative
Staff
VIP
Here is another long term trading indicator called Big Hand. The Big Hand indicator will let you know the beginning of a downtrend and also the beginning of an uptrend (indicated by arrow up and arrow down). It should should be run on SPY WEEKLY Chart.

Code:
#  Big_Hand_Arrows_On_Study_w_Agg
#  Use on Weekly Chart
#  Script by Waylock
# AlphaInvestor - 05/12/2017 - force to weekly aggregation

declare lower;

input agg = AggregationPeriod.WEEK;
# Hide Study Name and Inputs
# Add this to hide the text on the title bar
plot Scriptlabel = Double.NaN;
Scriptlabel.SetDefaultColor(CreateColor ( 6, 0, 48 ));
input fastLength = 19;
input slowLength = 39;
def c = close(period = agg);
plot Value = ExpAverage(c, fastLength) - ExpAverage(c, slowLength);
def Value_color = if Value > 0 then yes else no;
Value.DefineColor( "ValueUp", Color.GREEN );
Value.DefineColor( "ValueDn", Color.RED );
Value.AssignValueColor( if Value_color then Value.Color( "ValueUp" ) else Value.Color( "ValueDn" ) );
plot ZeroLine = 0;
Value.SetDefaultColor(Color.CYAN);
ZeroLine.SetDefaultColor(Color.YELLOW);
ZeroLine.HideTitle();
ZeroLine.HideBubble();
def xUndr = Value[1] < 0 and Value > 0;
def xOver = Value[1] > 0 and Value < 0;
plot ArrowUp = if xUndr then xOver else Double.NaN;
ArrowUp.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
ArrowUp.SetDefaultColor(Color.YELLOW);
ArrowUp.SetLineWeight(5);
ArrowUp.HideTitle();
ArrowUp.HideBubble();
plot ArrowDn = if xOver then xUndr else Double.NaN;
ArrowDn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
ArrowDn.SetDefaultColor(Color.YELLOW);
ArrowDn.SetLineWeight(5);
ArrowDn.HideTitle();
ArrowDn.HideBubble();
# Make Label on Study panel to show the value of the Big Hand
def data = Value;
AddLabel(yes, "Big Hand   " + Round(data, 2), if data > 0 then Color.GREEN else Color.RED);
AddLabel(yes, "Big Hand should be run on SPY WEEKLY Chart", Color.GRAY);
# End Study

dEoQUuN.png


# Example 1: Amazon

6e3HkVV.png


Let's use Amazon as an example. The last time we got a Buy signal from the Coppock indicator was October 9th, 2017. Closing price was $1002.94. Fast forward to October 23rd, we saw a $98 jump in price (in less than a month).

# Example 2: SPY

With SPY, the last time we got a Buy signal from the Coppock indicator was May 7th of this year. Closing price was $272.85. Shortly a month after, we saw a $5 jump in price.

I'll be taking a look at some of the signals given by the Big Hand indicator on SPY as well. In late September 2015 and early 2016, we saw a few uptrend and downtrend signals.

SPY opened at $195ish. Less than a month later, its lowest was 186ish. We can also see how the Coppock and Big Hand indicators correlate with each other at some events.

w6i6amQ.png


It's important to note that there is currently a downtrend signal on SPY, given by the Big Hand indicator.

Give these 2 indicators some backtesting and you should see a clear picture. Looking at historical data, we should see a Buy signal from the Coppock and an uptrend signal from the Big Hand indicator pretty soon. How I'm going to approach this strategy is fairly simple. Look through some historical data, see how much a stock usually jump after they were given a Buy signal and how long it took them. I'd say usually 1-2 months.
 
Last edited:

ramblers926

New member
I have just hacked together a version of the Coppock scan based on the indicator code from Ben. It appears to be working, feel free to check it out and let me know if you come across issues. Note: Please make sure the aggregation period is set to Weekly or higher.

Thinkscript Code

Rich (BB code):
input RateOfChangeSlowPeriod = 14;
input RateOfChangeFastPeriod = 11;
input WeightedMAPeriod = 10;

def price = close;

def ROC1 = if price[RateOfChangeSlowPeriod]!=0 then (price/price[RateOfChangeSlowPeriod]-1)*100 else 0;
def ROC2 = if price[RateOfChangeFastPeriod]!=0 then (price/price[RateOfChangeFastPeriod]-1)*100 else 0;

def Coppock = WMA(ROC1 + ROC2, WeightedMAPeriod);

plot result = Coppock[1] < 0 and Coppock > Coppock[1] and Coppock[1] < Coppock[2];
 
Last edited by a moderator:

EvilAI

New member
Ben, I did some back testing with this indicator, along with a couple other of my favorite for confirmation.

My chosen indicators were RSI, MACD, CAPPOT, and BigHand:

joTfpq8.png


Next, I picked a random past time window to to work from:

QeqYISX.png


From there, I started going through random tickers and looking for good setups. The criteria I was looking for looked something like the following:
  • 1. Cappot issued a "Buy" signal recently
  • 2. Big hand bullish cross, or at a minimum not negative
  • 3. MACD recently crossed up (or about to)
  • 4. RSI not overbought and preferably above 50

fC6aK25.png


Once I had found several tickers with matching criteria, I then headed over the ToS "Analyze -> ThinkBack" feature. For those unfamiliar, this feature allows you to set the date to some time in the past in order to simulate trades from that time. I set the start date in ThinkBack to match the end date of the time window I set up at the beginning.

mjJg3jL.png


Next, using the list of matching tickers, I simply bought 10 just out of the money calls for each one. My only criteria for selecting the options was that I wanted to have at least 30 days on monthly opex until expiration. So I chose an expiry of 12/21/2018 which would give 57 days until expiration.

PEsyqpw.png


Here is what the final list looked like once I finished buying calls for each ticker. Notice the P/L column on the right hand side, every ticker has a P/L of $0 since I just purchased the options. Also notice the Date is 10/25/2018 on the Backtrades section at the bottom.

v4b4sh0.png


Next, I started rolling the date forward to see how the options prices would change over time. First look here is a couple of days later at 10/27/2018.

a4f79AH.png


$SPY:

zyrpqA9.png


Next 11/01/2018:

EdP9W8O.png


$SPY:

yXU3n5C.png


Next 11/08/2018:

xWlLTSK.png


SPY:

JH5xhGO.png


Next 11/30/2018:

ha3z67o.png


SPY:

gAyA37s.png


Finally, the day before expiry on 12/21/2018. Here many of the options have gone from positive to negative. This isn't surprising since, around this time is when the market began to decline rapidly. However, there were plenty of opportunities to take profits along the way on most of these.

4PGPVOG.png


SPY:

cDernVG.png


From my testing, this definitely looks like a great way to find good setups. That being said, this is still anecdotal, and perhaps I just luckily chose a really good time to buy based on market conditions.

Edit: Based on my comment about just luckily picking a good time, I went back and inserted $SPY analysis for the same expiration dates to analyze how these would perform against the larger index.
 
Last edited:

markos

Well-known member
VIP
What you have created with a "monthly" type indicator is really cool. I may be able to adapt that to my time frames.

Thanks!

 
Last edited:

Nick

Active member
2019 Donor
VIP
Understood this is suitable for 15mins timeframe, may i know if there is any suggested modifications for daily timeframe? thank you

 
Last edited:

BenTen

Administrative
Staff
VIP
@Nick All you have to do is adjust the fourth line of the code.

Rich (BB code):
def AggregationPeriod = if (getAggregationPeriod() < AggregationPeriod.HOUR) then AggregationPeriod.HOUR else getAggregationPeriod();

Change HOUR to DAY
 
Last edited:

BenTen

Administrative
Staff
VIP
@vandell001#1439 By changing
Code:
AggregationPeriod.HOUR
to
Code:
AggregationPeriod.FIFTEEN_MIN
 
Last edited:

Nick

Active member
2019 Donor
VIP
@BenTen will there be a short or down arrow plotted on the chart after the scan list is generated? I am able to generate the scan list based on the short code above but there is no arrows plotted on the chart. thanks
 

RBO

New member
VIP
I see this as old thread, i copied " thinkScript Code for Buyingb " in charts ( study ) , i dont see any signals getting generating.. Any updates required for this script ?
 

ramizlol

New member
Hey Ben! I haven't had a chance to backtest the code but I noticed a thing in it that might sleep your results. I see that the price is set to open not open[-1] when you buy. Wouldn't this cause the code to "buy" at previous open price which is in past?
 

Madhu

New member
@vandell001#1439 By changing
Code:
AggregationPeriod.HOUR
to
Code:
AggregationPeriod.FIFTEEN_MIN
Hi Ben, the two screenshots showing 15 minutes but your code is showing Hour.
Do i need to change to Fifty_Min in code to trade on 15 min chart or even if the code has hour , will it work for both 15 min,and hour also?

please help me.

thanks
Madhu
 

Similar threads

Top