CAGR (compounded annual growth rates)?

eugchen

Member
Does anyone know how to use thinkscript to calculate compound annual growth rates?

on excel, the formula is something like this

=RRI(A7,B2,B7)

where A7 = how many years
B2 = start value
B7 = end value

so for example, lets say i want to calculate the 5 year CAGR rate for aapl. lets say aapl 5 years ago was 50, and the current price is 100.

if you plugged into this formula, it says that AAPL had an annual compounded growth rate of 14.87% each year for 5 years
thanks
eugene

CAGR formula in Excel: https://www.excel-easy.com/examples/cagr.html
 
Solution
@eugchen Here is a test label that returns the same value as your example you gave. The values can be changed as needed for you to check the results.
Code:
def begin = 50;
def end = 100;
def length = 5;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));
@eugchen I coded this up after researching the CAGR formula. I believe this will give the same results as your Excel version.

Code:
# CAGR Calculator
# Pensar, 03.05.2021

input yearsback = 5;
def agg = aggregationperiod.YEAR;
def o = open(period = agg)[yearsback];
def CAGR = Power(close/o,1/yearsback)-1;
AddLabel(1,"CAGR: " + AsPercent(CAGR), color.white);

# end code
 
Last edited:
@eugchen Here is a test label that returns the same value as your example you gave. The values can be changed as needed for you to check the results.
Code:
def begin = 50;
def end = 100;
def length = 5;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));
 
Solution
wow @Pensar much props, i dont know how you reverse engineered

A2 = A1 * (1 + CAGR)n
end = start * (1 + CAGR)n
end/start = (1 + CAGR)n
(end/start)1/n = (1 + CAGR)
CAGR = (end/start)1/n - 1

i tried following it and got thrown in a loop, give the man a beer! 🍺
 
@XeoNoX This is what I used for the method - https://www.wikihow.com/Calculate-Compounded-Annual-Growth-Rate
To understand what the formula did, I also researched the Power function in the ThinkorSwim Learning Center and on other websites, such as -
https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Math---Trig/Power
https://en.wikipedia.org/wiki/Exponentiation
https://www.brightstorm.com/math/precalculus/polynomial-and-rational-functions/power-functions/

So to the best of my understanding, this is how the power function works (at least in this case) -
Code:
AddLabel(1,Power(10,5)); # 10 raised to the power of 5
AddLabel(1,10*10*10*10*10); # 10 multiplied out 5 times
Of course, I'm not a math expert by any means.
 
lol, oh ok thaks for the link...this was much better explination of the forumula... https://www.wikihow.com/Calculate-Compounded-Annual-Growth-Rate

power/exponents im familiar with..... it was trying to figure out the crazy way they described the formula in the original post, often times i see formulas described like in the excel or just variables all over the place that they arent explaining what they represent and its confusing, i prefer how wikihow explained, its much easier to follow. Nice research bro.
 
Pensar, one last question....how would i alter this wonderful code to show me the CAGR from the beginning of the charts data?

so for instance, lets say XXX chart goes back 5.5 years. i want to see the CAGR for the period of 5.5 years. and then lets say stock YYY goes back 24.5 years. and i want a chart label showing CAGR for the 24.5 years. in other words, sort of an all time CAGR for each stock. is that possible?

i currently have 4 labels...1. 5 year CAGR , 2. 10 year CAGR, 3. 15 year CAGR, 4. 20 year CAGR. looking for an all time CAGR one.

thanks!!!!
 
Pensar, one last question....how would i alter this wonderful code to show me the CAGR from the beginning of the charts data?
@eugchen So here is what I came up with. I checked it against AAPL, and used the same test code as above for verification. When I ran it on a max daily chart, everything checked out, but when I ran it on a max yearly chart, the beginning value was around $0.30 vs the actual $0.13 starting price of the AAPL chart, so see what it gives you. I'm including the test code with the CAGR chart label since I've coded it to be tied directly to that label's variables for verification. Just delete that portion of the code after you check the results for accuracy.

Code:
# CAGR Total Chart Timeframe
# Pensar, 03.06.2021

def agg = aggregationperiod.YEAR;
def c = close(period = agg);
def yearbars = if c then yearbars[1] + 1 else yearbars[1];
def o = First(open(period = agg));
def CAGR = Power(c/o,1/yearbars)-1;
AddLabel(1,"CAGR: " + AsPercent(CAGR), color.white);

# end code

AddLabel(1,"Total Years: " + yearbars);
AddLabel(1,"Begin Price: " + o);
AddLabel(1,"End Price: " + close);

# adjustable test label

input begin = 0.13;
input end = 121.42;
input length = 37;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));

# end code
 
Last edited:
fantastic! but few questions...

is the code using the opening price of the first candle seen on TOS for a given stock?

for instance, lets look at SQ and TSLA.

