[Advanced Topic] EL debugging (trouble shooting) guide

Read before posting.
bowlesj3
Posts: 2016
Joined: 21 Jul 2007
Has thanked: 171 times
Been thanked: 402 times

[Advanced Topic] EL debugging (trouble shooting) guide

Postby bowlesj3 » 17 May 2012

This is a thread where users can contribute general procedures for debugging EL code and for reducing the number of bugs one experiences. The idea is that help may not always be available and if the procedures in this thread are followed then all users will be able to solve most of their simple programming problems fairly quickly. More experienced programmers/users will be able to point new users (especially those who have no programming experience at all) to this thread (avoiding duplicated work) and saving them a lot of time.

I am putting a few things in this first post to get it started. I will add things here as I think of them later.

Reducing Bugs:
To help prevent bugs try to format your code with proper indenting and also put comments in the code because when you come back to it a year later it will be a great help.
These threads have a few ideas.

MC/EL frequently triggered traps (how to avoid)
viewtopic.php?f=16&t=7665

Idea for Numbering your large if statements
viewtopic.php?f=5&t=7142

Use long descriptive variable names. Develop a consistent naming scheme for the variables in your code (Example: LastUpBarTime, LastUpBarDate, LastUpBarColor). You'll recall the purpose much faster.

Use long descriptive function names. I name all my indicators and functions starting with "A_" so I can find them easily when I press (file Open) in the editor. I also add some letters and numbers after the "A_" because they are executed in alphabetic order within the chart.

Know the commands properly and test this knowledge:
Make sure you really know the commands that are potentially having a problem. Reread the manual(s) on the command again and create simple tests if you are not sure about something. If you really want to learn a language really well try this. When I taught myself Unix shell scripting I would scan the commands sequentially in the manual every morning over coffee and make up tests for at night (at least 10 commands to test a night). You learn a lot by testing what you read. Try and read every word with a critical eye (not easy to do actually). For example, there is a clue in the documentation of the Alert statement that indicates it will only occur on the LastBarOnChart code. If you see something like this that makes you curious then test it. You will never remember your curiosity but you will probably remember your test.

Know Many Commands:
Try to learn as many commands as possible. Skim the commands making up a list of commands that are likely to be useful. Keep the list where you will be reminded often that you have it so you can remember to reference it and add to it (I have it in a popup in my calendar system and I bump it maybe 2 years out now each time I see it). Try to do this maybe once every year until you are at least aware of the commands. Learn them in detail as you need them. It does not hurt to do this again when you suspect a lot of new commands have been put in. Not only that, if you do it again 1 or 2 years later you will be amazed of what you forgot or what you see as useful now that you did not realize before. Do not just scan the manuals. Also scan and inspect inside the code when you do "File Open" from the editor. I am not referring to indicators but the basic commands. For example the Highest function. It can be inspected. if you do that with all of these types of functions you will learn a lot about EL and know what is available as well.

IntrabarPersist
Not understanding IntrabarPersist can create bugs. Make sure you run the tests on this command. It is contained in this thread along with other useful items.
MC/EL frequently triggered traps (how to avoid)
viewtopic.php?f=16&t=7665

Writing Traces:
For EL I at times create a trace. It is designed to figure out what code is executing. It has a print statement or FileAppend (shown below). You create a series of them. They are initially very simple containing the word "Here" or the word "Trace" plus a number so you can tell which print occurred. So for example "here01", Here02", etc. Later you may insert one with "Here01.001". You place maybe 10 or 15 of them the first time. You use these to figure out where the problem is occurring then once you do figure out what code is executing and where the problem is likely to be you remove the ones you do not need and start including variables in the ones you do need to get more and more information until you figure out the problem.

Writing Traps:
You write a trap when the bug can not be easily reproduced or shall we say is random and seldom occurs. Basically you need to understand the code and create an if statement to test for whatever is going wrong then normally use the FileAppend statement (discussed below) along with a RaiseRunTimeError which forces an abort of your code so you look at the information immediately when your charts are all fresh in your mind. Sometimes along with this you may have an alert command rather than a raiseruntimeerror. At times I will use a PlaySound command rather than an alert. I will either use the standard windows sounds or my own voice. You can not use the Print Statement with the RaiseRunTimeError because you loose the file during the abort. Also the typical trap process involves a series of traps. Your first trap gives you some information and you need to repeat it with more FileAppend Statements which have more variables in them to get more information. I have a few traps in place now. Sometimes it will be a few months before the trap gets tripped again and I will at times have it triggered 2 or 3 times before I figure out the problem.

