Arrow object appears only once in visual mode in MQL4 - 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

Related

mql4 separate window indicator using sin wave function

Below is the original code that creates a sin wave in a separate window for MetaTrader 4. My question is how to code it for a 2nd, or 3rd sin wave. The original code is compiled and is functional. I will also attach the code I added to the original, it still creates the 1st sin wave but not the second wave. I need help coding the 2nd and 3rd waves. Thanks.
This is the original working code:
//---- indicator settings
#property indicator_separate_window
#property indicator_buffers 2 // org 1
#property indicator_color1 Red //
//---- indicator buffers
double ExtBuffer1[];
double Dgr[];
extern datetime StartTime=D'1999.11.10 00:00';
//+---------------------------------------------------------------+
//| Custom indicator initialization function |
//+---------------------------------------------------------------+
int init()
{
IndicatorBuffers(1);
SetIndexStyle(0,DRAW_LINE); // 0
SetLevelValue(0,0); //
//----indicator buffers mapping //
SetIndexBuffer(0,ExtBuffer1);
SetIndexShift(0,25); // B. added
//---- initialization done
return(0);
}
//+---------------------------------------------------------------+
//| Accelerator/Decelerator Oscillator |
//+---------------------------------------------------------------+
int start()
{
int Shift;
int i;
Shift=iBarShift(Symbol(),PERIOD_D1,StartTime); // Only run on PERIOD_D1
ArrayResize(Dgr,Shift+1); // ArrayResize(Dgr,Shift+1); ?????????????????
MyCalc(Shift,1); // ??? 1
for(i=Shift; i>=0; i--)
ExtBuffer1[i]=Dgr[i];
return(0);
}
//+---------------------------------------------------------------+
void MyCalc(int Shift,int i Yhigh)
{
int i;
for(i=Shift;i>=0;i--) // should be >
{
Dgr[i]=i*2.5;
// ..... B. added code below
double val=i*2.5; // 2.5
Dgr[i]=MathSin(3.14159*val/149)+Yhigh; // 149 ,,, Origina code ...
Dgr[i]=MathSin(3.14159*val/180)+Yhigh; changing the /180 to lower degree changes the
frequency
// ..... B. added above code
//Dgr[i]=MathSin(3.14159*Dgr[i]/180)+Yhigh; // Original Dgr[i]=MathSin(3.14159*-
Dgr[i]/180)+Yhigh;
}
}
This code below is the same code, but with my attempt at creating the 2nd sin wave code added to the original code.
//---- indicator settings
#property indicator_separate_window
#property indicator_buffers 2 // org 1
#property indicator_color1 Red //
#property indicator_color2 Orange //
//---- indicator buffers
double ExtBuffer1[];
double ExtBuffer2[];
double Dgr[];
double Dgr2[];
extern datetime StartTime=D'1999.11.10 00:00';
//+---------------------------------------------------------------+
//| Custom indicator initialization function |
//+---------------------------------------------------------------+
int init()
{
IndicatorBuffers(2);
SetIndexStyle(0,DRAW_LINE); // 0
SetIndexStyle(1,DRAW_LINE); // 0
SetLevelValue(0,0); //
//----indicator buffers mapping //
SetIndexBuffer(0,ExtBuffer1);
SetIndexBuffer(1,ExtBuffer2);
SetIndexShift(0,25); // B. added
SetIndexShift(1,25); // B. added
//---- initialization done
return(0);
}
//+---------------------------------------------------------------+
//| Accelerator/Decelerator Oscillator |
//+---------------------------------------------------------------+
int start()
{
int Shift;
int i;
Shift=iBarShift(Symbol(),PERIOD_D1,StartTime); // Only run on PERIOD_D1
ArrayResize(Dgr,Shift+1); // ArrayResize(Dgr,Shift+1); ?????????????????
ArrayResize(Dgr2,Shift+1);
MyCalc(Shift,1); // ??? 1
for(i=Shift; i>=0; i--)
ExtBuffer1[i]=Dgr[i];
ExtBuffer2[i]=Dgr2[i];
return(0);
}
//+---------------------------------------------------------------+
void MyCalc(int Shift, int Yhigh)
{
int i;
for(i=Shift;i>=0;i--) // should be >
{
Dgr[i]=i*2.5;
Dgr2[i]=i*2.5;
double val=i*2.5; // 2.5
double val2=i*2.5; // 2.5
Dgr[i]=MathSin(3.14159*val/149)+Yhigh; // 149
Dgr2[i]=MathSin(3.14159*val2/49)+Yhigh; // 49
}
}
You've just mixed up some lines of your code. Try the following.
//---- indicator settings
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1 Red
#property indicator_color2 Orange
//---- indicator buffers
double ExtBuffer1[], ExtBuffer2[];
double Dgr1[], Dgr2[];
extern datetime StartTime=D'1999.11.10 00:00';
//+---------------------------------------------------------------+
//| Custom indicator initialization function |
//+---------------------------------------------------------------+
int init()
{
IndicatorBuffers(2);
SetIndexStyle(0,DRAW_LINE); SetIndexBuffer(0,ExtBuffer1); SetIndexShift(0,25);
SetIndexStyle(1,DRAW_LINE); SetIndexBuffer(1,ExtBuffer2); SetIndexShift(1,25);
SetLevelValue(0,0);
return(0);
}
//+---------------------------------------------------------------+
//| Accelerator/Decelerator Oscillator |
//+---------------------------------------------------------------+
int start()
{
int Shift;
int i;
Shift=iBarShift(Symbol(),PERIOD_D1,StartTime);
ArrayResize(Dgr1,Shift+1); ArrayResize(Dgr2,Shift+1);
MyCalc(Shift,1);
for(i=Shift; i>=0; i--)
{
ExtBuffer1[i]=Dgr1[i];
ExtBuffer2[i]=Dgr2[i];
}
return(0);
}
//+---------------------------------------------------------------+
void MyCalc(int Shift,int Yhigh)
{
int i;
for(i=Shift;i>=0;i--)
{
Dgr1[i]=i*2.5; Dgr2[i]=i*2.5;
double val1=i*2.5;
double val2=i*2.5;
Dgr1[i]=MathSin(3.14159*val1/149)+Yhigh;
Dgr2[i]=MathSin(3.14159*val2/49)+Yhigh;
}
}

Mql4 undeclared identifier for delete object

I am using the code from the example here Keep order details in arrays?
I am getting an error of listOfTrades - undeclared identifier when I add the code in the
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
delete(listOfTrades);
}
I have a feeling it is because listOfTrades is declared in the OnInit() and not outside global but not sure how that would affect it.
Main.mql
#include <CTrade.mqh>
int OnInit()
{
CArrayObj *listOfTrades=new CArrayObj;
}
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
delete(listOfTrades);
}
Yes, you have to declare that globally, before calling OnInit(). Missed that point in the mentioned question, will update.
If you pass the object by pointer somehow void OnTick(){ doSomeFunction(listOfTrades); } then you should make sure the same variable name is not used (at least in the same file), otherwise you will have warnings that some day may become a bug.
void doSomeFunction(CArrayObj* _listOfTrades)// not "listOfTrades" !!!
{
for(int i=_listOfTrades.Total()-1;i>=0;i--)
{
CTrade* trade=_listOfTrades.At(i);
// action with CTrade object
}
}

Variadic Dispatch Function

I have an interface wherein the types of the parameters mostly encode their own meanings. I have a function that takes one of these parameters. I'm trying to make a function that takes a set of these parameters and performs the function on each one in order.
#include <iostream>
#include <vector>
enum param_type{typeA,typeB};
template <param_type PT> struct Container{
int value;
Container(int v):value(v){}
};
int f(Container<typeA> param){
std::cout<<"Got typeA with value "<<param.value<<std::endl;
return param.value;
}
int f(Container<typeB> param){
std::cout<<"Got typeB with value "<<param.value<<std::endl;
return param.value;
}
My current solution uses a recursive variadic template to delegate the work.
void g(){}
template <typename T,typename...R>
void g(T param,R...rest){
f(param);
g(rest...);
}
I would like to use a packed parameter expansion, but I can't seem to get that to work without also using the return values. (In my particular case the functions are void.)
template <typename...T> // TODO: Use concepts once they exist.
void h(T... params){
// f(params);...
// f(params)...; // Fail to compile.
// {f(params)...};
std::vector<int> v={f(params)...}; // Works
}
Example usage
int main(){
auto a=Container<typeA>(5);
auto b=Container<typeB>(10);
g(a,b);
h(a,b);
return 0;
}
Is there an elegant syntax for this expansion in C++?
In C++17: use a fold expression with the comma operator.
template <typename... Args>
void g(Args... args)
{
((void)f(args), ...);
}
Before C++17: comma with 0 and then expand into the braced initializer list of an int array. The extra 0 is there to ensure that a zero-sized array is not created.
template <typename... Args>
void g(Args... args)
{
int arr[] {0, ((void)f(args), 0)...};
(void)arr; // suppress unused variable warning
}
In both cases, the function call expression is cast to void to avoid accidentally invoking a user-defined operator,.

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).

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

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.

Resources