Program Trading: Oscillators

lwebb

Member
Messages
64
Likes
4
This thread is for all discussions on oscillators: investigation, coding, testing, etc.
 
This is pretty much what we had in our 1st version of the TT_CYCLE & TT_ENTRYPOINT code, so I heartily agree !

Obviously the difference is in how we decided the trigger point. The TT_MTL_CYCLE3 does the same thing but removes the need for Global Variables whilst simultaneously discovering a bug in Tradestation which ensures it occasionally throws out ****ty data.

I thought the same. The TT_MTL_CYCLE3 code makes a good testing framework for oscillators. It's all in one place and allows control of the other factors in trade entry. Generally the oscillator testing code should be similar to, or reuse, the trade entry code. The testing environment is closer to the trading environment and the results easier to compare.

Glenn, I'll put the MACCI SMA cross code in TT_MTL_CYCLE3 for starters and try reproduce something along the lines of your example.
 
I thought the same. The TT_MTL_CYCLE3 code makes a good testing framework for oscillators. It's all in one place and allows control of the other factors in trade entry. Generally the oscillator testing code should be similar to, or reuse, the trade entry code. The testing environment is closer to the trading environment and the results easier to compare.

Glenn, I'll put the MACCI SMA cross code in TT_MTL_CYCLE3 for starters and try reproduce something along the lines of your example.

Please note that there is an issue with TT_MTL_CYCLE3.

This is to do with it occasionally bringing up invalid data when referencing bars back. See attached doc. The output is from the following test case logged on their site :

Code:
Inputs : Length(5);
Vars : 	CycleHistory60(0, data6),CycleHistory30(0, data5),CycleHistory10(0, data4),
	CycleHistory5(0, data3),CycleHistory3(0, data2),CycleHistory1(0,data1);
// Calculate the indicator for the timeframes
CycleHistory60 = CCI(Length) data6;
CycleHistory30 = cci(Length) data5;
CycleHistory10 = cci(Length) data4;
CycleHistory5 = cci(Length) data3;
CycleHistory3 = cci(Length) data2;
CycleHistory1 = cci(Length) data1;
// Plot cycle 1 as this indicator is for the 1 minute
Plot1(CycleHistory1, "Cycle"); 
Print(FormatTime( "hh:mm", ElTimeToDateTime( Time ))," Cycles[0] ", CycleHistory60, " ", CycleHistory30, " ", CycleHistory10, " ", CycleHistory5, " ", CycleHistory3, " ", CycleHistory1);
Print("      Cycles[1] ", CycleHistory60[1], " ", CycleHistory30[1], " ", CycleHistory10[1], " ", CycleHistory5[1], " ", CycleHistory3[1], " ", CycleHistory1[1]);

https://www.tradestation.com/Discussions/Topic.aspx?Topic_ID=82711

An issue has been logged with TS - I will give them today to answer it & then follow up on the phone tomorrow.

Note that this issue seems to occur at 10:29, 10:29, 11:28, 11:29 etc. It's something to do with many timeframes rolling over at the same time.

There's a number of ways to do multiple time frame analysis, it's just a matter now of finding the one that is most reliable. It may be we have to return to split scripts. IT may be we need to use ADE - but I worry about the overhead in using this, I can't afford a Cray.
 

Attachments

  • 1barlookback.doc
    63.5 KB · Views: 21
Last edited:
This is an illustration of Glenn's oscillator testing example as it might be done within the TT_MTL_CYCLE3 context. There's currently an issue with invalid data so this is untested.


// Get the cycle value for all timeframes
CycleHistory60 = TTCycle(CycleLength, Smoothing) data6;
CycleHistory30 = TTCycle(CycleLength, Smoothing) data5;
CycleHistory10 = TTCycle(CycleLength, Smoothing) data4;
CycleHistory5 = TTCycle(CycleLength, Smoothing) data3;
CycleHistory3 = TTCycle(CycleLength, Smoothing) data2;
CycleHistory1 = TTCycle(CycleLength, Smoothing) data1;

// Get (Oscillator + 3 SMA) crossover signals for all timeframes
Crossed60 = TT_Osc_Cross_Bar(CycleHistory60, 3, 10);
Crossed30 = TT_Osc_Cross_Bar(CycleHistory30, 3, 10);
Crossed10 = TT_Osc_Cross_Bar(CycleHistory10, 3, 10);
Crossed5 = TT_Osc_Cross_Bar(CycleHistory5, 3, 10);
Crossed3 = TT_Osc_Cross_Bar(CycleHistory3, 3, 10);
Crossed1 = TT_Osc_Cross_Bar(CycleHistory1, 3, 10);