Print and FileAppend Statements:
Since MC does not have a debugger, Print Statements and FileAppend Statements are your main debuggin tools with MC EL. What you basically end up doing is using a lot of prints/fileappends to test your theory of what should be going on until finally you find the problem (find the theory that is wrong and how to fix it). Persistence is the key (sometimes it can take a few days to figure out a problem and not understanding IntraBarPersist can create such problems). If you do not understand IntraBarPersist you could be looking at 3 weeks. Below is a sample script (which is also in a zip file) that has commented out print and fileappend commands for debugging. I like to have these at the top of most scripts ready to copy in for debugging when I need them. Now that they are all in one place in the zip file code below you can install it and just to to the samples there when you need it. You will obviously need to put in the correct variables for your code that you are testing as you need it. My print statements are designed so that I can copy and paste a line down and copy the new variable in easily. The trace statement samples are short because you often want to place 10 or 15 of them in quickly. Sometimes my trace format allows me to copy and paste variables in but I do not do this until I know the location where I want to do this. Some of the other commands and techniques I mention are also in there.

FileAppend Warning:
Warning. File append may have a bug if too many lines go out. To deal with this you may want to put a delete statement in which executes maybe every day (or every hour if you have a lot of lines going out). I think you need many 1000s of line before it will abort your study. I have a delete command in my code below. If you have it as part of a trap (only tripped with the trap) and there is a RaiseRunTimeError then there is no problem. At times I use FileAppend with a trace and it is fine. Again you need a large number of lines before it aborts (if the bug has not been fixed). You just have to remember to remove the FileAppend commands eventually so leave yourself a note about this in your calendar or have the delete statement if appropriate.

Code: Select all

Inputs: SampleUnused(5);

Variables:
   LogPath(""),
   PrintFile(""),
   AppendFile("");
 
If currentbar=1 then {If:101 - CurrentBar=1 Code}
   begin

   {
   RaiseRunTimeError("Often Used With Trap Debugging Code. " + NumToStr(CurrentDate,0));
   Alert("Often Used With Debugging Code. Nore likely with a trace than a trap but not always." + NumToStr(CurrentDate,0));
   }
   Alert("currentbar=1. (this is a test showing it does not appear until LastBarOnChart. " + NumToStr(CurrentDate,0));

   {START: Path and file commands in the form of comments ready to copy into the code for debugging}
   LogPath = "C:\";
   PrintFile = LogPath + "ALog_Print.txt";
   AppendFile = LogPath + "ALog_Append.txt";

    {START: a sample formatted, easy to change, print statement for debugging you can copy into place}

    {
       Print(File(PrintFile), "Trace 001.001");
   }

    {
       Print(File(PrintFile),
            "10 seconds " ,

            "CurrentTime=",
            CurrentTime, " " ,

            "Time=",
            Time, " " ,

             " ");
 
   }
    {END: a sample formatted, easy to change, print statement for debugging you can copy into place}

    {START: sample formatted, easy to change, fileappend statement for debugging.
    The file is retained if your script aborts.}
   {
    FileDelete(AppendFile);
   FileAppend(AppendFile,
      "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" +                    
        NewLine);
    FileAppend(AppendFile,
      " ProjName=" +                    
           ProjName + " " +
       " CurrentDate=" +                    
           NumToStr(CurrentDate,0) + " " +
      " CurrentTime_s=" +                    
           NumToStr(CurrentTime_s,0) + " " +
          NewLine);
   FileAppend(AppendFile,
      " " +                    
        NewLine);
    }
    {END: sample formatted, easy to change, fileappend statement for debugging. The file is retained if your script aborts.}

   {END: Path and file commands in the form of comments ready to copy into the code for debugging}


   end;  {If:101 - If currentbar=1 then}

 
Alert("All bars. (this is a test showing it does not appear until LastBarOnChart. " + NumToStr(CurrentDate,0));

{Sample code with a good form of proper indenting where the begin and end statements line up.
If barstatus = 2 then
   begin
   if close > Highest(close,40)[1] then
          begin
      Print( File(PrintFile),
            "highest(close,40)[1]=" ,
            highest(close,40)[1],
            " ");
      Print( File(PrintFile),
            "close=" ,
            close,
            " ");
      Print( File(PrintFile),
            "close[41]=" ,
            close[41],
            " ");
      Print( File(PrintFile),
            " ");
      end;
   end;
}
   
if LastBarOnChart then {If:901 - LastBarOnChart code}
   begin   
   
   Alert("Alert only works on LastBarOnChart. " + NumToStr(CurrentDate,0));
   
   end; {If:901 - LastBarOnChart code}






-------------------------------------------------------
Has this post been helpful to you?
You do not have the required permissions to view the files attached to this post.

bowlesj3
Posts: 2016
Joined: 21 Jul 2007
Has thanked: 171 times
Been thanked: 402 times

Re: EL debugging (trouble shooting) guide

Postby bowlesj3 » 13 Jan 2013

I thought I would pass on this recent improvement to a technique I have been using for a long time which helps with debugging code.

The technique is to mark code I am working on with || or ^^ markers so I can search to locate things quickly. They have to be a comment so in EL code I put them inside the {} comment markers like this {||} or {^^}. The recent improvement is to make them more meaningful by adding a number after them or a letter after them such as {||1} or {||A}.

Here is an approximate example.

{||A} to mark the start of an area I am working on.
{||B} to mark the end of an area I am working or or maybe a special part at the very bottom.

{||0} {||1} and {||2} to mark two sections within the "long side" portion of my changes then I duplicate the {||0} {||1} and {||2} in the "short side" portion of my changes.

I just used this pattern for the 1 minute bars changes I made then I used these markers to do a duplicate change in another parallel EL script which is designed for 10 second bars. I will use these markers Monday to help me test and debug any problems.

The change took about 6 hours to complete on Saturday and I figure this technique saved me about 20 or 30 minutes which is normally wasted trying to remember field names to do searches to find things and even if you do remember the names you have multiple hits before you get to the one you want. That is significant in terms of reducing bugs when you are working late into the night and you are tired. It is also going to be significant when you are testing during trading time and do not want to waste any more of that time than you need to.

If I was to make another change to these scripts I would first scan for the old markers from the prior change and remove them. I generally do not remove them until the next change since I could find a bug at any time in the future and they would help remind me of the sections of code I changed.

I would use the {^^A} and {^^1} markers if I was doing to different changes at the same time to the same module.

While I was making this change I found the marking of if statements useful (saving maybe 10 minutes or more). This technique can be found at this link.
Idea for Numbering your large if statements
viewtopic.php?f=5&t=7142

bowlesj3
Posts: 2016
Joined: 21 Jul 2007
Has thanked: 171 times
Been thanked: 402 times

Re: [Advanced Topic] EL debugging (trouble shooting) guide

Postby bowlesj3 » 17 Jan 2013

Speaking of using one's calendar system to remind one of useful ideas so you actually get in the habit of using them here is one I did not put in my calendar reminder system and I stumbled on it another way by accident over a year later. This is a method of locating complex documentation for complex logic. You create a directory called "ProgramDocumentation" on your compute and within that you have the language (example: PowerLanguage"). You create one new document in MS-Word for each complex function or complex set of code. I often mark sets of code using the method below. Inside these "START: / END:" comments you would mention the document name or maybe the hole directory name. Here is an example.

Code: Select all

{START: This code does whatever}
{START: For detained descriptions see C:\ProgramDocumentation\PowerLanguage\ComplexCode1.doc}
      large complex code.
      . . .
      . . .
      . . .
{END:  This code does whatever}
You may have guessed that I now have this idea in my calendar system so I get in the habit of using it more often.

bowlesj3
Posts: 2016
Joined: 21 Jul 2007
Has thanked: 171 times
Been thanked: 402 times

Re: [Advanced Topic] EL debugging (trouble shooting) guide

Postby bowlesj3 » 03 Apr 2013

I made an improvement to my debugging procedures. I try to always have the code below open in the PL editor so I can very quickly drop some new print statements or fileappend statements in any script. As always the formatting makes it very easy to display new fields simply by copying and changing the field name. The path and file names are improved. I also included a statement to make you laugh since laughing when you are debugging really helps. It is much more productive than throwing the computer out the window :-).


Code: Select all

Variables:
   AppendPath(""),
   AppendFile(""),
   
   PrintPath(""),
   PrintFile(""),
   
   strProjName(""),
   
   FutureUse(0);


   AppendFile = "Alog_ArwProj_" + strProjName + ".txt";
   AppendPath = "C:\YourAppendLogPath\" + AppendFile;
   FileDelete(Appendpath);   
      FileAppend(AppendPath,
             "Whatever " +
             
              " CurrentDate=" +
             numtostr(CurrentDate,0)  +
             
              " Currenttime=" +
             numtostr(Currenttime,0)  +

              " Date=" +
             numtostr(Date,0)  +
             
              " time=" +
             numtostr(time,0)  +
             
         NewLine);
         
   PrintFile = "Alog_ArwProj_" + strProjName + ".txt";
   PrintPath = "C:\YourPrintLogPath\" + PrintFile;
      Print(File(PrintPath),"John Hates Winter");
       Print(File(PrintPath),

              " CurrentDate=",
             CurrentDate:5:0,
             
              " Currenttime=",
             Currenttime:4:0,

              " Date=",
             Date:5:0,
             
              " time=",
             time:4:0,

         " ");



Return to “MultiCharts FAQ”