Inconsistent behavior?

 

I've been developing code on other platforms (Tradestation, WealthLab, etc) for years, but I'm new to MQL. Haven't learned the "tricks" yet, and I think that's biting me.

I have a fairly complex indicator that seems to work. Sometimes. And I can't figure out the "sometimes" part.

E.g.: I compile the indicator. I apply it on my chart. It works just like it should. Then without touching the code I recompile, and the results change -- arrows disappear, things like that.

With other code I'd see it work wrong when e.g. I changed timeframes on the chart, but a recompile (with no code changes) would change the results to work right.

How can a freshly compiled and applied indicator work differently than the same indicator after another recompile?? There are no error messages/etc in the Experts tab.

Thanks -- Gary

 
garyfritz:

How can a freshly compiled and applied indicator work differently than the same indicator after another recompile?

It cannot. The proof is in the codes which we cannot see.
 

Sounds like a zen koan. :)

Well, I figured out the cause for this particular issue. When you recompile, the inputs revert to the default values. I didn't realize it did that. I'd changed one of the params, and that change got discarded when I recompiled.

I have a similar puzzle involving initialization. I'm calculating an EMA by hand -- monitoring intraday H/L and using that to calculate an N-day ADR. Code below. (Sorry, can't figure out how to make the SRC button work for entering code...)

So I initialize adr20 to -1, using that as a flag to initialize the EMA to a reasonable value so it stabilizes quickly.

I run it on a chart, and I get a final EMA value of 99 pips. If I refresh the chart, the value changes to 109, and a second refresh changes it to 110. It's stable after that. If I recompile, OR if I switch timeframes and then back again, it goes back to 98.

I declared adr20 as a static so it would retain its value from call to call. I expected that a refresh would act exactly like switching timeframes & back, re-running the indicator from scratch, thus re-initializing adr20 to -1.0 and producing the same result. But it appears the refresh does NOT re-initialize adr20, just leaving it at its current value, which causes the EMA to converge quicker.

I tried making adr20 a global static, but it still changes after a refresh.

Since refresh apparently doesn't re-run the indicator from scratch, is there a way to ensure that the behavior is the same with a refresh as it is with a recompile or TF switch? Or do I just need to avoid doing a refresh if this is a problem?

Gary

========

static double adr20 = -1.0, ema10fact = 2.0 / (1.0 + 20.0);
static double HighToday = -999999.9, LowToday = 999999.9, Range;
int point;
double Range;

point = Point;
if(Digits == 3 || Digits == 5) 
   point *= 10;

// Calculate 20-day EMA of daily H-L

HighToday = MathMax(HighToday, High[bar]);
LowToday  = MathMin(LowToday, Low[bar]);

if (TimeDay(Time[bar]) != TimeDay(Time[bar+1]))  // New day, update ADR EMA
{
   Range = (HighToday - LowToday) / point;
   
   if (adr20 < 0)     // Initialize ADR EMAs?
   {
      adr20 = Range;
   }
   adr20 = ema20fact * Range + (1-ema20fact)*adr20;   
   HighToday = -999999.9;
   LowToday = 999999.9;
}
 

Here's the list of Init Reasons. https://docs.mql4.com/constants/uninit

If you don't want values changing between Un-Init and Re-Init then consider using GlobalVariableSet.

I don't think the Manual Refresh Event can be tracked by mql4. However closest match would be RefreshRates.

As a programmer, you can set if(RefreshRates){do something}.

Hope that helps. I'm not the expert on here.

 

Oh.. About SRC. Just copy codes and paste it after you hit the SRC button. Then hit OK or whatever.

 

Thanks!

Yeah, I used the SRC button, entered my code, then hit SRC again to go back to the message, and the source seemed to disappear. I see now -- I missed the "insert" button.

 
garyfritz:
How can a freshly compiled and applied indicator work differently than the same indicator after another recompile?
When you compile it, it goes through a deinit/init cycle. Same for switching periods and pairs. But global and static are NOT reset.
type function1(){ ..
  static type astat = 99999.
needs to become
int init(){ ...
  onInitFunction1();
  :
}
type astat; void OnInitFunction1(){ astat = 99999.; }
type function1(){ ..
 

OK, global and static are not reset. That explains the behavior I'm seeing. (But they ARE reset when you recompile, correct?)

So your solution is to declare the variables global, and explicitly initialize them in the init() function. Because they're global they retain their values from tick to tick, but you make sure they get reinitialized no matter how the chart gets updated: recompile, refresh, change symbol, change timeframe, whatever. That makes sense. Thanks!

EDIT: Hm. Refresh does **NOT** call the init() function. That's bogus. But at least this global solution should fix all the other cases. I don't see how you can properly deal with a refresh if it doesn't run any of the init code!!

 

But they ARE reset when you recompile, correct? Yes.

Looking ahead a little. Keep in mind that global and static will reset if you close the terminal and re-open for any reason. eg: mistakenly hit the close button; terminal freeze; restart computer; kick power cord; vps maintenance reset...etc. I wouldn't depend on global and static to save values between restarts.

Preferred option#1: Write EA/Indicator in a manner where it looks at previous bars/orders and continue where it stopped.

Preferred option#2: Write Cache/Arrays Values to file. Or GlobalVariableSet. Then back-up to external Hard-Drive or Online.

Backup is for in case computer crashes.

 

EDIT: Hm. Refresh does **NOT** call the init() function. That's bogus. But at least this global solution should fix all the other cases. I don't see how you can properly deal with a refresh if it doesn't run any of the init code!!

If you know how to program Windows API then there might be a solution for capturing the Refresh Event using that. Therefore, you could use something like Windows32.dll ... If(User_Refresh...or F_Key Equivalent){ Force_onInitFunction1(); }. Sorry I wouldn't have a clue where to start with Windows API.

 

Eww. I'll save the Windows API for more urgent/essential cases. I wouldn't have a clue either.

Yes, I understand global & static get reset anytime you restart the terminal. I'm OK with that, at least for my current application.

Reason: