mql4 Expert Advisor - OnTick() does not do anything in [ Strategy Tester ] - mql4

Part of the code:
int OnInit()
{
Print( "SL mover started" );
return( INIT_SUCCEEDED );
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
modifySLs();
}
void modifySLs()
{
int i, total = OrdersTotal();
Alert( total );
Print( "modify runs" );
for( i = 0; i < total; i++ ) {
modifySLIfNeededForSelectedOrder( i );
}
}
Why OnTick() does not run?
It does not print any message in the log, nor Alert() function gets called when I run in Strategy Tester. OnInit() function works - prints in the log "SL mover started".

MQL4 Documentation is explicit on this:
Alert() function does not work in the Strategy Tester.
So better remove it.
Print() function does not work during optimization in the Strategy Tester.
So, unless your Strategy Tester has genetic optimisation check-box on, this ought create no issues.
If in doubts about indeed "entering" the OnTick() code-block, may equip it with a non-blocking smart informer:
int aGlobatTickCOUNTER = 0;
void OnTick()
{
Comment( "[OnTick()].INF::", ++aGlobalTickCOUNTER );
modifySLs();
}

It runs. Weather you think it does not execute, it executes. it works. Ontick() function is running once when the value is changed in last floating point according to the charts.
But the problem is you can't see it is working because Stratergy tester not allows Alerts() and print() functions. It only allow to execute functions like OrderSend(),OrderClose(),Ordermodify() and etc.

Related

Arrow object appears only once in visual mode in MQL4

I'm an MQL4 newbie and would like to draw an arrow each time a simple trigger is made.
I don't understand why in the attached code below the arrow appears only once while the comment is displayed every time the trigger is made.
How can I solve this issue?
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
double UpBarPlace1 = Close[1]>Open[1];
double UpBarPlace2 = Close[2]>Open[2];
double UpBarPlace3 = Close[3]>Open[3];
double DwBarPlace1 = Close[1]<Open[1];
double DwBarPlace2 = Close[2]<Open[2];
double DwBarPlace3 = Close[3]<Open[3];
if(UpBarPlace1 == 1)
{
Comment ("Sell for 2 range size target ");
ObjectCreate(_Symbol,"Arrow", OBJ_ARROW,0,TimeCurrent(),Close[1]);
} else
{
Comment("Ambiguous");
}
}
The object_name (second parameter in ObjectCreate function) param must by unique for each object.
In your code, the object_name is always equal "Arrow", and this is the reason why the arrow appears only once.
For example, you can create a global counter and iterate it on every arrow create trigger.
ObjectCreate(_Symbol,"Arrow_" + IntegerToString(arrowIndexingCounter), OBJ_ARROW,0,TimeCurrent(),Close[1]);
arrowIndexingCounter++;
object_name -> Name of the object. The name must be unique within a chart, including its subwindows.
ObjectCreate function docs

Async/Await in Dart

I'm making a Flutter app that using asynchronous a lot but it not working like how I understand about it. So I have some question about async and await in dart. Here is an example:
Future<int> someFunction() async {
int count = 0;
for (int i=0; i< 1000000000;i ++) {
count+= i;
}
print("done");
return count;
}
Future<void> test2() async {
print("begin");
var a = await someFunction();
print('end');
}
void _incrementCounter() {
print("above");
test2();
print("below");
}
test2() function will take a lot of time to done. right? So what i want is when test2 keep his work running until done, everything will keep running and not wait for test2().
When i run the function _incrementCounter(), it show the result:
above begin done below end
The problem is it didn't show "below" right away but it wait until someFunction() done.
This is result i want:
above begin below done end
This is the expected behavior since this change in Dart 2.0 which can be found in the changelog:
(Breaking) Functions marked async now run synchronously until the first await statement. Previously, they would return to the event loop once at the top of the function body before any code runs (issue 30345).
Before I give the solution I want to note you that async code are not running in another thread so the concept of:
keep his work running until done, everything will keep running and not
wait for test2()
Is fine but at some point your application are going to wait for test2() to finish since it is spawned as a task on the job queue where it will not leave other jobs to run before it is done. If you want the experience of no slowdown you want to either split the job into multiple smaller jobs or spawn an isolate (which are running in another thread) to run the calculation and later return the result.
Here is the solution go get your example to work:
Future<int> someFunction() async {
int count = 0;
for (int i=0; i< 1000000000;i ++) {
count+= i;
}
print("done");
return count;
}
Future<void> test2() async {
print("begin");
var a = await Future.microtask(someFunction);
print('end');
}
void _incrementCounter() {
print("above");
test2();
print("below");
}
main() {
_incrementCounter();
}
By using the Future.microtask constructor we are scheduling the someFunction() to be running as another task. This makes it so the "await" are going to wait since it will be the first true instance of an async call.

