Combining TSI and RSI into a winning swing trading system [Part II.]

In part two of this series we are going to look into how to improve the exit. Currently the exit is using a RSI(2)>50.  As for the entry we are going to look at two very different outcomes

a.)    High CAR, low system quality numbers

b.)    Lower CAR, high system quality numbers

RSI>82 is having the highest absolute returns. However a lot of time (=low RAR%) is spend in the market in order to gain this return.  Vice versa RSI>39 is exiting fast, showing a high consistency  in returns (=high Sharpe ratio),  but leaving some returns behind.

Let’s use TSI to moderate the RSI exit value.

As in the previous post we will define the TSI threshold as 1.65. If the market is above 1.65 it’s in a trending environment and we want to exit the trade later than in a non trending environment. That makes sense! The best value to exit in a trending environment is above 61 while it’s recommended to exit at 39 in a non trending environment.

System quality numbers stay the same while absolute returns have improvement significantly without increasing max. draw down.


The system outlined has already pretty good risk adjusted returns and metrics. It should be possible to trade for many people as it’s end of day trading with a decent frequency of trading. You can expect about 1-2 trades a month with an average holding period of less than 5 days. Emotionally it’s easy to trade as the high %of winners and a ProfitFaktor of 3.6 indicate. Of course slippage and commission have to be deducted, but with an average trade of 1.31% that’s not an issue, especially not for index trading.   The system has been tested over many years, starting from 1999. Hence it survived in a number of very different market environments. The returns are consistent over the years (no severe outliers) .

As you have seen in this post, TSI is good moderator in separating trending vs. non-trending conditions.



How to further improve this system

  • Volatility hasn’t been taken into account: (delayed) entries might be better under certain volatility conditions.
  • The system uses a fixed position size. You might want to look into making the position size more adaptive to current volatility.
  • Intermediate oversold conditions aren’t taken into account. You might want to enter a trade earlier (=higher RSI value) when intermediate timeframe is already oversold. I like to use DVI for that purpose.


