Utility Procedures / Code Snippets

Post Reply
User avatar
youcrazykids
Trader
Posts: 44
Joined: Sat Nov 19, 2011 8:38 am
Location: Northumberland, UK

Re: Utility Procedures / Code Snippets

Post by youcrazykids »

Hi all

Following the kind comments and suggestions by George (gaheitman), I've refined the on-chart indicator code, to make it a little more efficient. It draws everything once on startup, and only recalculates/redraws everything when the chart is altered by incoming data, such as a new bar or changes to the range. This turned out to be a good exercise, which improved my understanding of Empty4's lesser-used functions. Maybe it - or part of it - will prove useful.

untitled.JPG

Code: Select all

extern double Level1=0.2, Level2=0.3, Level3=0.5, Level4=0.7, Level5=0.8;
extern int StochasticK=14, StochasticD=3, StochasticSlowing=7, RSIPeriod=9;

extern int EA_DrawingMem;
extern double EA_WindowPriceRangeMem;

//-------------------------------------------------------------------------------------------------------------------------------

int init(){ //This section contains code which executes only on startup

   EA_DrawingMem=Time[WindowFirstVisibleBar()]; // Identify the time of the oldest bar on the screen. This is for determining when a redraw is necessary, for the on-screen indicators, at the start of a new bar.
   EA_WindowPriceRangeMem=WindowPriceMax()-WindowPriceMin(); // Identify the range of the chart.
   
   // This routine paints gridlines on the screen every 100 pips.
   double a,b; // Define counting variables for this loop.
   while (a<2000)
   {b=a/100; ObjectCreate("_PriceLines"+a,OBJ_HLINE,0,Time[0],b); ObjectSet("_PriceLines"+a,OBJPROP_COLOR,Silver); ObjectSet("_PriceLines"+a,OBJPROP_STYLE,STYLE_DOT);a++;
   } // End of this loop.
   
   // These next two lines create two black boxes on the screen, to allow comments to be displayed without being obscured by the chart.
   ObjectCreate("LabelBox1", OBJ_LABEL, 0, 0, 0); ObjectSetText("LabelBox1","g",150,"Webdings",Black); ObjectSet("LabelBox1", OBJPROP_XDISTANCE, 0); ObjectSet("LabelBox1", OBJPROP_YDISTANCE, 13); ObjectSet("LabelBox1",OBJPROP_BACK,0);
   ObjectCreate("LabelBox2", OBJ_LABEL, 0, 0, 0); ObjectSetText("LabelBox2","g",150,"Webdings",Black); ObjectSet("LabelBox2", OBJPROP_XDISTANCE, 0); ObjectSet("LabelBox2", OBJPROP_YDISTANCE, 213); ObjectSet("LabelBox1",OBJPROP_BACK,0);

   RepetitiveDrawing();// Call the drawing routine, to paint level lines, indicators, etc.
   
} // End of init routine

//-------------------------------------------------------------------------------------------------------------------------------

int start(){

   if(Time[WindowFirstVisibleBar()] != EA_DrawingMem || (WindowPriceMax()-WindowPriceMin()) != EA_WindowPriceRangeMem) {
      RepetitiveDrawing(); // Call the drawing routine, to re-paint level lines, indicators, etc.
      } // End of the if routine

   Comment("\n","Light blue: Stochastic main ",StochasticK,",",StochasticD,",",StochasticSlowing,"\nDark blue: Stochastic signal ",StochasticK,",",StochasticD,",",StochasticSlowing,"\nViolet: RSI ",RSIPeriod);

} // End of start routine

//-------------------------------------------------------------------------------------------------------------------------------

int deinit(){ //This section contains code which executes only on shutdown of the EA. Things like deleting drawing objects, etc.
	
	ObjectsDeleteAll();
	
} // End of deinit routine

//-------------------------------------------------------------------------------------------------------------------------------