the opening price i have down for SQ on TOS is 11.2 on 11/19/15. yesterdays close was 216.44. this was over a 5.3 year period. putting into the CAGR calculator, the answer should be 74.82%.

but on the code, if i have 6 month DAY chart, the value shown is 85.37%. on the MAX DAY chart, i see a value of 52.66%.


the opening price i have down for TSLA on TOS is 3.8 on 6/1/10. yesterdays close was 597.95. this was over a 10.77 year period. putting into the CAGR calculator, the answer should be 59.93%.

but on the code, if i have 6 month DAY chart, the value shown is 165.39%. on the MAX DAY chart, i see a value of 52.43%.

Please let me know if you are getting the same data on the same settings.
 
Last edited:
fantastic! but few questions...

is the code using the opening price of the first candle seen on TOS for a given stock?

for instance, lets look at SQ and TSLA.

the opening price i have down for SQ on TOS is 11.2 on 11/19/15. yesterdays close was 216.44. this was over a 5.3 year period. putting into the CAGR calculator, the answer should be 74.82%.

but on the code, if i have 6 month DAY chart, the value shown is 85.37%. on the MAX DAY chart, i see a value of 52.66%.


the opening price i have down for TSLA on TOS is 3.8 on 6/1/10. yesterdays close was 597.95. this was over a 10.77 year period. putting into the CAGR calculator, the answer should be 59.93%.

but on the code, if i have 6 month DAY chart, the value shown is 165.39%. on the MAX DAY chart, i see a value of 52.43%.

Please let me know if you are getting the same data on the same settings.
@eugchen To the best of my knowledge, ThinkScript only works with the data on the chart. So if you have a 6 month 1 day chart timeframe, it will only read 6 months worth of data. I do notice inaccuracies with the value it is pulling for the first bar, as I noted earlier, I'll see if I can iron it out or not.
 
@eugchen I've worked with the label for a while, and I can't seem to improve the results it is getting. Here's some of the stocks I tested:

1. NIO - chart says 6.00, code uses 12.66
2. AMZN - chart says 1.97, code pulls 1.73
3. GOOGL - chart says 50.05, code says 55.42
4.TSLA - chart says 3.80, code pulls 5.00

I also had some strange data that far back -

5. MSFT - chart says -16.28, code gets -16.27
6. AAPL - chart says -39.65, code pulls -39.65 (the last time I looked, it was around 0.13 as the open price)
7. GE - chart says -8.34, code says -8.34

In many cases, the data used by the ThinkScript code came from the third day after the stock IPO.

After seeing these results, I feel that you would do better to take the test label in post #17, edit the code to only show on a selected ticker symbol, change the "end" price to use the most current price on the chart, and input the "begin" data manually. You can probably use the "yearbars" variable for the length of the chart, as long as it gives the correct data. You will get far more accurate results.
If you try to do it and can't figure it out, just let me know.
 
so you mean use the code below, and change each to a specific symbol like lets say AAPL...

so for end price, you can enter in "close", and begin price, need to enter in manually?

# adjustable test label

input begin = 0.13;
input end = 121.42;
input length = 37;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));

# end code
 
so you mean use the code below, and change each to a specific symbol like lets say AAPL...

so for end price, you can enter in "close", and begin price, need to enter in manually?

# adjustable test label

input begin = 0.13;
input end = 121.42;
input length = 37;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));

# end code
@eugchen To get the most accurate results for the entire stock trading time, yes. It seems that the further back in time that the stock began trading, the more inaccurate the value that gets pulled for the beginning price of the stock. So something like what I coded below. This is the second time recently I've come across a ThinkScript method that is'nt as precise as I'd like, and its very frustrating. Try it and see if it works.
Code:
# must be run on a MAX DAY chart

# the beginning price must be manually put into the "begin" input

input begin = 1.00;
input ticker = "AAPL";

def c = close(symbol = ticker);
def bars = if c then bars[1] + 1 else bars[1];
def x = Power(c/begin,1/(bars/252))-1;

AddLabel(1,"CAGR: " + AsPercent(x),color.white);
 
Hi @Pensar and all,

I am new to this community, and wanted to ask for your help. I have copied script. However, the result is not matching my expectation. Given this is a 5 Y (monthly) chart on Netflix, I would expect the "Total Years" to be 5, however, I am seeing that "Total Years" is 7.

Here is a screenshot: https://ibb.co/QvQP7SV

I'm sorry if this is an obvious question, but I would appreciate your help!

Warm Regards,
Nonce

-- Code for Reference

Code:
# CAGR Total Chart Timeframe
# Source: Pensar, 03.06.2021
# Modified by golden.nonce, 02.14.2022


def agg = AggregationPeriod.YEAR;
def c = close(period = agg);
def yearbars = if c then yearbars[1] + 1 else yearbars[1];
def o = First(open(period = agg));
def CAGR = Power(c / o, 1 / yearbars) - 1;
AddLabel(1, "CAGR: " + AsPercent(CAGR), Color.WHITE);

