{ Function: _SharpeRatio Author: Mark Krisburg (MarkSanDiego) Updated: 06/03/07 Original version. 01/20/08 Remove output variable AbsSR. May calculate in calling routine, if needed. 09/01/08 8-12X speed improvement by using fast calculation techniques to update avgRR and using in-line code for standard deviation 09/12/09 clean up code 01/30/10 posted to forum USAGE: Add these variables to calling indicator: inputs: { for _SharpeRatio } SRPrice(TypicalPrice), SegLength(5), SegsPerYear(52), Segments(52), Offset(0), RiskFreeReturn(2), { annualized risk free return in percent. } CalcSeconds(60), { Recalculate SR every 'CalcTicks' tick. } Ref1(0.00001), Ref2(0), Ref3(0); vars: { for _SharpeRatio } intrabarpersist avgRR(0), { average return rate for segments } intrabarpersist sdRR(0), { standard deviation of return rates } intrabarpersist annRR(0), { annualized rate of return = RR * 12 (1 segment = 1 month) } intrabarpersist annSD(0), { annualized standard deviation of returns = sdRR * 12 (1 segment = 1 month) } intrabarpersist excessRR(0), { excess return = annualized rate of return - risk free return } intrabarpersist SR1(0), { Sharpe Ratio = Excess return / annualized standard deviation of returns } intrabarpersist SR2(0), { Sharpe Ratio = Excess return / annualized standard deviation of returns } intrabarpersist SR3(0), { Sharpe Ratio = Excess return / annualized standard deviation of returns } intrabarpersist SR4(0); { Sharpe Ratio = Excess return / annualized standard deviation of returns } Function usage: value1 = _SharpeRatio(SRPrice, SegLength, SegsPerYear, Segments, RiskFreeReturn, Offset, avgRR, sdRR, annRR, annSD, excessRR, SR); } inputs: Price(NumericSeries), SegLength(NumericSimple), { number of bars in each segment for calculating gains } { on daily chart, use =1: daily analysis, =5: weekly analysis, =20: monthly analysis } SegsPerYear(NumericSimple), { daily: 251 (251 trading days in a year ); weekly: 52; monthly: 12 } Segments(NumericSimple), { number of segments used to calculate Sharpe Ratio } { e.g., on daily charts with SegLength = 1 then Segments = 20 means twenty bars were used to calculate the Sharpe Ratio } RiskFreeReturn(NumericSimple), { typically this is the current CD rate available, expressed as percent (e.g., =2) } Offset(NumericSimple), { outputs: } avgRR(NumericRef), { average return rate for segments } sdRR(NumericRef), { standard deviation of return rates } annRR(NumericRef), { annualized rate of return = RR * 12 if each segment represents 1 month, or RR*52 if each segment represents 1 week } annSD(NumericRef), { annualized standard deviation of returns = sdRR * SqRoot(SegsPerYear) (i.e., SqRoot(12) if segment = 1 month) } excessRR(NumericRef), { excess return = annualized rate of return - risk free return } SR(NumericRef); { Sharpe Ratio = Excess return / annualized standard deviation of returns } vars: j(0), SqrtSegsPerYear(SquareRoot(SegsPerYear)), { square root of number of segments per year } x(0), y(0), index(0), { index for circular array RR } FirstPass(True), Sum(0), OldestRR(0), SumSq(0), Diff(0); arrays: RR[3000](0); { RR[i] = return rates for segment[i] Note: static arrays are 20X faster than dynamic arrays } once begin { calculation of standard deviations of gains requires at least 2 segments } if Segments <= 1 then RaiseRunTimeError("Function _SharpeRatio: Segments must be > 1"); avgRR = 0; sdRR = 0; annRR = 0; annSD = 0; excessRR = 0; SR = 0; end; if SegLength > 1 or FirstPass then begin FirstPass = False; Sum = 0; for j = 1 to Segments begin { load rates of return } index = Offset + SegLength*(Segments - j); y = Price[index + SegLength]; if y <> 0 then RR[j] = (Price[Index]/y - 1)*100 else RR[j] = 0; Sum = Sum + RR[j]; end; index = 0; avgRR = Sum / Segments; { average rate of return of segments } end else begin { SegLength = 1, subsequent pass } index = index + 1; { create circular index for array RR } if index > Segments then index = 1; OldestRR = RR[index]; y = Price[Offset + SegLength]; if y <> 0 then RR[index] = (Price[Offset]/y - 1)*100 else RR[index] = 0; avgRR = avgRR[1] + ( RR[index] - OldestRR ) / Segments; { average rate of return of segments } end; annRR = avgRR * SegsPerYear; { annualized the rate of return } // excessRR = annRR - RiskFreeReturn; { original Sharpe Ratio formula } excessRR = annRR - Sign(annRR)*RiskFreeReturn; { modification: reverse sign on RiskFreeReturn if annRR is negative } SumSq = 0; { calculate SD of rates of returns } for j = 1 to Segments begin Diff = RR[j] - AvgRR; SumSq = SumSq + (Diff * Diff); end; sdRR = SquareRoot(SumSq/Segments); { variance assumes total population, not sample } annSD = sdRR * SqrtSegsPerYear; { annualize the SD of the returns } if annSD <> 0 then SR = excessRR/annSD { calculate Sharpe Ratio } else SR = 0; _SharpeRatio = SR;