How can I convert Metatrader 4 alert or email indicator signal to Expert Advisor to open trades?

I have been using an indicator to take trades. I didn't develop the indicator, so I only have access to the .ex4 file. How can I extract the take profit, open trade and stop loss values in the alerts or email signals to open trades? Please see a sample of the email and alert signals below.
Here is a working example script of a native MQL solution which uses kernel32.dll to copy the log file from ./MQL4/Logs to ./MQL4/Files. The LogSignalParser abstract base class needs to be subclassed and requires implementation of the virtual bool parse() method.
Edit: #TenOutOfTen would like a practical example of how to parse the following row format in a log file:
0 02:20:00.874 SuperIndicator USDCAD,M5: Alert: USDCAD, M5: Super Indicator SELL # 1.29136, TP 1.28836, SL 1.29286
Step 1: Save the LogParser.mqh somewhere meaningful.
//LogParser.mqh
#property strict
#include <stdlib.mqh>
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayObj.mqh>
#import "kernel32.dll"
bool CopyFileW(string lpExistingFileName,
string lpNewFileName,
bool bFailIfExists);
#import
//+------------------------------------------------------------------+
//|
//+------------------------------------------------------------------+
class Signal : public CObject
{
public:
string symbol;
datetime signal_time;
int order_type;
double price_entry;
double price_sl;
double price_tp;
virtual int Compare(const CObject *node,const int mode=0) const override
{
const Signal *other=node;
if(this.signal_time>other.signal_time)
return 1;
if(this.signal_time<other.signal_time)
return -1;
return 0;
}
string to_string()
{
return StringFormat("%s - %s(%s) # %.5f, SL=%.5f, TP=%.5f",
signal_time,
symbol,
order_type==OP_BUYLIMIT ? "BUY" : "SELL",
price_entry,
price_sl,
price_tp
);
}
};
//+------------------------------------------------------------------+
//|Vector-like collection
//+------------------------------------------------------------------+
class SignalList : public CArrayObj
{
public: Signal *operator[](int i){return this.At(i);}
};
//+------------------------------------------------------------------+
//|Abstract abse class: the parse method must be implemented in subclass
//+------------------------------------------------------------------+
class LogSignalParser : public CObject
{
protected:
CArrayString m_rows;
SignalList m_signals;
string m_log_file_name;
string m_ind_name;
public:
LogSignalParser(string indicator_name);
// parse method must be overridden!
virtual bool parse() = 0;
int Total();
Signal *operator[](int i);
protected:
bool _copy_log();
int _open_log();
bool _parse_rows();
};
//+------------------------------------------------------------------+
LogSignalParser::LogSignalParser(string indicator_name)
{
m_log_file_name="copy_log.log";
m_ind_name=indicator_name;
}
//+------------------------------------------------------------------+
bool LogSignalParser::_copy_log(void)
{
MqlDateTime t;
TimeLocal(t);
string data_path = TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL4";
string logs_path = data_path + "\\Logs\\";
string dest_file = data_path + "\\Files\\" + m_log_file_name;
string log_file=logs_path+StringFormat("%d%02d%02d.log",
t.year,t.mon,t.day);
return CopyFileW(log_file, dest_file, false);
}
//+------------------------------------------------------------------+
bool LogSignalParser::_parse_rows()
{
if(!this._copy_log())
return false;
int h= this._open_log();
if(h == INVALID_HANDLE)
return false;
m_rows.Clear();
while(!FileIsEnding(h)){
string row=FileReadString(h);
if(StringFind(row,"Alert:") >= 0 && StringFind(row,m_ind_name) >= 0)
m_rows.Add(row);
}
m_rows.Sort();
FileClose(h);
return true;
}
//+------------------------------------------------------------------+
int LogSignalParser::_open_log(void)
{
return FileOpen(m_log_file_name,
FILE_TXT|FILE_READ|FILE_SHARE_READ|FILE_SHARE_WRITE);
}
//+------------------------------------------------------------------+
int LogSignalParser::Total(void)
{
return m_signals.Total();
}
//+------------------------------------------------------------------+
Signal* LogSignalParser::operator[](int i)
{
return m_signals.At(i);
}
Step 2: Subclass the LogSignalParser class and override parse
//SuperIndicatorParser.mqh
#property strict
#include "LogParser.mqh"
//+------------------------------------------------------------------+
class SuperIndicatorParser : public LogSignalParser
{
public:
SuperIndicatorParser():LogSignalParser("SuperIndicator"){}
virtual bool parse() override;
};
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
bool SuperIndicatorParser::parse() override
{
if(!this._parse_rows())
return false;
m_signals.Clear();
MqlDateTime local;
TimeLocal(local);
for(int i=m_rows.Total()-1; i>=0; i--)
{
string row=m_rows[i];
MqlDateTime log_time;
TimeToStruct(StringToTime(StringSubstr(row, 2, 12)), log_time);
log_time.year = local.year;
log_time.mon = local.mon;
log_time.day = local.day;
datetime time = StructToTime(log_time);
row = StringSubstr(row, StringFind(row, m_ind_name) + StringLen(m_ind_name) + 1);
StringReplace(row, ",", " ");
string parts[];
StringSplit(row, ' ', parts);
int len = ArraySize(parts);
string debug = "";
for(int k=0;k<len;k++)
debug += "|" + parts[k];
if(len != 17)
continue;
Signal *s = new Signal();
s.signal_time = time;
s.symbol = parts[0];
s.order_type = parts[8] == "BUY" ? OP_BUYLIMIT : OP_SELLLIMIT;
s.price_entry = double(parts[10]);
s.price_tp = double(parts[13]);
s.price_sl = double(parts[16]);
m_signals.Add(s);
}
m_signals.Sort();
return true;
}
Step 3: Use in MQL program (example script)
#property strict
#include "SuperIndicatorParser.mqh"
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
SuperIndicatorParser parser;
if(parser.parse()){
for(int i=parser.Total()-1; i>=0; i--){
Signal *s = parser[i];
int ticket = OrderSend(
s.symbol, s.order_type, 0.1,
s.price_entry, 0, s.price_sl, s.price_tp
);
if(ticket < 0){
Print(_LastError);
}
}
}
}
There's no need to pull the data from your email since the indicator is also sending the data via the Alert function. Alerts are logged to the .\MQL4\Logs directory in a *.log text file. You could write some MQL which uses win32 to read the log, and then make your own parser in MQL.
Another option is to write a watchdog script to scan and parse the log file and write the results to a csv where the EA can access it. The benefit of this method is how easy it is to develop compared to an MQL solution and since it works for all symbols it avoids a potential race condition where multiple EAs are trying to read log write csv at the same time.
Here is an example written in Python.
import csv
import re
import time
from datetime import datetime
from pathlib import Path
MQL_DATA_PATH = Path(
'C:/Users/user/Desktop/MT-TEST/Vanilla-MT4-v0_0_2/MT4/MQL4'
)
OUTPUT_FILENAME = 'signals.csv'
signal_pattern = re.compile(r'''# regex - verbose mode
(?P<time>\d\d:\d\d:\d\d).*? # time stamp
(?P<symbol>[A-Z]{6}\w*),.*? # symbol with ECN suffix
(?P<type>BUY|SELL).*? # BUY or SELL command
(?P<price>\d+\.\d+).*? # execution price
(?P<tp>\d+\.\d+).*? # takeprofit
(?P<sl>\d+\.\d+) # stoploss
''', re.VERBOSE)
def log_to_csv():
date = datetime.now()
log_file = MQL_DATA_PATH / 'Logs' / f'{date.strftime("%Y%m%d")}.log'
with open(log_file) as f:
log_entries = f.read()
signals = [s.groupdict() for s in signal_pattern.finditer(log_entries)]
for signal in signals:
# correct time to MQL datetime
signal['time'] = f"{date.strftime('%Y.%m.%d')} {signal['time']}"
csv_file = MQL_DATA_PATH / 'Files' / OUTPUT_FILENAME
with open(csv_file, 'w') as f:
writer = csv.DictWriter(f,
fieldnames=('time', 'symbol', 'type', 'price', 'tp', 'sl',),
lineterminator='\n',
)
writer.writerows(signals)
def main():
print(f'Watching MQL log and saving signals to {OUTPUT_FILENAME}')
print('Press Ctrl+C to exit')
while True:
try:
log_to_csv()
print(datetime.now().strftime('%Y.%m.%d %H:%M:%S'), end='\r')
time.sleep(5)
except KeyboardInterrupt:
exit()
if __name__ == '__main__':
main()
MT4 cannot read your emails. You need to employ some other tools or a more universal language to read your emails, Java.Mail.API or Pyhton, or something else.
Read the email, make sure the the format is correct and it is from the sender you are expecting, then put down the message into a file that is available to MT4 - either own folder (C:\Users\UserName\AppData\Roaming\MetaQuotes\Terminal\12345678E7E35342DB4776F5AE09D64B\MQL4\Files) or Common folder (C:\Users\User1\AppData\Roaming\MetaQuotes\Terminal\Common\Files). Then read the file from the MT4 application using FileSearchNext() function and example in MQL4 docs. After reading the file, you need to parse it with the String functions, and create a OrderSend() request (probably check the input and that your logic allows your robot to send a trade, e.g. you do not have reached maximum of allowed open trades, trading time, other logic).

