Saturday, November 26, 2011

ThinkScript Included - Growth Of 10K

At the bottom I have provided the ThinkScript source for the classic growth of $10,000 study that funds use to pitch investments to retail customers. I was surprised that this did not exist in the standard studies in the ThinkDesk trading platform so I am providing it, gratis. Here are some images of this study in action:


AAPL 10 Year Growth, 1 Month Candle 


SPY 10 Year Growth, 1 Month Candles
The solid green line represents the monthly growth of a $10,000 investment purchased once 10 years ago (BNH -Buy -N- Hold), while the dashed blue line represents the monthly growth of a $10,000 investment divided into 120 purchases, once a month for 10 years  (DCA - Dollar Cost Averaging) with $5 commissions and 0.2 APR interest paid on the idle portion of the 10K.

While it is awe-inspiring to see that $10,000 invested in AAPL 10 years ago is now worth $345,000, the SPY picture is an average performance that can't be ignored: $10,000 invested in SPY 10 years ago is worth only $10,232. (Note: The TOS data feeds for ETF's do not provide dividend information, so your actual performance would have been on the order 2-3%/year better. However, the sdi_passive study does model dividend reinvestment when the data is available.) There must be many more poor/average investments out there than a cherry-picked-with-hindsight high-flier like AAPL. (Note: that IPO purchasers of AAPL did not make money for the first 18 years.)

In my opinion, this means that it is dreadfully hard to find these high-fliers that you can buy and forget. There must be so much crash 'n burn out there that it would just not be practical for most of us small-dogs to just sit on investments. Be vigilent and work the time-advantaged strategies.

#########################
# sdi_passive - plot results of buy-and-hold and dollar-cost-averaging
#hint: shows the growth of $10,000 (configurable invested by the two basic passive-investment strategies: buy-and-hold (bnh) and dollar-cost-averaging (dca). dividend reinvestment is accounted for if the data is available(alas, etf's generally do not have this data available.) for dca the $10,000 is invested in equal periodic investments over the duration of the chart as determined by dcaFrequency. commissions are accounted for. idle money accrues interest, compounded per bar, but accrued interest is not invested. rev:1.2.0 http://www.smalldoginvestor.com
# author: allen everhart
# date: Oct 1, 2011
# rev. 1.2.0 17aug2013 -
#    added dcaFrequency to produce more realistic results on aggregationPeriod.DAY
#    start the study on barnumber() 3 to avoid a thinkScript bug.
#    added chart labels to break down the dividends and interest earned.
# copylefts reserved. This is free software. That means you are free
# to use or modify it for your own usage but not for resale.
# Help me get the word out about my blog by keeping this header
# in place.

declare lower;
input totalInvestment = 10000;
input commission = 5.0;
#hint buyAt: Other calculators may differ on this so choice is provided here for comparison purposes.
input buyAt = { default open, close} ;
#hint APR: annual percentage rate applied to idle money.
input APR=0.2;
def purchasePrice =
  if buyAt == buyAt.close then
    close
  else
    open;
#plot pp = purchasePrice;
input dcaFrequency = 21 ;
#hint dcaFrequency: number of bars per purchase for dollar cost averaging. there are about 21 trading days per calendar month.
def aggFact = getAggregationPeriod()/(12*AggregationPeriod.MONTH);
def intRate = (APR/100) * aggFact;
#plot af = aggFact ; #diagnostic
def startBar = 3 ;
def barn =
  if isNaN(close) then 0
  else if barnumber() < startBar then 0
  else barNumber()-startBar+1; #bar numbers origin to 1


def divy =
  if isNaN(getDividend()) then 0
  else getDividend() ;
def dripSharesPerShare =
  if buyAt==buyAt.open && divy[1]>0 then
    divy[1]/purchasePrice
  else if buyAt==buyAt.close && divy>0 then
    divy/purchasePrice
  else
    0 ;
#plot dss = dripSharesPerShare ;
def numberOfPurchases = floor(0.5+highestAll(barn)/dcaFrequency);
def periodicInvestment = totalInvestment/numberOfPurchases;
#AddLabel(1, Concat("Periodic Invest:", periodicInvestment));
#addlabel(1, Concat("Commissions:", numberofPurchases*Commission));
def moneyInvested =
  if barn == 0 then 0
  else if barn == 1 then periodicInvestment
  else if barn>1 && barn % dcaFrequency == 0 then
    periodicInvestment + moneyInvested[1]
  else
    moneyInvested[1]
;
#plot mi=moneyInvested ; #diag
################ BNH ####################

def bnhshrs =
  if barn == 0 then 0
  else if barn == 1 then
    (totalInvestment-commission)/purchasePrice
  else
    bnhshrs[1]*(1+dripSharesPerShare)
;
def bnhdiv =
    if barn == 1 then 0
    else if barn > 1 && divy[1] then bnhdiv[1]+divy[1]*bnhshrs
    else bnhdiv[1];
#plot bd= bnhdiv; #diagnostic
addlabel(1, concat("bnhdiv:",round(bnhdiv,2)), color.DARK_GREEN) ;
plot bnh = if barn>0 then bnhshrs*close else double.NaN;
bnh.setDefaultColor(color.DARK_GREEN);
########################### DCA ############################
def dcashrs =
  if barn == 0 then 0
  else if barn == 1 then
    ((periodicInvestment-commission)/purchasePrice)
  else if barn>1 && barn%dcaFrequency == 0 then  
    ((periodicInvestment-commission)/purchasePrice)+(dcashrs[1]*(1+dripSharesPerShare))
  else
    dcashrs[1]*(1+dripSharesPerShare)
;
#plot ds=dcashrs ; #diagnostic
# if we buy at open then maybe exclude a periodicInvestment from interest calc
def idleMoney =
  if barn==0 then 0
  else if barn==1 && buyAt==buyAt.open then
    (totalInvestment-periodicInvestment)*(1+intRate)
  else if barn==1 && buyAt==buyAt.close then
    (totalInvestment*(1+intRate)) - periodicInvestment
  else if barn>1 && barn%dcaFrequency == 0 && buyAt==buyAt.open then
    (idleMoney[1]-periodicInvestment)*(1+intrate)
  else if barn>1 && barn%dcaFrequency == 0 && buyAt==buyAt.close then
     (idleMoney[1]*(1+intRate)) - periodicInvestment
  else
     idleMoney[1]*(1+intRate)
;
plot dca = if barn>0 then (dcashrs*close) + idleMoney else double.NaN;
dca.setDefaultColor(color.BLUE);
dca.setstyle(curve.MEDIUM_DASH);
addlabel( 1, Concat("dcaint:", round(idleMoney,2)), color.BLUE );
def dcadiv =
    if barn == 1 then 0
    else if barn > 1 && divy[1] then dcadiv[1]+divy[1]*dcashrs
    else dcadiv[1];
#plot dd= dcadiv; #diagnostic
addlabel(1, concat("dcadiv:", round(dcadiv,2)), color.BLUE);

############################################

No comments:

Post a Comment