Rotational Trading: Stay with the best

This post is about a revised rotational trading system. I’m a big fan of rotational trading. Please read the first post to get more about the why. While I DON’T think rotational trading is better than the system types that buy into weakness and sell into strength, I do think it’s an excellent way to diversify your trading systems.  A while ago I had two posts (first second) on  rotational trading, since then I continued my research and further worked on my database. So the system I’m going to present is build on a survivorship bias free  database, hence it carries a lot more validity than the previous version.

Market filter

  • The system is only going to be traded when the NASDAQ100 idx is above the 20 or 200 days moving average. To say it in other words, the NDX100 has to be bellow 20 or 200 days moving average in order to prevent execution.
  • Yes I know, some of the key elements of rotational trading is to avoid market timing. However, from an emotional point of view I find it incredible difficult to execute long trades under these circumstances.

Scoring

  • As previously, I’ve used TSI to measure trend strength. We only want to be invested in strongly trending stocks. Remember, TSI only measures strength of the trend and not direction.
  • For trend direction i suggest to use a simple ROC(200).  The value of 200 isn’t optimized. Doing some optimization you might get better returns, but it’s good enough for me.
  • You might want to use only the absolute value of the ROC(200).  When the market is rebounding after an extremely sharp sell off, it’s better to buy oversold stocks.

Ranking

  • Once you get the two scores, you have to combine them in order to get one unique rank.

Position

  • NASDAQ 100 stocks
  • Top five stocks, rebalanced weekly (Friday)
  • 20% capital

Result

  • Bellow you find the results from January 2001 to September 2010. I like to exclude the crazy NASDAQ times from 1999-2000 as I think they have been extremely unusual on either side.
  • No commission or slippage calculated
  • Database includes delisted stocks, index constitution is revised at day of change.

  • The impact of survivorship bias (link): I re-run the same system based on a database with survivorship bias. Basically i used the NDX100 index as of today. The systems shows better performance, of course:  CAR: 62% with a slightly lower draw-down

Conclusion

The simple system presented delivers decent performance and a good starting point for your own research. Past results are no guarantee for future returns. I do NOT trade the system as presented here. Do your own research. In case you can’t or won’t do your own research, then follow David Varadi from CSS Analytics. Every week David posts his Top10 picks for the coming week. This year his picks have outperformed the index by about 10% and there are still three month left.

AmiBroker code

The AmiBroker code is extremely tricky this time, because AmiBroker doesn’t support the ranking approach as presented.