# end code

AddLabel(1, "Total Years: " + yearbars);
AddLabel(1, "Begin Price: " + o);
AddLabel(1, "End Price: " + close);

#debug
AddLabel(1, "agg: " + agg);
AddLabel(1, "c: " + c);
AddLabel(1, "yearbars: " + yearbars);
AddLabel(1, "o: " + o);
AddLabel(1, "CAGR: " + CAGR);

# adjustable test label

#input begin = 0.13;
#input end = 121.42;
#input length = 42;
#def x = Power(end/begin,1/length)-1;
#AddLabel(1,"CAGR Test Result: " + AsPercent(x));

# end code
 
Last edited by a moderator:
@eugchen So here is what I came up with. I checked it against AAPL, and used the same test code as above for verification. When I ran it on a max daily chart, everything checked out, but when I ran it on a max yearly chart, the beginning value was around $0.30 vs the actual $0.13 starting price of the AAPL chart, so see what it gives you. I'm including the test code with the CAGR chart label since I've coded it to be tied directly to that label's variables for verification. Just delete that portion of the code after you check the results for accuracy.

Code:
# CAGR Total Chart Timeframe
# Pensar, 03.06.2021

def agg = aggregationperiod.YEAR;
def c = close(period = agg);
def yearbars = if c then yearbars[1] + 1 else yearbars[1];
def o = First(open(period = agg));
def CAGR = Power(c/o,1/yearbars)-1;
AddLabel(1,"CAGR: " + AsPercent(CAGR), color.white);

# end code

AddLabel(1,"Total Years: " + yearbars);
AddLabel(1,"Begin Price: " + o);
AddLabel(1,"End Price: " + close);

# adjustable test label

input begin = 0.13;
input end = 121.42;
input length = 37;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));

# end code
Hi Pensar, why does it always produce "NaN" for CAGR. it does not produce any percentage. is this CAGR calculation correct?
 
Last edited:
@eugchen So here is what I came up with. I checked it against AAPL, and used the same test code as above for verification. When I ran it on a max daily chart, everything checked out, but when I ran it on a max yearly chart, the beginning value was around $0.30 vs the actual $0.13 starting price of the AAPL chart, so see what it gives you. I'm including the test code with the CAGR chart label since I've coded it to be tied directly to that label's variables for verification. Just delete that portion of the code after you check the results for accuracy.

Code:
# CAGR Total Chart Timeframe
# Pensar, 03.06.2021

def agg = aggregationperiod.YEAR;
def c = close(period = agg);
def yearbars = if c then yearbars[1] + 1 else yearbars[1];
def o = First(open(period = agg));
def CAGR = Power(c/o,1/yearbars)-1;
AddLabel(1,"CAGR: " + AsPercent(CAGR), color.white);

# end code

AddLabel(1,"Total Years: " + yearbars);
AddLabel(1,"Begin Price: " + o);
AddLabel(1,"End Price: " + close);

# adjustable test label

input begin = 0.13;
input end = 121.42;
input length = 37;
def x = Power(end/begin,1/length)-1;
AddLabel(1,"CAGR Test Result: " + AsPercent(x));

# end code
H Pensar, can you please advise why I am not getting any value? I always get Nan for CAGR
 
Even I am seeing NaN for the below simple CAGR calculation:

Code:
# CAGR Calculator
# Pensar, 03.05.2021

input yearsback = 5;
def agg = aggregationperiod.YEAR;
def o = open(period = agg)[yearsback];
plot CAGR = Power(close/o,1/yearsback)-1;
AddLabel(1,"CAGR: " + AsPercent(CAGR), color.white);

# end code

UPDATE!
Ok, I got it to work. I had to replace Aggregation period to DAY from YEAR. In this case, I multiply the input yearsback by 252 to get the open value at x yearsback. We can also enter fractional years (e.g., 2.5 years as input) as I round the daysback to a whole number. The input (yearsback) can be entered/modified in the GUI using conditional wizard.

Note the below script also calculates Annualized Return on Investment (RoI) as CAGR is equal to that when we consider only initial and final values of an asset:

Code:
# CAGR Calculator
# Pensar, 03.05.2021
# Updated by omsrisagar, 5/31/2024

input yearsback = 1; # can enter fractional as well like 0.5

def period = AggregationPeriod.DAY;

def daysback = ROUND(yearsback * 252, 0); # 252 trading days in a year

def o = open(period=period)[daysback];

def o1 = if !IsNaN(o) then o else if !IsNaN(o[1]) then o[1] else o[-1];

def c1 = if !IsNaN(close) then close else  if !IsNaN(close[1]) then close[1] else close[-1];

def CAGR = Power(c1/o1, 1/yearsback)-1;

plot CAGR_Percent = CAGR * 100;

AddLabel(1,"CAGR: " + AsPercent(CAGR), color.white);

# end code
 
Last edited by a moderator:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
294 Online
Create Post

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top