// Long signals for all timeframes
var: Sig60Long(false), Sig30Long(false),Sig10Long(false),Sig5Long(false),Sig3Long(false),Sig1Long(false);
Sig60Long = CycleHistory60 > 80 and Crossed60 < 0;
Sig30Long = CycleHistory30 > 80 and Crossed30 < 0;
Sig10Long = CycleHistory10 > 80 and Crossed10 < 0;
Sig5Long = CycleHistory5 > 80 and Crossed5 < 0;
Sig3Long = CycleHistory3 > 80 and Crossed3 < 0;
Sig1Long = CycleHistory1 > 80 and Crossed1 < 0;

// Short signals for all timeframes
var: Sig60Short(false), Sig30Short(false),Sig10Short(false),Sig5Short(false),Sig3Short(false),Sig1Short(false);
Sig60Short = CycleHistory60 < -80 and Crossed60 > 0;
Sig30Short = CycleHistory30 < -80 and Crossed30 > 0;
Sig10Short = CycleHistory10 < -80 and Crossed10 > 0;
Sig5Short = CycleHistory5 < -80 and Crossed5 > 0;
Sig3Short = CycleHistory3 < -80 and Crossed3 > 0;
Sig1Short = CycleHistory1 < -80 and Crossed1 > 0;

// Get market direction
var: MarketLong(false), MarketShort(false);
MarketLong = (Sig10Long and Sig60Long) or (Sig10Long and Sig30Long);
MarketShort = (Sig10Short and Sig60Short) or (Sig10Short and Sig30Short);

// Get entry direction
var: EntryLong(false), EntryShort(false);
EntryLong = (Sig1Long and Sig3Long) or (Sig1Long and Sig5Long);
EntryShort = (Sig1Short and Sig3Short) or (Sig1Short and Sig5Short);

if MarketLong and EntryLong then
Alert("Buy"); // etc

if MarketShort and EntryShort then
Alert("SellShort"); // etc
 
This is an illustration of Glenn's oscillator testing example as it might be done within the TT_MTL_CYCLE3 context. There's currently an issue with invalid data so this is untested.


// Get the cycle value for all timeframes
CycleHistory60 = TTCycle(CycleLength, Smoothing) data6;
CycleHistory30 = TTCycle(CycleLength, Smoothing) data5;
CycleHistory10 = TTCycle(CycleLength, Smoothing) data4;
CycleHistory5 = TTCycle(CycleLength, Smoothing) data3;
CycleHistory3 = TTCycle(CycleLength, Smoothing) data2;
CycleHistory1 = TTCycle(CycleLength, Smoothing) data1;

// Get (Oscillator + 3 SMA) crossover signals for all timeframes
Crossed60 = TT_Osc_Cross_Bar(CycleHistory60, 3, 10);
Crossed30 = TT_Osc_Cross_Bar(CycleHistory30, 3, 10);
Crossed10 = TT_Osc_Cross_Bar(CycleHistory10, 3, 10);
Crossed5 = TT_Osc_Cross_Bar(CycleHistory5, 3, 10);
Crossed3 = TT_Osc_Cross_Bar(CycleHistory3, 3, 10);
Crossed1 = TT_Osc_Cross_Bar(CycleHistory1, 3, 10);

// Long signals for all timeframes
var: Sig60Long(false), Sig30Long(false),Sig10Long(false),Sig5Long(false),Sig3Long(false),Sig1Long(false);
Sig60Long = CycleHistory60 > 80 and Crossed60 < 0;
Sig30Long = CycleHistory30 > 80 and Crossed30 < 0;
Sig10Long = CycleHistory10 > 80 and Crossed10 < 0;
Sig5Long = CycleHistory5 > 80 and Crossed5 < 0;
Sig3Long = CycleHistory3 > 80 and Crossed3 < 0;
Sig1Long = CycleHistory1 > 80 and Crossed1 < 0;

// Short signals for all timeframes
var: Sig60Short(false), Sig30Short(false),Sig10Short(false),Sig5Short(false),Sig3Short(false),Sig1Short(false);
Sig60Short = CycleHistory60 < -80 and Crossed60 > 0;
Sig30Short = CycleHistory30 < -80 and Crossed30 > 0;
Sig10Short = CycleHistory10 < -80 and Crossed10 > 0;
Sig5Short = CycleHistory5 < -80 and Crossed5 > 0;
Sig3Short = CycleHistory3 < -80 and Crossed3 > 0;
Sig1Short = CycleHistory1 < -80 and Crossed1 > 0;

