// This indicator will return a value based on analyzing the $INDU
// It should be applied to the 60,30,10,5,3,1 minute $INDUs
// FlatPercentage is the percentage move we conside flat
Inputs : OBThreshold(100), OSThreshold(-100),CycleLength(6), Smoothing(5),
AlertLevelOB(80), AlertLevelOS(-80), FlatPercentage(5);
Vars : LoopCount(0), RTNVal(0), FlatAmt(0),
Zone60("", data6),Zone30("", data5),Zone10("", data4), Zone5("", data3), Zone3("", data2), Zone1("", data1),
Direction60("", data6), Direction30("", data5), Direction10("", data4), Direction5("", data3), Direction3("", data2), Direction1("", data1),
Bias(" "), Trigger(""), ReturnCode(0),
CycleHistory60(0, data6),CycleHistory30(0, data5),CycleHistory10(0, data4),CycleHistory5(0, data3),CycleHistory3(0, data2),CycleHistory1(0,data1);
// If FlatAmt hasn't been calculated yet - do that now...
If FlatAmt = 0 then
FlatAmt = ((OBThreshold - OSThreshold) / 100) * FlatPercentage;
// re-arrange the array so that we store the last 30 values of the indicator in case we get more sophisticated
// in figuring direction
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;
// Now that we have cycle history - we sl pass ihould call another function (TTDirection) that should tell us which way
// The indicator is going - we'ln the array & that function will tell us up, down, flat, etc
// That function can be improved over time
// Direction - Indicates direction
// + moving up
// - moving down
// F flat (should not indicate that it is perfecly flat but within a tolerance - say less than 10% angle)
// Insert Function Call to set direction here !!
// What follows is not final - just a simplification
If CycleHistory60 > CycleHistory60[1] + FlatAmt then
Direction60 = "+"
else if CycleHistory60 < CycleHistory60[1] - FlatAmt then
Direction60 = "-"
else
Direction60 = "F";
If CycleHistory30 > CycleHistory30[1] + FlatAmt then
Direction30 = "+"
else if CycleHistory30 < CycleHistory30[1] - FlatAmt then
Direction30 = "-"
else
Direction30 = "F";
If CycleHistory10 > CycleHistory10[1] + FlatAmt then
Direction10 = "+"
else if CycleHistory10 < CycleHistory10[1] - FlatAmt then
Direction10 = "-"
else
Direction10 = "F";
If CycleHistory5 > CycleHistory5[1] + FlatAmt then
Direction5 = "+"
else if CycleHistory5 < CycleHistory5[1] - FlatAmt then
Direction5 = "-"
else
Direction5 = "F";
If CycleHistory3 > CycleHistory3[1] + FlatAmt then
Direction3 = "+"
else if CycleHistory3 < CycleHistory3[1] - FlatAmt then
Direction3 = "-"
else
Direction3 = "F";
If CycleHistory1 > CycleHistory1[1] + FlatAmt then
Direction1 = "+"
else if CycleHistory1 < CycleHistory1[1] - FlatAmt then
Direction1 = "-"
else
Direction1 = "F";
// Now that we have direction, we can look to see if we are OB, OS (based on inputs above) as well as direction
// and set 2 global variables for the 60 macci as follows :
// Zone - Indicates where it is
// OB In the Overbrought zone
// OS In the Oversold zone
// MID Between OB & OS
If CycleHistory60 >= OBThreshold then
Zone60 = "OB" // Overbrought
else if CycleHistory60 <= OSThreshold then
Zone60 = "OS" // Oversold
else
Zone60 = "MD"; // Between overbrought & oversold
If CycleHistory30 >= OBThreshold then
Zone30 = "OB" // Overbrought
else if CycleHistory30 <= OSThreshold then
Zone30 = "OS" // Oversold
else
Zone30 = "MD"; // Between overbrought & oversold
If CycleHistory10 >= OBThreshold then
Zone10 = "OB" // Overbrought
else if CycleHistory10 <= OSThreshold then
Zone10 = "OS" // Oversold
else
Zone10 = "MD"; // Between overbrought & oversold
If CycleHistory5 >= OBThreshold then
Zone5 = "OB" // Overbrought
else if CycleHistory5 <= OSThreshold then
Zone5 = "OS" // Oversold
else
Zone5 = "MD"; // Between overbrought & oversold
If CycleHistory3 >= OBThreshold then
Zone3 = "OB" // Overbrought
else if CycleHistory3 <= OSThreshold then
Zone3 = "OS" // Oversold
else
Zone3 = "MD"; // Between overbrought & oversold
If CycleHistory1 >= OBThreshold then
Zone1 = "OB" // Overbrought
else if CycleHistory1 <= OSThreshold then
Zone1 = "OS" // Oversold
else
Zone1 = "MD"; // Between overbrought & oversold
Plot1(CycleHistory1, "Cycle");
Plot2(OBThreshold,"OverBought");
Plot3(OSThreshold,"Oversold");
plot4(0,"Zero");
Plot5(AlertLevelOB,"Alert");
Plot6(AlertLevelOS,"Alert");
// if higher timeframes(60,30,10) are OB or pointing down - short bias
// if higher timeframes(60,30,10) are OS or pointing up - long bias
if (Zone60 = "OB" or Direction60 = "-")
and (Zone30 = "OB" or Direction30 = "-")
and (Zone10 = "OB" or Direction10 = "-") then
Bias = "Short"
else if (Zone60 = "OS" or Direction60 = "+")
and (Zone30 = "OS" or Direction30 = "+")
and (Zone10 = "OS" or Direction10 = "+") then
Bias = "Long" else
Bias = "None";
// Look for entry points on lower timeframes
// OS/OB in either 5/3 + 1 is OK
Trigger = "None";
if bias = "Short" and (Zone5 = "OB" or Zone3 = "OB") and Zone1 = "OB" then
Trigger = "SellShort";
if bias = "Long" and (Zone5 = "OS" or Zone3 = "OS") and Zone1 = "OS" then
Trigger = "Buy";
if Trigger = "SellShort" then begin
// Plot1(Low);
Alert("Sell Short");
// ReturnCode = TT_GET_ARRAY;
end;
if Trigger = "Buy" then begin
// Plot2(High);
Alert("Go Long");
// ReturnCode = TT_GET_ARRAY;
end ;
//
If Time <> Time[1] then
Print(FormatDate( "dd MMM yy", ElDateToDateTime( Date )), " ", FormatTime( "hh:mm", ElTimeToDateTime( Time )) , " Zone 60 = ", Zone60, ", Dir 60 = ", Direction60,
", Zone 30 = ", Zone30, ", Dir 30 = ", Direction30,
", Zone 10 = ", Zone10, ", Dir 10 = ", Direction10,
", Zone 5 = ", Zone5, ", Dir 5 = ", Direction5,
", Zone 3 = ", Zone3, ", Dir 3 = ", Direction3,
", Zone 1 = ", Zone1, ", Dir 1 = ", Direction1,
", Bias = ", Bias, ", Trigger = ", Trigger);
{
// For testing only - if this is the last bar on the chart - output the array
// Switch this off if running in real time
//if LastBarOnChart then
// ReturnCode = TT_GET_ARRAY;
end;}
// if higher timeframes(60,30,10) are OB or pointing down - short bias
// if higher timeframes(60,30,10) are OS or pointing up - long bias
if (Zone60 = "OB" or Direction60 = "-")
and (Zone30 = "OB" or Direction30 = "-")
and (Zone10 = "OB" or Direction10 = "-") then
Bias = "Short"
else if (Zone60 = "OS" or Direction60 = "+")
and (Zone30 = "OS" or Direction30 = "+")
and (Zone10 = "OS" or Direction10 = "+") then
Bias = "Long" else
Bias = "None";
// Look for entry points on lower timeframes
// OS/OB in either 5/3 + 1 is OK
Trigger = "None";
if bias = "Short" and (Zone5 = "OB" or Zone3 = "OB") and Zone1 = "OB" then
Trigger = "SellShort";
if bias = "Long" and (Zone5 = "OS" or Zone3 = "OS") and Zone1 = "OS" then
Trigger = "Buy";
PeteSignals generated in the past 30 days:
30th Sept 12:18 - Buy
6th Oct 12:40 - Buy
10th Oct 9:33 - Buy
15th Oct 1:20 - Buy
16th Oct 10:12 - Buy
16th Oct 11:13 - Buy
17th Oct 1:36 - Short
20th Oct 4:00 - Short
As well as the cycle, the parts we need to look at are :
Bias
Code:// if higher timeframes(60,30,10) are OB or pointing down - short bias // if higher timeframes(60,30,10) are OS or pointing up - long bias if (Zone60 = "OB" or Direction60 = "-") and (Zone30 = "OB" or Direction30 = "-") and (Zone10 = "OB" or Direction10 = "-") then Bias = "Short" else if (Zone60 = "OS" or Direction60 = "+") and (Zone30 = "OS" or Direction30 = "+") and (Zone10 = "OS" or Direction10 = "+") then Bias = "Long" else Bias = "None";
Entry
Code:// Look for entry points on lower timeframes // OS/OB in either 5/3 + 1 is OK Trigger = "None"; if bias = "Short" and (Zone5 = "OB" or Zone3 = "OB") and Zone1 = "OB" then Trigger = "SellShort"; if bias = "Long" and (Zone5 = "OS" or Zone3 = "OS") and Zone1 = "OS" then Trigger = "Buy";
We can also play with other settings other than just direction & zone.
Thoughts ?
Pete
Pete
Well done - yesterday after market hours the code was not working as needed because it was giving multiple rows in the print log for the same timestamp and the zone values were not always the same on the same timestamp. Looking at both your code and the results this morning this is really looking good and I think you have cracked it.
The things I would want to check is how it actually deals with the evaluation of the higher timeframes each minute. Does it look at only completed bars or does it evaluate mid-bar ? Does this matter and which would we prefer ?
Also what happens during say the first hour of the market. We will not have completed the first 60 min bar, so do we say that no trades are possible. Do we evaluate mid-bar ? or do we ignore the 60 and 30 during the first hour and use only 10 downwards ?
With regard to refining the conditions, I think we can certainly adjust the OS/OB side. Thus if the MACCI 10 for example doesn't reach 100 but turns down within 80 -100 this would most likely prompt a sell short or an exit from a long. We can use position sizing in combination with the signals to adjust for what might be regarded as less than ideal signals.
Anyway this is great progress and now makes optimisation possible, so making all these kinds of adjustments is much easier and can be quantitatively evaluated.
Charlton
HiI haven't been around long so I cannot be sure, but don't the 60min and 30min signals carry from overnight? i.e the day before.
Either way, I've been watching a lot of Grey's seminars over the last week that I've joined TT, so I have some stuff fresh in my mind. He says that although taking a signal on "barclose" would be a stronger signal, you should take signals from "non-barclose" as otherwise you would miss out on a lot of trades.
His ideology was that if you are taking trades on "non-barclose" then to reduce your position size/risk.
Also, I was thinking that for non-technical days/times such as major news releases, there should be a "manual override" button or something similar, so that the program keeps running but will not execute any trades until the market seems more technical.
This would save the hassle of turning it off and on, and one mouse-click could quickly disable the program from executing trades but keep it collating data.
Great work guys I just wish I had as much coding knowledge as you do.
Paul
Glenn
GVs weren't the issue. The issue we needed to resolve was in backtesting with data from multiple time scales.
So for instance, if we have an ESL on the 60 & 30 min that set GVs, it's fine in real time but when backtesting, it'll run the ESL for every bar on the 60 before running it for every bar on the 30. If you reference 60 min GVs on the 30 min time frame, you'll always be looking at the last bars data.
To get around this we had to use the last script I posted to analyze all timeframes in the same ESL - the it executes in chronological order.
Our other scripts use GVs - check out the weak/strong thread.
Cheers
Pete
I agree that backtesting is limited but this is more about getting the code right & being able to run it when the market is closed. It's very limiting to be able to run something only when the market is open.
Hmm - not sure what your problem is. I do most testing after hours because changing code in flight during market hours often causes TS2ki to crash. (Alternatively during market hours you can leave Globalserver running, close tradestation, change your code and re-load tradestation.)
However provided you load enough data and use the print function for output you can test anything after hours.
Glenn
I'm afraid that I don't fully understand this question... Of course, in "real-time," ticks are processed as they occur, so Chart A can process a tick, then Chart B can process a tick, and so on. In historical testing, however, because EasyLanguage runs in a single process thread, EasyLanguage analysis techniques must run to completion, through all of the available bars, before processing of another analysis technique can begin.
Glenn - we have 6 timescales, on the $INDU in our ESL.
Initially, we put the indicator on each individual chart & shared indicator values with global variables.
When you load up the workspace, you will see that for earier data, it runs
Chart 1
9:30
9:31
9:32
Chart 2
9:30
9:31
9:32
etc.
What you actually want it to do is :
9:30
chart 1
chart 2
9:31
chart 1
chart 2
9:32
chart 1
chart 2
This is documented on the Tradestation site. Basically loading prior data is done chart by chart and not in time sequence. So with multi time-frame analysis onmultiple charts with global variables you have an execution sequence issue.
I agree that you can test anything after hours but you have to code it a specific way in order to have your ESLs executed in chronological sequence.
Here's the solution :
https://www.tradestation.com/Discussions/Topic_Archive.aspx?Topic_ID=32085
Here's the problem
https://www.tradestation.com/Discussions/Topic.aspx?Topic_ID=81910
If you have multiple ESLs or a single ESL running on multiple charts/timescales that run in chronological order outside of market hours - I'd be very interested to see the code.
Pete
Pete
What's an ESL ? If it's something to do with backtesting I know nothing about it.
Regarding the problem let me try to explain how I would test something.
Lets say you have 6 pieces of code each outputting a value to 6 different globalvariables.
The value is sent as soon as it occurs if you update on every tick.
Then you have a receiving piece of code which looks at all the 6 globalvariables and makes a decision. By updating this code on every tick the incoming data is constantly updated and the code runs through on every tick, analysing the latest data.
So nothing gets out of sequence and the data being analysed is the latest data from all 6 bits of code.
An ESL - an easylanguage script !
What you describe only happens when you are running in real time. So if you run during todays market hours, you will see what you describe. If you attempt to re-run after market hours, you will not see what you describe because it will process all bars in a chart before moving to the next chart and processing all bars in that chart.
To demonstrate this, pull up 6 charts - 60,30,10,5,3,1 min $INDU on 1 workspace.
On each chart have a script that does the following :
print("Interval ", Barinterval, " Time ", time);
Run this when you are online but when the market is closed. You will see that the print statements each chart are processed for the whole day before it moves to the next chart.
Therefore you cannot set a global variable for 11 am on the 60 minute and use it at 11:00 am on the 1 minute, unless of course you have a different global variable for each time.
Let's say the 60 minute chart executes first (which you can't really control), followed by the 1 minute. Every time the 1 minute references the variable from the 60 minute, it will only be referencing the last value at the end of the day.
Put the print statement on the 6 charts & you'll see what I mean.
Off line processing is chart, then tick. On line processing is tick then chart.