#include <ndx100history.afl>;
#include <Boilerplate.afl>;
#include <Generall.afl>;
SetCustomBacktestProc(“formulas\\include\\cbt_midlevel.afl”,True);
SetOption(“CommissionAmount”,0.00);
SetOption(“InitialEquity”, 100000);
SetTradeDelays(0,0,0,0);
SetBacktestMode( backtestRotational );
EnableRotationalTrading() ;
SetOption(“MaxOpenLong”,5);
SetOption(“MaxOpenPositions”,5);
SetPositionSize( 20, spsPercentOfEquity);
IndexMember = NDX100member(Name(),DateNum());
idx         = Foreign(“$NDX”,”Close”);
Listnum     = 1; //here you enter the number of the NDX100 watchlist you want to use
list        = CategoryGetSymbols( categoryWatchlist, Listnum);
Rank1_Score = 1;
Rank2_Score = 1;
Rank3_Score = 1;
Rank4_Score = 1;
Rank5_score = 1;
Rank1_bench = trendstrength();
Rank2_bench = abs(ROC(Close,200));
Rank3_bench = 1;
Rank4_bench = 1;
Rank5_bench = 1;
MArketOk    = idx > MA(idx,20) OR idx > MA(idx,200);
exec        = IIf(Name()==”AAPL”,1,0);   //hard coded in order to improve performance, need to to this only once per bar for all stocks
for( i = 0;( ( sym = StrExtract( List, i ) ) != “”) ; i++ )
{
Maxitems    = i+1;
}
if (EXEC[1]==1)
{
for( i = 0;( ( sym = StrExtract( List, i ) ) != “”) ; i++ )
{
Member   = NDX100member(sym,DateNum() );
SetForeign(sym);
sym_v1   = IIf(member,trendstrength(),0);
sym_v2   = IIf(member,abs(ROC(Close,200)),0);
sym_v3   = 1;
sym_v4   = 1;
sym_v5   = 1;
RestorePriceArrays();
StaticVarSet(“IDXMember”+(i+1),member);
StaticVarSet(“RANK1″+(i+1),sym_v1);
StaticVarSet(“RANK2″+(i+1),sym_v2);
StaticVarSet(“RANK3″+(i+1),sym_v3);
StaticVarSet(“RANK4″+(i+1),sym_v4);
StaticVarSet(“RANK5″+(i+1),sym_v5);
}
}
for( i = 1; i < Maxitems; i++ )
{
Idx         = StaticVarGet( “IDXMember”+i);
Rank1       = StaticVarGet( “RANK1″+i );
Rank2       = StaticVarGet( “RANK2″+i );
Rank3       = StaticVarGet( “RANK3″+i );
Rank4       = StaticVarGet( “RANK4″+i );
Rank5       = StaticVarGet( “RANK5″+i );
Rank1_Score = Rank1_Score + IIf( Rank1_bench > Rank1 AND idx AND rank2!=0,1,0);
Rank2_Score = Rank2_Score + IIf( Rank2_bench > Rank2 AND idx AND rank2!=0,1,0);
Rank3_Score = Rank3_Score + IIf( Rank3_bench > Rank3 AND idx AND rank2!=0,1,0);
Rank4_Score = Rank4_Score + IIf( Rank4_bench > Rank4 AND idx AND rank2!=0,1,0);
Rank5_Score = Rank5_Score + IIf( Rank5_bench > Rank5 AND idx AND rank2!=0,1,0);
}
ComboRank   = IIf(indexmember,Rank1_score + Rank2_Score ,0);
Score                 = IIf(marketok AND ComboRank>0 AND IndexMember AND DateNum()<=1100901,ComboRank,0);
Condition1      = (DateNum()>=1010101 AND DayOfWeek()==5) OR DateNum()>=1100901;
PositionScore= IIf(Condition1,score,scoreNoRotate);
Rank1_Score  = IIf(indexmember,Rank1_Score,0);
Rank2_Score  = IIf(indexmember,Rank2_Score,0);
Rank3_Score  = IIf(indexmember,Rank3_Score,0);
Rank4_Score  = IIf(indexmember,Rank4_Score,0);
Filter       = DateNum() == EndValue(DateNum());
AddColumn(Rank1_bench, “Rank1_Value”, 1.2);
AddColumn(Rank1_score, “Rank1_Score”, 1);
AddColumn(Rank2_bench, “Rank2_Value”, 1.2);
AddColumn(Rank2_score, “Rank2_Score”, 1);
AddColumn(Rank3_bench, “Rank3_Value”, 1.2);
AddColumn(Rank3_score, “Rank3_Score”, 1);
AddColumn(Rank4_bench, “Rank4_Value”, 1.2);
AddColumn(Rank4_score, “Rank4_Score”, 1);
AddColumn(Rank5_bench, “Rank5_Value”, 1.2);
AddColumn(Rank5_score, “Rank5_Score”, 1);
AddColumn(ComboRank, “Combo_Rank”, 1);
SetSortColumns(-5,-3);
About these ads