// Get market direction
var: MarketLong(false), MarketShort(false);
MarketLong = (Sig10Long and Sig60Long) or (Sig10Long and Sig30Long);
MarketShort = (Sig10Short and Sig60Short) or (Sig10Short and Sig30Short);

// Get entry direction
var: EntryLong(false), EntryShort(false);
EntryLong = (Sig1Long and Sig3Long) or (Sig1Long and Sig5Long);
EntryShort = (Sig1Short and Sig3Short) or (Sig1Short and Sig5Short);

if MarketLong and EntryLong then
Alert("Buy"); // etc

if MarketShort and EntryShort then
Alert("SellShort"); // etc

Be careful using Crossover commands. I tried them in TS2000 and found it better to use > and <.
e.g. if signal line > macci then long signal

Glenn
 
lwebb
There are variations with different types of crossover.
If you have an indicator like M653, then the 3sma signal line will respond more quickly to price, so the signal is given when the 3sma moves above or below the 5 sma.
However many (all?) of the Ehler indicators work differently i.e the signal is given when the main line crosses the signal line, not when the signal line crosses the main line.
So if you use Cross over and under you will get incorrect results if you make the wrong comparison between the two lines.

Glenn
 
lwebb
There are variations with different types of crossover.
If you have an indicator like M653, then the 3sma signal line will respond more quickly to price, so the signal is given when the 3sma moves above or below the 5 sma.
However many (all?) of the Ehler indicators work differently i.e the signal is given when the main line crosses the signal line, not when the signal line crosses the main line.
So if you use Cross over and under you will get incorrect results if you make the wrong comparison between the two lines.
Glenn

I've posted the modified function TT_Osc_Cross below. It's been changed to use the comparision operators (<,>) instead of TradeStation's cross over/under as per your post. The cross is defined as the oscillator line crossing the SMA line.

I'm not entirely sure I follow the distinction of "the signal is given when the main line crosses the signal line, not when the signal line crosses the main line".
 

Attachments

  • OSCCROSS.ELD
    6.8 KB · Views: 16
  • OscTurn.png
    OscTurn.png
    29.6 KB · Views: 27
I've posted the modified function TT_Osc_Cross below. It's been changed to use the comparision operators (<,>) instead of TradeStation's cross over/under as per your post. The cross is defined as the oscillator line crossing the SMA line.

I'm not entirely sure I follow the distinction of "the signal is given when the main line crosses the signal line, not when the signal line crosses the main line".

What you've done is ok for M653 because the long signal is given when the 3sma crosses above the 5sma, but when you look at Ehler Indicators its different. See attached picture.
Glenn
 

Attachments

  • Crossover.JPG
    Crossover.JPG
    58.7 KB · Views: 34
An aspect of finding better oscillators involves using Moving Averages which are smoother and react faster than SMA. The reference standard here is the propriatory Jurik MA. Two open-source contenders are the Hull and the Gaussian MAs.

TradeStation forum link to Hull:
https://www.tradestation.com/Discussions/Topic.aspx?Topic_ID=40589

TradeStation forum link to Gauss:
https://www.tradestation.com/Discussions/Topic.aspx?Topic_ID=31076

The chart below shows the CCI smoothed by SMA, Hull and Gauss moving averages respectively. Both the Hull and Gauss cases react faster than the vanilla MACCI; though at the cost of being more whippy (which also makes them better candidates as scalping indicators).
 

Attachments

  • CCI-MAs.png
    CCI-MAs.png
    47.7 KB · Views: 43
An aspect of finding better oscillators involves using Moving Averages which are smoother and react faster than SMA. The reference standard here is the propriatory Jurik MA. Two open-source contenders are the Hull and the Gaussian MAs.

TradeStation forum link to Hull:
https://www.tradestation.com/Discussions/Topic.aspx?Topic_ID=40589

TradeStation forum link to Gauss:
https://www.tradestation.com/Discussions/Topic.aspx?Topic_ID=31076

The chart below shows the CCI smoothed by SMA, Hull and Gauss moving averages respectively. Both the Hull and Gauss cases react faster than the vanilla MACCI; though at the cost of being more whippy (which also makes them better candidates as scalping indicators).

Likewise Weighted and Exponential MA's should respond earlier.
The number of possible combinations is, erm - a lot !
Glenn
 
Top