int RepetitiveDrawing(){

   Print("Redrawing all graphical objects, to match new chart data.");
   
	//This paints level lines on the chart, at a percentage of the chart range.
	double WindowPriceRange=WindowPriceMax()-WindowPriceMin(); // Determine the range of the chart window
	ObjectCreate("_Level1",OBJ_HLINE,0,Time[0],WindowPriceMin()+WindowPriceRange*Level1); ObjectSet("_Level1",OBJPROP_PRICE1,WindowPriceMin()+WindowPriceRange*Level1); ObjectSet("_Level1",OBJPROP_COLOR,Tan); ObjectSet("_Level1",OBJPROP_STYLE,STYLE_SOLID);
	ObjectCreate("_Level2",OBJ_HLINE,0,Time[0],WindowPriceMin()+WindowPriceRange*Level2); ObjectSet("_Level2",OBJPROP_PRICE1,WindowPriceMin()+WindowPriceRange*Level2); ObjectSet("_Level2",OBJPROP_COLOR,Tan); ObjectSet("_Level2",OBJPROP_STYLE,STYLE_SOLID);
	ObjectCreate("_Level3",OBJ_HLINE,0,Time[0],WindowPriceMin()+WindowPriceRange*Level3); ObjectSet("_Level3",OBJPROP_PRICE1,WindowPriceMin()+WindowPriceRange*Level3); ObjectSet("_Level3",OBJPROP_COLOR,Tan); ObjectSet("_Level3",OBJPROP_STYLE,STYLE_SOLID);
	ObjectCreate("_Level4",OBJ_HLINE,0,Time[0],WindowPriceMin()+WindowPriceRange*Level4); ObjectSet("_Level4",OBJPROP_PRICE1,WindowPriceMin()+WindowPriceRange*Level4); ObjectSet("_Level4",OBJPROP_COLOR,Tan); ObjectSet("_Level4",OBJPROP_STYLE,STYLE_SOLID);
	ObjectCreate("_Level5",OBJ_HLINE,0,Time[0],WindowPriceMin()+WindowPriceRange*Level5); ObjectSet("_Level5",OBJPROP_PRICE1,WindowPriceMin()+WindowPriceRange*Level5); ObjectSet("_Level5",OBJPROP_COLOR,Tan); ObjectSet("_Level5",OBJPROP_STYLE,STYLE_SOLID);

	// This routine paints a 0-100 stochastic oscillator on the main chart, instead of creating a separate chart window.
	int c; // define a counting variable for a loop
	double Indicator1Val, Indicator1ValPrev, Indicator2Val, Indicator2ValPrev, Indicator3Val, Indicator3ValPrev, Indicator4Val, Indicator4ValPrev;
	while (c<WindowBarsPerChart()){ // define the limits of the loop
	  Indicator1Val=(WindowPriceMin()+((iStochastic(NULL,0,StochasticK,StochasticD,StochasticSlowing,MODE_SMA,0,MODE_MAIN,c)/100)*WindowPriceRange));
	  Indicator1ValPrev=(WindowPriceMin()+((iStochastic(NULL,0,StochasticK,StochasticD,StochasticSlowing,MODE_SMA,0,MODE_MAIN,c+1)/100)*WindowPriceRange));
	  Indicator2Val=(WindowPriceMin()+((iStochastic(NULL,0,StochasticK,StochasticD,StochasticSlowing,MODE_SMA,0,MODE_SIGNAL,c)/100)*WindowPriceRange));
	  Indicator2ValPrev=(WindowPriceMin()+((iStochastic(NULL,0,StochasticK,StochasticD,StochasticSlowing,MODE_SMA,0,MODE_SIGNAL,c+1)/100)*WindowPriceRange));
	  Indicator3Val=(WindowPriceMin()+((iRSI(NULL,0,RSIPeriod,0,c)/100)*WindowPriceRange));
	  Indicator3ValPrev=(WindowPriceMin()+((iRSI(NULL,0,RSIPeriod,0,c+1)/100)*WindowPriceRange));
	  Indicator4Val=NULL;
	  Indicator4ValPrev=NULL;
	  ObjectCreate("_Indicator1"+c,OBJ_TREND,0,Time[c],Low[c]); ObjectSet("_Indicator1"+c,OBJPROP_PRICE1,Indicator1ValPrev); ObjectSet("_Indicator1"+c,OBJPROP_PRICE2,Indicator1Val); ObjectSet("_Indicator1"+c,OBJPROP_TIME1,Time[c+1]); ObjectSet("_Indicator1"+c,OBJPROP_TIME2,Time[c]); ObjectSet("_Indicator1"+c,OBJPROP_RAY,0); ObjectSet("_Indicator1"+c,OBJPROP_COLOR,DodgerBlue); ObjectSet("_Indicator1"+c,OBJPROP_WIDTH,1); ObjectSet("_Indicator1"+c,OBJPROP_BACK,1);
	  ObjectCreate("_Indicator2"+c,OBJ_TREND,0,Time[c],Low[c]); ObjectSet("_Indicator2"+c,OBJPROP_PRICE1,Indicator2ValPrev); ObjectSet("_Indicator2"+c,OBJPROP_PRICE2,Indicator2Val); ObjectSet("_Indicator2"+c,OBJPROP_TIME1,Time[c+1]); ObjectSet("_Indicator2"+c,OBJPROP_TIME2,Time[c]); ObjectSet("_Indicator2"+c,OBJPROP_RAY,0); ObjectSet("_Indicator2"+c,OBJPROP_COLOR,DarkBlue); ObjectSet("_Indicator2"+c,OBJPROP_WIDTH,1); ObjectSet("_Indicator2"+c,OBJPROP_BACK,1);
	  ObjectCreate("_Indicator3"+c,OBJ_TREND,0,Time[c],Low[c]); ObjectSet("_Indicator3"+c,OBJPROP_PRICE1,Indicator3ValPrev); ObjectSet("_Indicator3"+c,OBJPROP_PRICE2,Indicator3Val); ObjectSet("_Indicator3"+c,OBJPROP_TIME1,Time[c+1]); ObjectSet("_Indicator3"+c,OBJPROP_TIME2,Time[c]); ObjectSet("_Indicator3"+c,OBJPROP_RAY,0); ObjectSet("_Indicator3"+c,OBJPROP_COLOR,Violet); ObjectSet("_Indicator3"+c,OBJPROP_WIDTH,1); ObjectSet("_Indicator3"+c,OBJPROP_BACK,1);
	  ObjectCreate("_Indicator4"+c,OBJ_TREND,0,Time[c],Low[c]); ObjectSet("_Indicator4"+c,OBJPROP_PRICE1,Indicator4ValPrev); ObjectSet("_Indicator4"+c,OBJPROP_PRICE2,Indicator4Val); ObjectSet("_Indicator4"+c,OBJPROP_TIME1,Time[c+1]); ObjectSet("_Indicator4"+c,OBJPROP_TIME2,Time[c]); ObjectSet("_Indicator4"+c,OBJPROP_RAY,0); ObjectSet("_Indicator4"+c,OBJPROP_COLOR,Wheat); ObjectSet("_Indicator4"+c,OBJPROP_WIDTH,1); ObjectSet("_Indicator4"+c,OBJPROP_BACK,1);
	  c++;
	} // End of this loop
	
	EA_DrawingMem=Time[WindowFirstVisibleBar()]; // Redefine the time of the oldest bar on the screen, to prevent unnecessary repetition of this function.
   EA_WindowPriceRangeMem=WindowPriceMax()-WindowPriceMin(); // Redefine the range of the chart, to prevent unnecessary repetition of this function.

} // End of Drawing routine