Comments

  1. This looks like a great system! I wonder how much more upside there is from chaning the ROC(200) parameter. I personally use a system where I take the average of ROC(20) ROC(50) and ROC(100).

  2. The market filter is not clear. Any of the two sentences should say “20 AND 200″, instead of “20 or 200″, INHO.
    Thank you for your posts

    • Hello Orion.

      no, i trade the system when either criteria is meet. Either IDX>MA20 or IDX>MA200.

      That’s the line of code i use: MArketOk = idx > MA(idx,20) OR idx > MA(idx,200);

      • Ilya Malikov says:

        Hello Frank, First of I wish you a good year 2011:)

        According the market filter, I am still not sure about 2 special situations.
        1) The idx is under the MA20 but above MA200 will you open the trade or not?
        2) The idx is above MA20 but under MA200, will you open the trade or not?

        Early thanks for your smart answers to this silly questions:)

  3. Aristotle says:

    I’m not clear on the Trend rating, does the trend score of 70 as an example, represent a 200 D ROC of 70%?

  4. hi Frank,
    it is a bit of a pain to try this on different watchlists by constantly changing the hardcoded name of the
    watchlist and the first symbol in the watchlist in the script. I have used in my programs the following mechanism (which you may already be aware of) to remove this hardcoding.. (I am replacing your code with the following lines)

    //to get the current watch list number
    EnableScript(“jscript”);

    script = GetScriptObject();

    Listnum = script.curWatchListNum();

    //to get the first symbol in the watch list..
    exec = IIf(Name() == StrExtract(List,0),1,0); //hard coded in order to improve performance, need to to this //only once per bar for all stocks

    hope it helps. To give credit where it is due, most of this is derived from amibroker user group.

    rgds
    bgpl

  5. For some reason, the javascript code got removed from the earlier comment.. mostly due to the formatting..

    EnableScript(“jscript”);
    //Here remove the word space”

    script = GetScriptObject();

  6. oh boy.. sorry about that.. its getting real messed up. Hope this works..

    put this function:

    function getAAWatchListNum() {
    var ab = new ActiveXObject(“Broker.Application”);
    var aa = ab.Analysis;

    return aa.Filter(0, “watchlist”);
    }

    within the separators “”

  7. Hello Frank,
    Are the “include” files required to run this system? If so, can you please email them to me?

    Thanks for sharing.

    Burger

  8. Frank,

    When I sum up 2009 monthly returns from your chart in excel, I get 89.6 not 120

    Thoughts?

    Dave

  9. oh duh, brain must not have been functioning last night . . .

  10. Frank,

    the only include file you realy need is the NDX100 one, because it eliminates the survivorship bias.

    Yes. Can you throw a bone on how to get the start date and end date in afl? I would think each symbol will need to be hard coded, correct?

    Regards,

    John

  11. After much grief I finally got the code to work. It was the copy/paste process from html to AFL that was causing issues such as quotes not pasting correct. Anyway, works great and thanks Frank for a fine program. Here is a possible suggestion for ranking called Most Anchored Momentum. It is outlined here:

    http://www.actwin.com/kalostrader/MAM-Rev3.PDF&pli=1

    • Aristotle says:

      Burger, I took a look at the MAM paper last night. Do you think if you wanted to try that for say 6 month ROC, that you’d use something like 3DEMA/126SMA?

  12. Fantastic post Frank! I am also a big fan of rotational strategies and like you I think that rotation must be combined with timing. This really is A Grade research. Thanks for sharing!

    One way that I have found to improve results further is to identify the best industry groups, trade only the top stocks in those groups and only trade in the direction of the broad market. Are you panning on having any of your strategies tracked and independently verified moving forward?

    Keep up the great work!
    Cheers
    Derry

  13. The reason I ask about having a public track record is that there is theory and there is practice and they are very different. You have some great ideas so laying out how they perform (and your ability to execute them) in real time would be the logical next step. I use timertrac.com but there are many different options that you may like to consider.

    Cheers
    Derry

  14. Aristotle says:

    Frank, would it be much trouble to run the test with 10 stocks held instead of 5?

    Also, how much does the market filter add to returns?

    • Hello Aristotle,

      running this with 10 stocks and 10% you get

      RAR: 49.65%
      CAR: 37.54%
      Trades: 827
      DD: -46.13%

      Running the system with 5 positions without a market filter would result about 10% a year. In this case i would suggest to hedge

      Frank

  15. I hate to ask a newbie question here but this system is a theory I have been thinking about for awhile and would love to play around with it. I am a tradestation coder but new to amibroker

    how do I build these three initial files
    #include ;
    #include ;
    #include ;

  16. Would like to ask whether you’re implementing the roc outright or using the absolute value?

    Wouldn’t there be a problem if you used the absolute value as if a stock is trending downwards, you’ll get a high TSI and high absolute value of ROC which combining the two rankings, might wrongly signal a buy?

    • Hello Yish,

      I’m using the %ROC value (not the absolute ROC value)

      I agree with your concern, that’s why I would trade that only in a healthy market (close above MA20 or MA200).

      Regards,
      Frank

      • Thanks for clarifying frank. Also, if say you got long the 5 stocks when the index was trading above the dmas, what happens if the index goes below the dmas the following week? Would you exit the stocks and wait for the index to me above the dmas again to put on the trade?

  17. Hi Frank,

    Excellent ranking routine.

    One question. For your EXEC, if you use EXEC = iif(status(“stocknum”)==1,1,0) instead of Name()==”AAPL” wouldn’t that give you execution control for any indice and not have to rely on the identifying the symbol of the first stock in the index? Or is there another side effect that you are trying to avoid by using AAPL?

    Thaks,
    Carl

    • Hi Carl,

      BGPL made me aware of this improvement and I’m using it for my own system as well. Next time I post a revision of this system I’m going to include it. The same for listnum…

      Frank

  18. Aristotle says:

    I just realized that you changed the timing filter from 30 & 200 to 20 & 200. I assume 20 tests out better than 30?

    Thanks,

  19. Hi!
    I suppose is a silly question, but I can not test the system because of the lines:

    IndexMember = NDX100member(Name(),DateNum());
    and
    Member = NDX100member(sym,DateNum() )

    I don’t recognize such a function ‘NDX100member’. Should it be in an auxiliary file?
    I don’t ask for the non-supervivorship Nasdaq bias file, I understand Frank’s reasons, and I just want to test the system with survivorship bias, but.. I should be doing something wrong..

    Thanks any answer..

    • Hello Gonzaga,

      just write IndexMember = TRUE …

      because it’s my function for checking if the stock is part of the index at any given day.

      Frank

      • Thanks Frank, but I have still a trouble.
        The other line,

        Member = NDX100member(sym,DateNum() )

        still crash in Ami. If I set

        Member = true; // instead of Member=NDX100member(sym,DateNum() )

        the code crash in the line

        StaticVarSet( “IDXMember” + (i+1), member)

        because ‘Member’ has to be a ticker, not a boolean value. ( the error is “Argument #2 has incorrect type (the function expects different argument type here) ” )

        As I don’t really understand the code, (several lines are a mistery), I don’t know what to do..

        Thanx in advance..

  20. Hello Frank,

    Just to let you know there is a simpler way in AFL to create a “Dynamic list of Stocks”.

    1. By way of improting from a CSV file, automatically create another ticker with an extention for each stock with in out information in a price field. eg if the stock is MSFT then new ticker is MSFT-Survivor and is it is in the index it is coded as 1 for the close field and if it is out of the index it is coded as “0″ for the Close field. Of course you need to play with the excel get the CSV file like adding the extension to the tiker name and in/out info using excel functions but for THIS task it is much easier to play with excel than AFL.

    2. Using the AFL Foreign function, determine the membership of the index when coding in AFL.

    I have attached another code which I used for another project. as an example for the item 2.

    _SECTION_BEGIN( “Use_a_specific_InOut_List”) ;

    // Use a Specific InOut List; List In = 1, List Out = 2 for close of the list

    Use_a_specific_InOut_List = ParamList(“Use_a_Specific_InOut_List”, “No,Yes”,defaultvar = 0);

    if ( Use_a_specific_InOut_List == “Yes” )
    {
    List_Name =ParamStr(“Name of the In Out Stock List”, “-Star”);

    // Stock List Selection
    // Extract Foreign Data
    sym = Name() + List_Name ;

    SS = 0;
    ListIn = 0;
    ListOut = 0;

    SS = Foreign( sym , “Close” ) ;

    ListIn = IIf(SS == 1, 1, 0);
    ListOut = IIf(SS == 2, 1, 0);

    List = Flip(ListIn ,ListOut );

    Plot( List , “List_Name”, colorBlue, styleOwnScale|styleArea|styleNoLabel,-0.1,50);

    }
    _SECTION_END();

    Regards

    • Hello Asanka,

      thanks for your code and contribution here. Why would you want to do that? Would you use that to replace my AFL function that checks for index membership?

      Regards,
      Frank

      • Hello Frank,

        Yes so you don’t have to hard code your AFL function – with few excel functions CSV file can be created.

        But in no way I am suggesting you should do that because you have already done it. !!

        Regards

        Asanka

  21. No one else asked about this, so I must be missing something obvious, but what is this file:

    SetCustomBacktestProc(“formulas\\include\\cbt_midlevel.afl”,True);

    the cbt_midlevel.afl ?

    and where would I find it?

    ges

    • Hello Ges,

      you don’t need the line to reproduce the results. I use CBT in this particular case to calculate spcific KPI’s.

      However, sent you an email containing the CBT AFL code.

      Frank

      • Hello Frank,

        I want to ask for the cbt_midlevel.afl too. May I can get it as exercise-example.

        Regards from Stuttgart

        Helmut

  22. Hello Frank,

    very interesting study. Why is not possible to send a Amibroker script for testing without your add ons with
    survivorship Nasdaq bias file. So we can test ourselfs and discuss with further ideas. I know it is
    a lof of work for this survivorship issues. All other issues can everybody add on, but if I have your basic idea in a code then everybody will play and add ideas.

    • Hello Thomas,

      you just need to change a line or so in the AFL statement and remove the check.

      ” .. AND IndexMember ” remove the check

      That’s pretty easy.

      Frank

  23. Hello Frank,

    actually it is not so pretty easy because if you cancel member then your staticvarset is missing this.
    Could send me the the adjusted code without any survivorship issues.

  24. You did this suggestion above to someone else, but if i do this you get LN 43 Col 24 Error 30, Syntax error
    with member = NDX100member(sym,DateNum() ); And by the way I exchange trendstrength() for
    TSI in the script as
    Ratio = abs(Close-Ref(Close,-10))/ATR(10);
    TSI = MA(MA(Ratio,10),100);

    this is not working but I did your suggestion:

    SetOption(“CommissionAmount”,0.00);
    SetOption(“InitialEquity”, 100000);
    SetTradeDelays(0,0,0,0);
    SetBacktestMode( backtestRotational );
    EnableRotationalTrading() ;
    SetOption(“MaxOpenLong”,5);
    SetOption(“MaxOpenPositions”,5);
    SetPositionSize( 20, spsPercentOfEquity);

    Ratio = abs(Close-Ref(Close,-10))/ATR(10);
    Trendstrength = MA(MA(Ratio,10),100);

    IndexMember = True;//NDX100member(Name(),DateNum());
    idx = Foreign(“$NDX”,”Close”);
    Listnum = 0; //here you enter the number of the NDX100 watchlist you want to use
    list = CategoryGetSymbols( categoryWatchlist, Listnum);
    Rank1_Score = 1;
    Rank2_Score = 1;
    Rank3_Score = 1;
    Rank4_Score = 1;
    Rank5_score = 1;
    Rank1_bench = Trendstrength;//trendstrength();
    Rank2_bench = abs(ROC(Close,200));
    Rank3_bench = 1;
    Rank4_bench = 1;
    Rank5_bench = 1;
    MArketOk = idx > MA(idx,20) OR idx > MA(idx,200);
    //exec = IIf(Status(“stocknum”)==1,1,0)
    exec = IIf(Name()==”AAPL”,1,0); //hard coded in order to improve performance, need to to this only once per bar for all stocks
    for( i = 0;( ( sym = StrExtract( List, i ) ) != “”) ; i++ )
    {
    Maxitems = i+1;
    }
    if (EXEC[1]==1)
    {
    for( i = 0;( ( sym = StrExtract( List, i ) ) != “”) ; i++ )
    {
    Member = NDX100member(sym,DateNum() );
    SetForeign(sym);
    sym_v1 = IIf(member,Trendstrength,0);//IIf(member,trendstrength(),0);
    sym_v2 = IIf(member,abs(ROC(Close,200)),0);
    sym_v3 = 1;
    sym_v4 = 1;
    sym_v5 = 1;
    RestorePriceArrays();
    StaticVarSet(“IDXMember”+(i+1),member);
    StaticVarSet(“RANK1?+(i+1),sym_v1);
    StaticVarSet(“RANK2?+(i+1),sym_v2);
    StaticVarSet(“RANK3?+(i+1),sym_v3);
    StaticVarSet(“RANK4?+(i+1),sym_v4);
    StaticVarSet(“RANK5?+(i+1),sym_v5);
    }
    }
    for( i = 1; i Rank1 AND idx AND rank2!=0,1,0);
    Rank2_Score = Rank2_Score + IIf( Rank2_bench > Rank2 AND idx AND rank2!=0,1,0);
    Rank3_Score = Rank3_Score + IIf( Rank3_bench > Rank3 AND idx AND rank2!=0,1,0);
    Rank4_Score = Rank4_Score + IIf( Rank4_bench > Rank4 AND idx AND rank2!=0,1,0);
    Rank5_Score = Rank5_Score + IIf( Rank5_bench > Rank5 AND idx AND rank2!=0,1,0);
    }
    ComboRank = IIf(indexmember,Rank1_score + Rank2_Score ,0);
    Score = IIf(marketok AND ComboRank>0 AND IndexMember AND DateNum()=1010101 AND DayOfWeek()==5) OR DateNum()>=1100901;
    PositionScore= IIf(Condition1,score,scoreNoRotate);
    Rank1_Score = IIf(indexmember,Rank1_Score,0);
    Rank2_Score = IIf(indexmember,Rank2_Score,0);
    Rank3_Score = IIf(indexmember,Rank3_Score,0);
    Rank4_Score = IIf(indexmember,Rank4_Score,0);
    Filter = DateNum() == EndValue(DateNum());
    AddColumn(Rank1_bench, “Rank1_Value”, 1.2);
    AddColumn(Rank1_score, “Rank1_Score”, 1);
    AddColumn(Rank2_bench, “Rank2_Value”, 1.2);
    AddColumn(Rank2_score, “Rank2_Score”, 1);
    AddColumn(Rank3_bench, “Rank3_Value”, 1.2);
    AddColumn(Rank3_score, “Rank3_Score”, 1);
    AddColumn(Rank4_bench, “Rank4_Value”, 1.2);
    AddColumn(Rank4_score, “Rank4_Score”, 1);
    AddColumn(Rank5_bench, “Rank5_Value”, 1.2);
    AddColumn(Rank5_score, “Rank5_Score”, 1);
    AddColumn(ComboRank, “Combo_Rank”, 1);
    SetSortColumns(-5,-3);
    _SECTION_END();

  25. Frank,

    This is really useful. I’d been putting off tangling with static arrays and this code is a great jumping off point.

    To get it to run I had to upgrade AmiBroker, because static arrays were only introduced around version 5.24.

    Pre 5.24 versions might explain some of the problems people were having with this code up thread.

    Please consider posting this code to the yahoo user list, as there is very little there re: static arrays.

    Keep the posts coming and thanks for sharing all your hard work,

    ftm

  26. You mention TSI as a software.
    Would be very helpful to have your system coded in their language as well.
    Anybody able here to do that?

  27. Hi Frank, where do I find following includes ?

    //#include ;
    //#include ;
    //#include ;

  28. Hi Frank,

    could you update the performance till now. How was the 2010 return and DD in %.
    Thanks.

  29. Ilya Malikov says:

    Hey Frank. If an NDX100 stock has an great TSi, and ROC but is total illiquide, what is your approach in such situation? Do you have any volume filters for the rotational trading?

    Early thanks!

    Ilya

    • Hello Ilya,

      not sure I understand your question. Based on my experience I haven’t seen any illiquide stock being part of the NDX100 / SP500. I theory that can be the case, just think of Volkswagen a few years ago. But this is an EXTREMELY rare scenario. That’s actually the reason why I trade SP500 / NDX100 stocks only.

      Frank

  30. Hi frank, great system to stimulate ideas. To confirm are the orders placed as market on close or market on open ?

    • Hi,

      Close2Close.

      However, I did a test on Open2Close … hardly any difference in performance.

      Frank

      • How do you realized Open2Close? I can set these paramaters in Amibroker Backtest settings (and in the code as well) but checking the results reveals that Amibroker is using for selling the same price that is defined for buying. E.g. Buy at Open, Sell at Close is carried out as Buy and Sell as Open.

        • Hello David,

          in my opinion there is bug in AmiBroker. The backtester takes the AFL specific commands, e.g. Buyprice = Close or Sellprice=Close….
          However, this isn’t true for rotational trading. In this case the backtester WILL always use the settings from the settings-page. Hence AFL comands are ignored.

          Frank

      • Hello Frank,

        I agree. But in my Amibroker environment work the parameters set in the settings-page neither. Close will carried at buy, independent from the sell parameters. Can you consider this behaviour as well?

        David

      • Hi David,

        i tested Open2Open trades. Didn’t find any issue. Changed settings manually to buyprice = open and sellprice = open

        Furthermore I’ve got this:
        SetTradeDelays(1,1,0,0);

        Frank

      • Hi Frank,

        Open2Close leads in my backtesting trade report to buyprice = open and sellprice = open instead of buyprice = open and sellprice = close if I compare the price shown in the backtest report with the original share prices.

        David

  31. Burkhard says:

    Hallo Frank,
    your approach is very nice. I read your article in Traders too, but it seems, that I didn’t understand your ranking algorithm fully.

    Is there no precedence between TSI and “Trend” (i.e. derived from ROC). What, if the stocks A to E have top five TSI, but “Trend” (however) is poor? Maybe, stocks V to Z are best in “Trend”, but their TSI is low. Do I misunderstand something, can you help?

    • Hello Burkhard,

      Thanks for your feedback. Both attributed are equal weighted. In theory what you described can happen, in practice it’s rarely the case.

      Regards,
      Frank

  32. Frank, what would be the results if you
    a) used the market filter AND only used ROC (200) for ranking the stocks?
    b) used the market filter AND only used TSI for ranking the stocks?
    Thanks.

  33. Hi Frank,

    Your rotational strategy is nice. I want to test the strategy in Indian index Nifty.

    I saw the following codes in the AFL
    #include ;
    #include ;
    #include ;
    SetCustomBacktestProc(“formulas\\include\\cbt_midlevel.afl”,True);

    May I know, how can I get those include files?

    Also the RSI/TSI formula is giving sintax errors:

    SetOption(“CommissionAmount”,0.00);
    SetBacktestMode( backtestRegular);
    SetOption(“InitialEquity”, 100000);
    tsi = trendstrength();
    LongCond = Close>MA(Close,50) OR ROC(Close,150)>0;
    Setup1 = Longcond==True AND ((tsi>1.65 AND RSI(2)<18) OR (tsi<1.65 AND RSI(2)1.65 AND RSI(2)<13) OR (tsi<1.65 AND RSI(2)= 1999 ) * sigScaleIn;
    Sell = (tsi>1.65 AND RSI(2) > 61) OR (tsi 39);

    SetPositionSize(33, spsPercentOfEquity );

    I feel that error is for the tsi = trendstrength();

    Where can I found the trendstrength() function?

    Waiting for your kind reply.


    Regards,

    Indrajit

  34. Hi Frank,

    What happens if a metric (such as TSI) gives exactly the same values for different stocks (E.g. TSI(A) = 1.4 and TSI(B) = 1.4)? In such cases, do both stocks get the same score?

    Regards,
    Wils

    • Hi Wils,

      yes, you can give them the same score.

      Frank

      • Thanks Frank. Have you considered other means of normalizing the scores across assets, such as percentile-rank or zero-mean-unit-variance? This way one can perhaps combine both continuous and discrete metrics.

        Wils

  35. Hi Frank,
    Could you post the code for:
    #include ;
    #include ;
    #include ;
    I could not find it.
    Thank you very much!

    • Hello,

      these are my own functions. You don’t need it to get the system running.

      #include ; -> function for survivorship bias free index constitution
      #include ; -> default settings
      #include ; -> prop indicators, e.g. TSI

      Regards,
      Frank

  36. Hi Frank – Excuse my ignorance…
    How to get these files listed on your amibroker code.
    #include ;
    #include ;
    #include ;
    SetCustomBacktestProc(“formulas\\include\\cbt_midlevel.afl”,True);

    Pontric

Trackbacks

  1. [...] Stay with the best: rotational trading (link) [...]

  2. [...] of month ago I had a few posts on rotational trading.  The essence of these posts is summarized here.  In this post I want to give you an update how the strategy has been doing since then. [...]

  3. [...] Engineering Returns and Sticking with the Best [...]

  4. [...] strong. Of course if you trade an intermediate trend-following system, such as the one presented here, you would have done better.  So the question is, how to benefit from an overbought market on the [...]

  5. [...] Rotational Trading: Stay with the best / strategy review [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 306 other followers

%d bloggers like this: