Features of the mql5 language, subtleties and tricks - page 336

 
amrali #:

High-performance time-handling functions applicable to the entire MQL5 date and time range (from 1 January 1970 to 31 December 3000):

(Based on the Neri–Schneider calendar conversion algorithm: see here)

The attached script file contains the source code and comprehensive tests.

What are ULL and U?
 
Vladimir Pastushak #:
What are ULL and U?

  • U suffix   : unsigned int 32 (uint)
  • ULL suffix: unsigned long 64 (ulong)

These unsigned divisors (3600ULL, 86400ULL,..) will force unsgnied division and modulus, esp. when the numerator is of datetime type (treated internally as signed long 64). 

The datetime will be promoted to ulong before performing the division / modulus. This ensures faster optimizations by the compiler. 

datetime / 86400ULL is a bit faster than datetime / 86400.

Signed division and modulus will require extra instructions to handle the signedness.

Check it on https://godbolt.org/


Compiler Explorer
Compiler Explorer
  • Matt Godbolt
  • godbolt.org
Compiler Explorer is an interactive online compiler which shows the assembly output of compiled C++, Rust, Go (and many more) code.
 

Signed vs. unsigned div/mod:

int DayOfWeek(const datetime t)
  {
   return (int)(t / 86400 + THURSDAY) % 7;
  }

int DayOfWeekU(const datetime t)
  {
   return (int)((t / 86400ULL + THURSDAY) % 7U);
  }

#define BENCHSIZE 10000000

ulong randUlong() { return((ulong)rand()<<60)|((ulong)rand()<<45)|((ulong)rand()<<30)|((ulong)rand()<<15)|(ulong)rand(); }

void OnStart() {
   Print("\nCompiler Version: " + (string)__MQLBUILD__ + ", " + __CPU_ARCHITECTURE__);
   Print(TerminalInfoString(TERMINAL_CPU_NAME) + ", " + TerminalInfoString(TERMINAL_CPU_ARCHITECTURE));

   datetime t[];
   ArrayResize(t, BENCHSIZE);
   for(int i = 0; i < BENCHSIZE;i++) {
      t[i] = (datetime) (randUlong() % D'3000.01.01');
   }

   // Tests
   ulong sum = 0;
   ulong tt = GetMicrosecondCount();
   for(int i=0; i<BENCHSIZE; i++) { sum += t[i] + DayOfWeek(t[i]); }
   PrintFormat("%5.2f ns, checksum = %llu   // DayOfWeek", (GetMicrosecondCount()-tt)*1000.0/BENCHSIZE, sum);

   sum = 0;
   tt = GetMicrosecondCount();
   for(int i=0; i<BENCHSIZE; i++) { sum += t[i] + DayOfWeekU(t[i]); }
   PrintFormat("%5.2f ns, checksum = %llu   // DayOfWeekU", (GetMicrosecondCount()-tt)*1000.0/BENCHSIZE, sum);
  }

Results:

 Compiler Version: 5836, AVX2 + FMA3
 13th Gen Intel Core i7-13700KF, AVX2 + FMA3
  1.24 ns, checksum = 162509975528847278   // DayOfWeek
  0.72 ns, checksum = 162509975528847278   // DayOfWeekU
 

Stefano Cerbioni #:
Subject: Feature Request: Introduction of OnChartSwitch Event Handler for Terminal-wide Monitoring

Description:
Currently, in MQL5, an Expert Advisor is strictly bound to the chart it is running on. There is no native, event-driven way to detect when a user switches focus (clicks) between different chart tabs within the terminal unless the EA is present on every single chart.

[...]


This event should:

    Trigger whenever the user clicks on a different chart tab in the terminal.

    Be available to any EA running in the terminal, regardless of which chart the EA is physically attached to (or at least provide a global chart property accessible via OnChartEvent).


Not exactly what you asked for, but you can use this undocumented CHARTEVENT_CHART_CHANGE lparam to detect switching tabs, but it only works if you switch maximized tabs (changing window size), not when they are side by side. 

if(id == CHARTEVENT_CHART_CHANGE)
  {
   if(lparam != 16)
     {
      BroadcastEvent(ChartID(),0,"Broadcast Message");
     }
  }

You could make a minimalistic chart indicator to broadcast custom event to your EA, that would be your "push" trigger.

If you need side by side windows then you could use CHARTEVENT_CLICK but that would either need additional (bool) toggle switch to enable/disable the event or it would spam every time you click on the chart.

I agree there should be better way of handling this.

Documentation on MQL5: EventChartCustom / Working with Events
Documentation on MQL5: EventChartCustom / Working with Events
  • www.mql5.com
The function generates a custom event for the specified chart. Parameters chart_id [in] Chart identifier. 0 means the current chart...
 
amrali #:

Signed and unsigned div/mod operations:

Thank you, that’s a very interesting detail, and I’d like to understand the reasons behind it so that I can write more optimally in general in future.

P.S. I’ve seen the explanation. Thanks again.

 
amrali #:

An alternative to the StructToTime() function in MQL:

Replacing the TimeToStruct() function in MQL:

Brilliant work! Perhaps MQ should consider this solution as a replacement for its standard functions.

The performance boost here is of great practical significance – Tester.

 

How can you quickly reverse a strategy?

Simply change

Trade.Buy(lot, _Symbol, 0, sl, tp);

to

Trade.Sell(lot, _Symbol, 0, ask+bid- sl, ask+bid- tp);

and, following the same logic, swap ‘Sell’ for ‘Buy’

The maths is simple, but not obvious

 
rkdius #:

This isn’t quite what you asked for, but you can use this undocumented parameter, `lparam CHARTEVENT_CHART_CHANGE`, to detect tab switching; however, it only works when switching between tabs in full-screen mode (when the window is resized), not when they are displayed side by side.

You could create a minimalist indicator on the chart that would send a custom event to your expert advisor — this would serve as your ‘push’ trigger.

If you need the windows to be side by side, you could use CHARTEVENT_CLICK, but this would either require an additional toggle (bool) to enable/disable the event, or it would be triggered every time you click on the chart.

I agree that there must be a more convenient way to solve this problem.

ChartGetInteger(0, CHART_BRING_TO_TOP)
Isn’t that right?
 
rkdius #:

This isn’t quite what you asked for, but you can use this undocumented parameter, lparam CHARTEVENT_CHART_CHANGE, to detect tab switching; however, it only works when switching between tabs in full-screen mode (when the window is resized), not when they are displayed side by side.

You could create a minimalist indicator on the chart that would send a custom event to your expert advisor — this would serve as your ‘push’ trigger.

If you need windows positioned side by side, you could use CHARTEVENT_CLICK, but this would either require an additional toggle (bool) to enable/disable the event, or it would trigger every time you click on the chart.

I agree that there must be a more convenient way to solve this problem.

You could track the ID of the active chart in `OnChartEvent` when the mouse is clicked.

ChartGetInteger(0, CHART_BRING_TO_TOP)
 
Aleksandr Slavskii #:

You could track the ID of the active chart in `OnChartEvent` when the mouse is clicked.

That's the hard part because it all depends on how you use MT.
If it's one monitor, one maximized chart then it's easy - either CHART_BRING_TO_TOP or CHART_IS_MAXIMIZED will work.
If you have multiple monitors, multiple chart windows side by side, or detached charts then tracking mouse-click/key-press is probably the right way to go.

It would be much easier if there was a chart property to indicate if the chart window is active or not, or an event handler as Stefano mentioned before.

EDIT:

Actually after briefly testing, CHART_BRING_TO_TOP seems to do the job of "window active", the name is rather unfortunate and misleading. The MQL5 documentation begs for an update...