//-------------------------------------------------------------------------------------------------------------------------------
Once again, any comments are welcome.

Thanks!

youcrazykids
[/size]
You do not have the required permissions to view the files attached to this post.
magft
Trader
Posts: 195
Joined: Tue Nov 15, 2011 9:59 pm
Location: East Midlands, UK

Re: Utility Procedures / Code Snippets

Post by magft »

Here is a link to some code by 7-bit that is useful for debugging code, it removes the reliance on Print statements and use windows api and MS DebugView app to allow real-time logging of values not delayed like using Print and they are top to bottom.

Hope it helps.

Mike
User avatar
gaheitman
Trader
Posts: 655
Joined: Tue Nov 15, 2011 10:55 pm
Location: Richmond, VA, US

Re: Utility Procedures / Code Snippets

Post by gaheitman »

magft wrote:Here is a link to some code by 7-bit that is useful for debugging code, it removes the reliance on Print statements and use windows api and MS DebugView app to allow real-time logging of values not delayed like using Print and they are top to bottom.

Hope it helps.

Mike
This is great stuff, everyone who wants to write any code for Empty4 should read through all of 7-bit's code.

For using DebugView, I wrote a procedure that checks to see if DebugView is running. It currently notifies the user that debug output will not be available, but you could easily change it to do nothing or to switch to old fashioned print statements.

Code: Select all

bool IsDebugViewRunning() {

   string NullString;
   int hWin = FindWindowA("dbgviewClass",NullString);
   if (hWin == 0) 
      Alert("Debug output not available, DebugView application is not running."); 
   else 
      return(true);
     
   return(false);

}
You'll need this statement to import the FindWindow() function:

Code: Select all

#include <WinUser32.mqh>
George
dietcoke
Trader
Posts: 162
Joined: Tue Nov 15, 2011 9:59 pm

Re: Utility Procedures / Code Snippets

Post by dietcoke »

magft wrote:Here is a link to some code by 7-bit that is useful for debugging code, it removes the reliance on Print statements and use windows api and MS DebugView app to allow real-time logging of values not delayed like using Print and they are top to bottom.

Hope it helps.

Mike

I found this independently a few days ago and already I can't live without it, so I came here to post it and discovered I've been beaten to it :(
Image
mbkennel
Trader
Posts: 29
Joined: Tue Dec 20, 2011 5:40 am

Re: Utility Procedures / Code Snippets

Post by mbkennel »

I'll use this post of mine to point to some useful utility libraries procedures as the thread is pinned to the top.

1) Attempt to force download of historical data (up to 2048 bars per pair/timeframe) in a batch script.

http://www.stevehopwoodforex.com/phpBB3 ... f=15&t=254

2) libGMT.h: Broker-independent time-routine: get local time & day of week in NYC,London,Tokyo in HHMM format, independent of server time, and with daylight saving adjustment.

http://www.stevehopwoodforex.com/phpBB3 ... f=15&t=225
"It is a capital mistake to theorize before one has data." Sir Arthur Conan Doyle.
"If your experiment needs statistics, you ought to have done a better experiment" Lord Rutherford.
User avatar
gaheitman
Trader
Posts: 655
Joined: Tue Nov 15, 2011 10:55 pm
Location: Richmond, VA, US

Compound Logic Statements/Code Optimization

Post by gaheitman »

I have been curious for some time about what optimization Empty4 does at runtime with regards to compound logic statements. For example, in this code:

Code: Select all

if (CheckXThingy() == true  && CheckYThingy() == true) DoZThingy()
My expectation is that at runtime Empty4 should evaluate one or the other (I don't care which order) and if it is false, don't evaluate the other one. Same thing for an or statement:

Code: Select all

if (CheckXThingy() == true  || CheckYThingy() == true) DoZThingy()
As soon as one of them evaluates to true, don't check the other one.
    • Note: For newer programmers, the "== true" portion of each test is unnecessary, since CheckXThingy() already returns a true or false value, there is no need to test to see what it returned. You can just use:

      Code: Select all

      if (CheckXThingy() || CheckYThingy()) DoZThingy()
      which I will be doing in the rest of the examples.
      [/i]
To test what Empty4 is actually doing, I wrote the following test script. After each test, I wrote an optimized version.

Code: Select all

bool SendAlert(bool cond,int Id) {

   Alert("Send Alert Called: ",Id);
   return(cond);
}

int start() {

   Alert("Test 1 Begin");
   if (SendAlert(true,1) && SendAlert(false,2) && SendAlert(true,3) && SendAlert(true,4)) 
      Alert("True");
   else
      Alert("False");
   Alert("Test 1 End");

   Alert("Test 1A Begin");
   if (SendAlert(true,1))
      if (SendAlert(false,2))
        if (SendAlert(true,3))
           if (SendAlert(true,4)) 
               Alert("True");
            else
               Alert("False");
   Alert("Test 1A End");
   
   Alert("Test 2 Begin");
   if ((SendAlert(false,1) || SendAlert(false,2))  || (SendAlert(true,3) || SendAlert(true,4))) 
      Alert("True");
   else
      Alert("False");
   Alert("Test 2 End");

   Alert("Test 2A Begin");
   if (SendAlert(false,1))
      Alert("True");
   else if (SendAlert(false,2))
      Alert("True");
   else if (SendAlert(true,3))
      Alert("True");
   else if (SendAlert(true,4))
      Alert("True");
   else
      Alert("False");
   Alert("Test 2A End");
   
   Alert("Test 3 Begin");
   if (False && ((SendAlert(true,1) && SendAlert(false,2))  && (SendAlert(true,3) && SendAlert(true,4)))) 
      Alert("True");
   else
      Alert("False");
   Alert("Test 3 End");
   
   Alert("Test 3A Begin");
   if (False)
      if (SendAlert(true,1) && SendAlert(false,2))
         if (SendAlert(true,3) && SendAlert(true,4)) 
            Alert("True");
         else
            Alert("False");
   Alert("Test 3A End"); 
}
As everyone has already guessed, Empty4 evaluates each condition in the compound statement even if there is no way for the entire statement to evaluate to true. It also evaluates them from left to right.

Often this is no big deal, but in an indicator loop I was doing the following test up to 150 times for each bar on the chart:

Code: Select all

      if (High[i] > Close[bar] && High[i] < High[bar] && LocalMax(i) && High[i] >= maxhigh)
It's slower than I'd like, and I blame Empty4. I am going to rewrite it with nested if() statements even though I hate sacrificing readability. I also hate typing more than absolutely necessary (though many of my posts seem to contradict that statement :D ).

As an aside, functions that we call to test something shouldn't actually change anything. Those are called side-effects and they are bad. :>

George
Dozer
Trader
Posts: 25
Joined: Wed Nov 16, 2011 4:32 pm

Re: Compound Logic Statements/Code Optimization

Post by Dozer »

gaheitman wrote:I have been curious for some time about what optimization Empty4 does at runtime with regards to compound logic statements. For example, in this code:
Excellent optimization tip. Thanks for posting this info George. :D
User avatar
gaheitman
Trader
Posts: 655
Joined: Tue Nov 15, 2011 10:55 pm
Location: Richmond, VA, US

Expert Program Flow

Post by gaheitman »

In my ongoing series of two messages :) , I wanted to share with everyone what I have learned about program flow within an EA. I wrote a simple expert that keeps track of the number of calls made to init(), deinit() and start() using extern, global and static variables. The EA also sends an alert when each procedure is called so you can see the order.

