Sharpe of Buy and Hold

Hi,

How would I calculate the Buy & Hold Sharpe of a symbol and use that B&H Sharpe in a rotational strategy, as in the below instead of ROC?
Thanks,

Mike


SetBacktestMode( backtestRotational );
SetOption("MaxOpenPositions",5);
//SetOption("WorstRankHeld",5);
SetPositionSize( 20, spsPercentOfEquity );
PositionScore = ROC( Close, 3):


I found some code to calculate the Sharpe as a custom metric but cannot find anything re how to calculate the Sharpe based on B&H.
Also, how do I reference the "SharpeRatio2" in the positionscore function, assuming I can calculate SharpeRatio2 on the B&H of the symbol?

SetCustomBacktestProc("");
if( Status("action") == actionPortfolio )
{
bo = GetBacktesterObject();

bo.Backtest(); // run default backtest procedure

st = bo.GetPerformanceStats(0); // get stats for all trades
eq = bo.EquityArray;

SharpeRatio2 = st.GetValue("CAR")/(sqrt(252)*StDev(((eq-Ref(eq,-1))/Ref(eq,-1))*100, BarCount -2 ));

 Here we add custom metric to backtest report
bo.AddCustomMetric( "SharpeRatio2", LastValue(SharpeRatio2) );
StaticVarSet("MySharpe", SharpeRatio2 );
}

SetBacktestMode( backtestRotational );
SetOption("MaxOpenPositions",5);
SetOption("WorstRankHeld",5);
SetPositionSize( 20, spsPercentOfEquity );
PositionScore = ROC( Close, 3):

image

Maybe look in this direction... I tried it, but it gave an "inf" sharpe... but I did not test it extensively. Maybe you get it working (don't forget to let us know)

Thanks Henri. I did see this on the Report so I guess the stat is available but not sure how to calculate and call it in a script for each & every symbol in a Watchlist.

Best,

Mike

@reds You want to rank your securities by Sharpe Ratio instead of ROC. The number you are getting in the above code or from AmiBroker (will give you the Sharpe Ratio of trades) is probably only available to you after you run a backtest.

All you need is to replace your ROC(C, 3) with a formula for calculating the Sharpe Ratio of your securities, bar-by-bar. That can be found in hundreds of places on the internet. If you want to start with the original author The Sharpe Ratio

Simplified,
image

But I think that for your needs you can further simplify because the “Risk Free Rate of Return” is going to be the same for all securities that you are doing the calculation upon so really you only need,

Rate of Return / St Deviation of Rate of Return

And use that to do your ranking. Coded it might look something like this

// you wrote that you want a Buy & Hold Sharpe, so I assume as it would
// be measured from the first bar you are analyzing
BarsInAnalysis  = Cum( Status( "barinrange" ) ); 

avDailyRt = MA(ROC(C, 1), BarsInAnalysis);

sdDailyRt = StDev( ROC(C, 1), BarsInAnalysis);

// not a real Sharpe ratio but an estimate for comparison purposes
sRatio = ( avDailyRt /sdDailyRt )  *  sqrt( 252 );  // annualizing the daily measure

Or perhaps you are using Monthly bars instead of Daily? ( "ROC(C,3)" )

// or if you are using monthly data
sRatio = ( avDailyRt /sdDailyRt )  *  sqrt( 12 );  // annualizing the Monthly measure

3 Likes

That works perfectly, thanks Larry!

Larry your code works perfectly, ranking and taking positions by Sharpe.

With rotational trading, can we condition the code to only go long (buy) when the Sharpe is >1? In the below I added "+100" to the Sharpe ratio so it will only go long, but it does not accomplish only buying when the sRatio is >1 since it holds the top 5 and the top 5 may be below 1.

Thanks,

Mike


BarsInAnalysis  = Cum( Status( "barinrange" ) ); 

avDailyRt = MA(ROC(C, 1), BarsInAnalysis);

sdDailyRt = StDev( ROC(C, 1), BarsInAnalysis);

// not a real Sharpe ratio but an estimate for comparison purposes
sRatio = ( avDailyRt /sdDailyRt )  *  sqrt( 252 );  // annualizing the daily measure

SetBacktestMode( backtestRotational );
SetOption("MaxOpenPositions",10);
SetOption("WorstRankHeld",10);
SetPositionSize( 10, spsPercentOfEquity );
PositionScore = sRatio+100; 

Read here
https://www.amibroker.com/guide/afl/enablerotationaltrading.html

The score (PositionScore) for all securities is calculated first. Then all scores are sorted according to absolute value of PositionScore. Then top N are choosen to be traded. N depends on available funds and "max. open positions" setting. Backtester successively enters the trades starting from highest ranked security until the number of positions open reaches "max. open positions" or there are no more funds available. The score has the following meaning:

  • higher positive score means better candidate for entering long trade
  • lower negative score means better candidate for entering short trade
  • the score of zero means no trade (exit the trade if there is already open position on given symbol)
  • the score equal to scoreNoRotate constant means that already open trades should be kept and no new trades entered
  • the score equal to scoreExitAll constant causes rotational mode backtester to exit all positions regardless of HoldMinBars. Note that this is global flag and it is enough to set it for just any single symbol to exit all currently open positions, no matter on which symbol you use scoreExitAll (it may be even on symbol that is not currently held). By setting PositionScore to scoreExitAll you exit all positions immediatelly regardless of HoldMinBars setting
PositionScore = Iif(sRatio>1, sRatio+100, 0); 

Not true. It is not a single number.
It can be retrieved on bar-by-bar basis.

4 Likes

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.