What can be done by void functions in MQL4?

A question by an MQL4 newbie.
What are the limits of what a void function can do in MQL4?.
I mean what can be done by a void function code and what can not be done?.
"void" only means that there is no return value from such function. So "returning a value" can not be done by a void function.
Hope that help....
you can put everything in a void function that you can put in a double, int, string, bool, ... function. What changes is what type of variable the function returns.
For instance, the following int function returns the sum of two values.
int sum( int a, int b )
{
return( a + b );
}
you could turn this function into a void function and instead of returning the value, you can print the value to the console.
void printsum( int a, int b )
{
Print( a + b );
}
In your follow up answer you ask about creating a void function that does something to a moving average. The following void function will accept different periods as input and print the MA. The function can't directly return the value of anything ( unless you use global variables / pass variables by reference ), but it can still accept values and do stuff based on those values.
void PrintMA( int period )
{
Print( iMA( NULL, 0, period, 8, MODE_SMMA, PRICE_MEDIAN, 1 ) );
}
The int function in your follow up answer only ever returns 0, so you could swap it to a void function and remove return(0) and it will work as before. Just change the function name first as start is a function name you should avoid using.
If you read the compile log, you'll be able to see why your above answer won't compile.
The only thing a void function(...) cannot do is to ever participate in an MQL4 assignment statement, i.e.:
someVariable = aVoidDeclaredFUNCTION();
Except this, one can do literally everything imaginable.
How that can be useful?
void aVoidDeclaredFUNCTION( const int thisParameterWillNeverChangeItsVALUE,
int &thisParameterWillBeAbleToChangeVALUE
){...}
Using a technique to pass by-Value, resp. to pass by-reference ( &passVariableByREF ) , even a void function(...) can process and "return"-results, if it is not enough to cause some actions in the void function(...){...} body, per-se.
"Void" just means the function doesn't return anything. These are useful for segmenting any stand alone sections of code (to make the code more organized for example, or to prevent repeating code... etc).
See this short video (not made by me) on the topic: Void Functions

my process doesn't go to the child process

I have to take a user input number 'n' in the parent process and then pass it to the child process.The child process then takes 'n' user input values and stores them in an array.It then call a thread and send this array as an argument.The thread sums all the values in the array and send it back to the child process which prints it.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
#include<fcntl.h>
void *sum(void *a)
{printf("in thread" );
int * arr=(int *)a;
int i;
int sum=0;
int size=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<size;i++)
{
sum=sum +arr[i];
}
pthread_exit(sum);
}
int main()
{
int pipefd[2];
pid_t childpid;
pthread_t tid;
pipe(pipefd);
int r;
int n;
childpid=fork();
if (0==childpid)
{
printf("in child process" );
close(pipefd[1]);
read(pipefd[0],r,sizeof(int));
close(pipefd[0]);
int *ret;
int a[r];
int i;
for (i = 0; i <r; i++)
{ printf("enter values: ");
scanf("%d",&a[i]);
}
pthread_create(&tid,NULL,sum,(void *)a);
pthread_join(tid,(void *)&ret);
printf("%d",*ret );
}
else
{ printf("in parent process" );
printf("enter a number" );
scanf("%d",&n);
close(pipefd[0]);
write(pipefd[1],n,sizeof(int));
close(pipefd[1]);
}
return 0;
}
I have checked this code a dozen of times and nothing seems to be wrong.The process stops after taking the value of 'n'.The child process never runs.
Both read and write expect to receive the memory address of a buffer to use. You need to take the address of the variables you're trying to fill.
E.g.
write(pipefd[1], &n, sizeof(int));
and
read(pipefd[0], &r, sizeof(int));
By the way, the child process most likely is running. It's just your value for r is coming back as 0. Simple debugging trick: Use fprintf(stderr, "stuff to print"); to check your results at various stages. You can easily verify the child process is running, for example.

Resources