What I have learned so far (some things are what I expected, some are not):
  1. Init() runs when you drop an EA on the chart, even with expert advisors turned off.
  2. When changing options via F7, deinit runs and then init runs, even with expert advisors off.
  3. When changing options via F7, only externs are reset.
  4. Compiling the program while it is attached runs deinit() and resets everything and runs init()
  5. Removing the expert runs deinit()
  6. Dragging the expert back onto the chart runs deinit() from first ea and init() from second
  7. Disconnecting from the server doesn't do a thing.
  8. Changing timeframe or currency runs deinit() and init() and resets all the externs but does not change static values and does not change global variables
I was surprised that code runs even with expert advisors off. I was also surprised that the last one doesn't do a complete restart of the EA.

If you feel like playing, the EA is attached.

George
You do not have the required permissions to view the files attached to this post.
User avatar
gaheitman
Trader
Posts: 655
Joined: Tue Nov 15, 2011 10:55 pm
Location: Richmond, VA, US

Infinite Loop

Post by gaheitman »

Yesterday I had a silly logic error that caused my program to go into an infinite loop. There isn't much you can do when that happens but shut down Empty4. I wasn't able to get any of my debugging print() results either. So I added a time limit to my loop so that if it didn't finish after a certain time, it would still stop.

Original code:

Code: Select all

while (StringLen(tmp)>0) {

  // do some stuff that was supposed to use up all the characters
  // in tmp, but didn't

}
Revised code:

Code: Select all

int stop = GetTickCount()+5000;
while (StringLen(tmp)>0 && stop > GetTickCount()) {
  // do some stuff that was supposed to use up all the characters
  // in tmp, but didn't
   Print(tmp);  //so we can see what we are doing wrong!
}
The code above will run for at most 5 seconds and then finish. Made it a snap to find my logic error. You could also increment a variable within the loop, but this way I didn't have to change anything inside the loop, just in the while condition.

Also, it's safe to leave this code in, should you forget. (I did :lol: )

George
User avatar
gaheitman
Trader
Posts: 655
Joined: Tue Nov 15, 2011 10:55 pm
Location: Richmond, VA, US

Breaking out of good infinite loops

Post by gaheitman »

In the dsugums thread there is a conversation about how to access the F7 functionality in the EA. The EA never leaves the start() procedure after the first tick arrives so that it can monitor prices for currencies that are not on the current chart. It's unfortunate that you can't work off ticks for any currency you want, but there you have it.

If you are really interested in gaining control of the EA through live use of the F7 key, you can make the following changes.

Option 1
This change will drop out of the infinite loop every 5 seconds. This goes against the purpose of the loop, since start() won't start again until the next tick arrives, so it may not be the best solution for this particular EA.

in Start(), change

Code: Select all

   while (x == 0)
to

Code: Select all

   int stop = GetTickCount()+5000;
   while (x == 0 && stop > GetTickCount())
Option 2
This change requires calling a windows API function to see if you have pressed the F7 key. After saving your changes, the EA waits until the next tick arrives, but then stays in the infinite loop again.

Above "int Start()" insert

Code: Select all

#define VK_F7 0x76
#import "user32.dll"
   bool      GetAsyncKeyState(int nVirtKey);
#import
This defines the call to GetAsyncKeyState() so that Empty4 knows how to access the code in user32.dll.

Next, change the loop code to be:

Code: Select all

   while (x == 0 && !GetAsyncKeyState(VK_F7))
For either option, you will need to press the F7 key and hold it in until the dialog box appears.

George
Post Reply

Return to “Coders Hangout”