AFL Code

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)<8));
Setup2       = Longcond==False AND ((tsi>1.65 AND RSI(2)<13) OR (tsi<1.65 AND RSI(2)<2));
Buy          = ((Setup1 OR setup2) AND Year() >= 1999 ) * sigScaleIn;
Sell         = (tsi>1.65 AND RSI(2) > 61) OR (tsi<1.65 AND RSI(2) > 39);
SetPositionSize(33, spsPercentOfEquity );
About these ads


  1. Very robuts system!
    Have you tried a sell side version of the TSI RSI?
    Also, the use of 1.65 on the TSI, is this value optimized or is there a rationale for it?

    • Hi Alex,

      No, I didn’t look at all into a short version of this specific system I posted here. I don’t expect people to use this system and JUST trade it. I wanted to drive home the point of using TSI as a moderator of RSI.

      A good way to short…. short overbought stocks / SPY that show a weak trend (TSI <1.65). That's what i do for counter trend shorting.

      Regarding 1.65 level: that's the best point to separate trending vs non trending. It's pretty stable, .e.g the same for NDX100 stocks.


  2. Hi Frank

    truly great stuff, I am looking at implementing this for the trade of FOREX. I expect to use TSI to indicate when the particular currency is positively trending (using the 1.65 level), then go long or short at the appropriate time.

    Have you looked at using this indicator for forex?


    • Hello,

      Thanks for your feedback. I’m not a currency expert. However please do some research in order to assure 1.65 is the RIGHT level as i haven’t tested this for FX market. I would also recommend TSI not to use as a signal for enter a trade. TSI can act as a filter, but the actual entry should be more timely than what TSI can provide you with for swing trading.

      All the best,

  3. Ilya Malikov says:

    Hi Frank, How is the logic for stops by this strategie TSI+RSI? What should happen, that you accept a loosing trade?

    Early Thanks:)

  4. Hello Ilya,

    i do not understand your question. The position will be sold as soon as the exit criteria is hit.


  5. Oops, now I’m seeing that my post got deleted because of that, I guess.

    So here it is again

    “Hi Frank, thanks for introducing your system idea!

    What does trendstrength(); mean in your AFL code, because I’m getting an error when executing your backtesting formula. It seems to be a custom function being in your include folder? I simply replaced it with
    Ratio = abs( C – Ref(C, -10) ) / ATR(10);
    TSI = MA( MA( Ratio, 10 ), 100 );

    But my results are different from yours then. Are there any settings to consider?

    Other question. You say that you are trading the German Dax Spot. What instrument are you trading it with?


    Good trades and nice weekend!

    Mr. T”

    • Hello Mr. T.

      Trendstrenght() = TSI … an indicator I developed. You find everything you need to know about TSI in the top-level navigation. There is also the detailed source-code.

      Trading the DAX would be done using FDAX (or CFD’s).


  6. Hi Frank, thanks for info.

    But I’m still a bit confused. You wrote in your explanation part one that it is calculated on DAX spot or cash index but FDAX isn’t Dax Spot, it’s the DAX Future index. DAX Spot has different start and ending times than FDAX. FDAX is traded on EUREX from 08:00 to 22:00 (CET) but DAX Spot is just calculated from 09:00 to 17:35 (CET). So are your results calculated on DAX Xetra EOD data or FDAX EOD data?

    Regarding TSI. So this means that “my” settings of TSI from above post are correct?

    Thank you!

    • Hi,

      yes, TSI calc seems to be correct

      I run this on CASH INDEX, didn’t have FDAX data at that time. I agree, you should test this on FDAX. My data provider has to FDAX series. One with close for 17:35 and the other with EOD close.


  7. Frank,
    Quick question – how would the TSI formula be coded in excel? I understand the basic concept behind TSI, but I’m having trouble interpreting the formula.


    • Hi Jon,

      based on your request / question I added the Excel version to the TSI page / technical implementation.


      • You are the greatest!

        So TSI for SPY would be 1.94 on 2/1/11?

      • Hi Frank,

        I have read all the articles and published code regarding calculation of the TSI (the ATR part), but it’s still not clear how you calculate this strange ATR. In the excel sheet you pasted in the values so that doesn’t help much…


        • Hello Mark,

          I’m sorry to hear that you are not able to reproduce TSI. I re-checked my ATR in the XLS. It’s definitely correct.

          You might want to check:
          1.) is your ATR already expressed in percentage of the base. I’m not doing that.
          2.) how is your ATR calculated. This is the way AmiBroker does it:


          • Frank,

            I, like Mark, had difficultly reproducing your spreadsheet results in my own code. The issue for me, and I suspect with Mark, is that the ATR calculation used by AmiBroker and StockCharts is not a simple average of the last X True Range values.
            Stockcharts uses the following for ATR(14):
            Current ATR = [(Prior ATR x 13) + Current TR] / 14

            This is not the same as summing up the TR for the last 14 days and dividing by 14.

            Obviously, the difference is very small, and likely insignificant with regard to the TSI’s performance.

            I look forward to testing out the TSI and thanks for the great blog.

  8. Hello,

    shall i post a silly question?

    when i copy your strategy code into amibroker formula editor
    and i try verify syntax of this strategy, I recieve a message ” Error 31. Syntax error, expecting ”

    i saved a TSI indicator in C:\Program Files\AmiBroker\Formulas\Custom

    and code of TSI indiacator is

    function TSI()
    Ratio = abs(Close – Ref(Close,-10)) / ATR(10) ;
    Result = MA(MA(Ratio,10),100);
    return Result;

    im a new to amibroker

    thak you for possible help

    • Hi Ivan,

      Can you use the same function that is

      function TSI()
      Ratio = abs(Close – Ref(Close,-10)) / ATR(10) ;
      Result = MA(MA(Ratio,10),100);
      return Result;

      and use this

      SetBacktestMode( backtestRegular);
      SetOption(“InitialEquity”, 100000);
      tsi = TSI();
      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 );

  9. mql4 builder says:

    of course like your web-site however you need to take a look at the spelling on several of your posts. Several of them are rife with spelling problems and I find it very bothersome to inform the reality nevertheless I’ll definitely come back again.

  10. Great system idea.. especially for the trending filter.. But what about for the short side… Would you use the opposite levels for rsi(2) calculating them like (100-(the best numbers like 61 or 39 you found))? And what about applying the 1,65 threeshold to S&P500 or Dow Jones? Do you think is it still a robust level?

    • Hello Marco,

      thanks for the feedback. The 1.65 works very well for SP500. Never tested it for Dow Jones.

      Haven’t tested it for trading stocks (short).


      • Thank you very much Frank. What do you think on using leverage? For example: with leverage at 5 the drawdawn goes at 50%. But if I use only 2/3 of equity and keep 1/3 on cash I can add the cash to the equity keeping the stake at the same amount after the drawdawn. So in each trade I use:
        0,33*(2/3)*(total equity) in one position leveraged. The profits are then saved until I reach the cash amount before drawdawn. On average having 1,3% as average trade, 2 average trades per month, in a year: 1,3*2*12*5*(2/3)=104%. This average yearly return should compensate for the risk. Am I right? Or have to keep *0,33 in the equation? It depends on your backtesting rules.

        • Hello Marco,

          i can not give you any advise on leverage. Simply because I don’t use leverage at all. I’m not ready to enter that area… I’m fine trading my capital 100% (without leverage). Don’t get me wrong, I’m not saying not to use it … i’m just not there.


  11. Hi Frank,

    Have you tested this system on the futures market and found it to work?

  12. Hey Frank, love reading your stuff! Qq, new to Ami and getting a bit better but this is throwing me for a loop. So, took your afl above and saved in as in my custom folder. Then, got your tsi code and saved that as in the same folder custom folder. I open Ami, insert the but get an error around “tsi = trendstrength();” . Even when I insert into the same sheet. Can you lmk where I am blowing it? Much appreciated!

    • Hi Erik,

      Thanks for your feedback. In case you just copied the file(s) you might run into some naming issues

      The TSI here is build using

      function TSI()
      Ratio = abs(Close – Ref(Close,-10)) / ATR(10) ;
      Result = MA(MA(Ratio,10),100);
      return Result;

      the system the system is using

      tsi = trendstrength();

      You run into two issues:
      a.) a variable has the same name as a function.
      b.) the function trendstrength() doesn’t exist.

      So you can do like this:

      function trendstrength()
      Ratio = abs(Close – Ref(Close,-10)) / ATR(10) ;
      Result = MA(MA(Ratio,10),100);
      return Result;

      tsi = trendstrength();


      • Thanks Frank! So if i add the function as you have it above into the same afl as the system, it works perfect. But if I save the function above as a separate afl in the custom folder, and the system as you had written in a separate afl, the “tsi = trendstrength();” throws a syntax error. Does the function have to be in the system code? Sorry for asking for afl lessons, but would love to understand why it is breaking down when separated. Thanks again!

  13. Hi Frank,
    I found this roboust system now. I have a question about the processing of trade. (this is a general question).
    This system -like more others – use close price. When system provides trading signal, I have to buy the instrument. On same day. My problem is, that I get signal after the closing and I should have buy before the end of day.
    How possible to solve this paradox?
    I hope, I can explain my question.


    • Hello Tamas,

      I only trade these kind of systems at the OPEN next day (MOO).

      You can test this with Amibroker as well.


      • Hello Frank,

        Thank you for your answer. I tested it with Amibroker and I get more impressive result.


  14. Admiring the time and energy you put into your blog and detailed information you
    offer. It’s good to come across a blog every once in a while that isn’t the same out of date rehashed information.
    Great read! I’ve bookmarked your site and I’m including your RSS feeds to my Google account.

  15. Hello,
    I tried to replicate the signals in R and after downloading the historical data for the FDAX on yahoo. I find much lower returns. Could you give me the historical data for the signals and the FDAX that you used so that I can figure out where the differences come from?


  1. [...] Combining TSI and RSI into a winning system [...]

  2. [...] Combining TSI and RSI into a winning system [...]

Leave a Reply

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

You are commenting using your 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


Get every new post delivered to your Inbox.

Join 306 other followers

%d bloggers like this: