Connors and Raschke (Momentum Pinball)™ EasyLanguage

In the Connors Raschke book, “Street Smarts – High Probability Short-Term Trading Strategies” published by M. Gordon Publishing Group 1995, the authors describe a strategy that incorporates several ideas and functions that can be difficult to program into TradeStation.  I highly suggest purchasing the book as it has some very interesting ideas and comes from the minds of two very accomplished traders.

The strategy is conceptually simple and uses the Taylor Buy/Sell day concept.   On buy days, buy on the penetration of the first hour high and use the extreme of the first hour as the stop.  If you get stopped out the system will allow you to re-enter once more on a re-penetration of the first hour high.  If the trade is profitable at the close of the day session then exit on the open of the following day.  Selling short is just the opposite.  The Buy Day is defined when the three day RSI of the one day ROC (close[0] – close[1]) is below 30 and the Sell Day  is defined when this indicator rises above 70.  As you can see, pretty simply.

The first problem when programming this strategy is the mixing of the 5 minute bars (for trade execution) and daily bars (calculating the indicator.)  How do you calculate an RSI(c[0] – c[1],3) indicator value when looking at a 5 minute bar chart.   This turns out to be pretty simple since TradeStation allows the mixing of different time frames on the same chart.  First plot a 5 minute bar of the @ES.D as data 1 and then insert a daily bar of the @ES.D as data 2.   The first step in programming this strategy is setting up the indicator.

//EasyLanguage

Vars: rsiVal(0,data2);

rsiVal = rsi(close of data2 - close[1] of data2,3);
Setting up the nested indicator.

Notice how I declared the variable rsiVal?  I initially set it to zero and tie it to data2.  This tying or aliasing limits the variable from being updated on each five minute bar.  Remember we want the RSI calculation done on the daily bars.  The RSI function allows the embedding of calculations as well as different prices.  Here we are telling the computer to look at the momentum of today’s close versus yesterday’s  and apply the RSI  3 – period calculation.

In their book Connors and Raschke determined that it would be better to buy after an RSI reading of below 30 and sell after an RSI above 70.  Once we have this set, then the fun really begins with this type of programming.  If you can do this type of programming, there’s very little you can’t do.  This is because we are solving a few limitations of EasyLanguage by logically addressing the what we need from language. In this example, we have to capture the range of the first hour.  There really isn’t a built-in way to do this or at least not an easy one.  When testing intra-day, I always like using five minute bars.  This time frame is small enough that not much usually happens during this t time and it isn’t much of a resource hog – like say minute or smaller bars. Since there are 12 five minute bars in an hour, I wait until the 12th bar of the day is completed to determine the first hour’s range and its extremes.  I set the dayBarCount to zero on the first bar of the day and then increment the variable on each bar.

If date <> date[1] then
begin
dayBarCount = 0;
buysToday = 0;
sellsToday = 0;
end;

dayBarCount = dayBarCount + 1;

If dayBarCount = 12 then
Begin
buyLevel = highD(0) + minMove/priceScale;
sellLevel = lowD(0) - minMove/priceScale;
end;
Tracking the number of bars and capturing first hour.

TradeStation has made this process simpler by providing the highD and lowD functions.  When you call these functions the current daily bar extremes are returned at the point in the day.  So the functions are called on the 12th bar and they return the high and low of the first hour.   The functions are not called again until the next day.  Oh yeah – passing a zero as the function argument informs EasyLanguage to return today’s values.  A 1 would return yesterday’s values.  These are nifty functions if you aren’t incorporating a secondary daily data stream.  Even if you are, like in our example, they still come in handy.

mp = marketPosition;

If mp = 1 and mp[1] <> 1 then buysToday = buysToday + 1;
If mp = -1 and mp[1] <> -1 then sellsToday = sellsToday + 1;

If dayBarCount > 12 and time < 1430 then
Begin
if rsiVal < 30 and mp <> 1 and buysToday < 2 then buy next bar at buyLevel Stop;
If rsiVal > 70 and mp <> -1 and sellsToday < 2 then sellShort next bar at sellLevel stop;
end;
Order placement directives and the use of mp.

I also keep track of the number of buys and shorts for the day.  The books states that a re-entry is possible, so I allow up to two trade entries.  I look and the current MP value and its prior value to see if  the system went from one state to another.  If current MP is long and the prior reading is not long, then a long entry was undoubtedly entered.  You can use this logic (I did for illustrative purposes) or use the built-in functions entriesShortToday/entriesLongToday to determine the number of trades for the day.  If the rsiValue < 30 and less than two long entries have occurred, then you can buy on a breakout of the first hourly bar.  Entering short is the opposite, but with the RSI reading of greater than 70.

If mp = 1 then
Begin
Sell next bar at sellLevel stop;
end;

If mp= -1 then
Begin
Buytocover next bar at buyLevel stop;
end;

If time = 1510 and openPositionProfit < 0 then setExitOnClose;
If time = 1515 then
Begin
If mp = 1 then sell next bar at open;
If mp =-1 then buyToCover next bar at open;
end;
Initial stop and if winning trade exit next morning else get out on close.

The buy/sell levels are the first hourly bar’s extreme +/- min. tick.  These levels are used as protective stops as well as entry levels.  If long then the first hourly bar’s low is the protective stop.  Notice how I check at 1510 if the trade is in a profit by examining the current openPositionProfit.  I am checking five minutes prior to the close because I need to execute setExitOnClose if in a loss.  I don’t think I can check at 15:15 (closing time) and then exit, but I will check and let you know.

The last little trick is to execute on the open tick the next morning.  I have explained in my books the different trading paradigms where you are either sitting on the prior bar when you place orders or sitting on the open of the current bar.  EasyLanguage assumes the former so you always have to place an order for the next bar.  If you wait until the open, then the earliest you can exit is 8:35.  So you have to issue the order on the last bar of the prior day to get the open tick, hence the test to see if the time stamp is 15:15.

This sample of EasyLanguage is a good example of some easy fixes to things that usually leave beginning EasyLanguage coders scratching their heads and groaning out loud.