stevehopwoodforex.com
https://www.stevehopwoodforex.com/phpBB3/
Print view

Utility Procedures / Code Snippets
https://www.stevehopwoodforex.com/phpBB3/viewtopic.php?t=166
Page 2 of 7
Author:  youcrazykids [ Tue Dec 27, 2011 7:08 pm ]
Post subject:  Re: Utility Procedures / Code Snippets

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]
Author:  magft [ Sat Dec 31, 2011 8:30 am ]
Post subject:  Re: Utility Procedures / Code Snippets

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
Author:  gaheitman [ Sat Dec 31, 2011 2:50 pm ]
Post subject:  Re: Utility Procedures / Code Snippets

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
Author:  dietcoke [ Mon Jan 02, 2012 9:43 pm ]
Post subject:  Re: Utility Procedures / Code Snippets

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 :(
Author:  mbkennel [ Sun Jan 22, 2012 1:20 am ]
Post subject:  Re: Utility Procedures / Code Snippets

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
Author:  gaheitman [ Tue Jan 31, 2012 11:04 am ]
Post subject:  Compound Logic Statements/Code Optimization

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
Author:  Dozer [ Tue Jan 31, 2012 3:51 pm ]
Post subject:  Re: Compound Logic Statements/Code Optimization

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
Author:  gaheitman [ Tue Jan 31, 2012 5:03 pm ]
Post subject:  Expert Program Flow

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
Author:  gaheitman [ Thu Feb 02, 2012 7:23 pm ]
Post subject:  Infinite Loop

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
Author:  gaheitman [ Fri Feb 03, 2012 11:18 am ]
Post subject:  Breaking out of good infinite loops

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
All times are UTC Page 2 of 7