Email Notification when Expert Advisor fails to close a trading position - mql4

I'm trying to develop a piece of MQL4 code which sends you a notification when an position opened by an Expert Advisor fails to close/liquidate when the conditions specified by the Expert Advisor are met.
Here is what I have so far.The ClosePosition() returns true when the position is closed successfully and returns false when the EA fails to close the position. This is where the else if (ClosePosition == false) kicks in.
//Order Close//
string sym = Symbol();
int ordersTotal = OrdersTotal();
for(int PosSel = ordersTotal-1; PosSel>=0; PosSel--)
{
if(OrderSelect(PosSel,SELECT_BY_POS,MODE_TRADES))
if(OrderTicket() > 0)
if(OrderMagicNumber() == Period())
if(OrderSymbol() == Symbol())
if(TimeCurrent() >=(OrderOpenTime() + 60 * Period()))
{
ClosePosition = OrderClose(OrderTicket(),8,MarketInfo(sym,MODE_BID) + MarketInfo(sym,MODE_SPREAD) * MarketInfo(sym,MODE_POINT),300,clrNONE);
if(ClosePosition == true)
{
Sleep(60000);
int PosSelHist = OrdersHistoryTotal()-1;
bool reshist = OrderSelect(PosSelHist,SELECT_BY_POS,MODE_HISTORY);
if(reshist == true && Digits == 5)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail("Trade Notification Email (TNE)","Order# "+DoubleToStr(Ticket,0)+" has been closed on the account "+AccountName()+
"\n"+
"\nThe order exit price for this trade is "+DoubleToStr(ClosingPrice,5)+"with a profit/loss of"+DoubleToStr(Profit,2)+
"\n"+
"\nThe spread charge for this position is £"+DoubleToStr((spread*tickvalue)*LotSize,2)+
"\n"+
"\n-----------------------------------------------------------------------"+
"\n"+
SendNotification("Ticket # "+IntegerToString(Ticket,10)+"has closed with a profit/loss of "+DoubleToStr(Profit,2));
}
else if(reshist == true && Digits == 3)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail("Trade Notification Email (TNE)","Order# "+DoubleToStr(Ticket,0)+" has been placed on the account "+AccountName()+
"\n"+
"\nThe order entry price for this trade is "+DoubleToStr(ClosingPrice,3)+"with a profit/loss of"+DoubleToStr(Profit,2)+
"\n"+
"\nThe spread charge for this position is £"+DoubleToStr((spread*tickvalue)*LotSize,2)+
"\n"+
"\n-----------------------------------------------------------------------"+
SendNotification("Ticket # "+IntegerToString(Ticket,10)+" has closed with a profit/loss of "+DoubleToStr(Profit,2));
}
}
else if(ClosePosition == false)
{
int failedClosePosition = OrdersTotal()-1;
bool fail = OrderSelect(failedClosePosition,SELECT_BY_POS,MODE_HISTORY);
if(fail == true)
{
SendNotification("Order Number #"+IntegerToString(OrderTicket(),10)+" has failed to close. Please refer to error code "+IntegerToString(GetLastError()));
}
}
}
}
Firstly, is this the correct way in getting the desired result, and secondly; is this the correct way of coding the alternative for the ClosePosition == true, or would this be an if instead of an else if?

It is possible that you will try to close your position but fail due to some regular issues - requote, or trade context is busy or some other.
For such reason you MUST make sure the closing price is fresh
RefreshRates();
also you may try to solve TradeContext issue and others, alternative way - try to send some number of close requests:
int ATTEMPTS; // declare on a global scope
int OnInit(){ // initialise
ATTEMPTS = IsTesting() ? 1 : 100; // ternary-op =boolA?valB:valC
//---
return(INIT_SUCCEEDED);
}
void Order_Close(){
int ticket = GetTicketNumberToClose(); // put all checks here
TradeClose(ticket);
}
void TradeClose(int ticket){ // change to bool
// returning T/F if you need
while(IsTradeContextBusy()) Sleep(5); // a blocking-loop
int current_attempt = 0, err=-1;
while(current_attempt < ATTEMPTS){
RefreshRates(); // get fresh prices from Market
if (!OrderClose(ticket,OrderLots(),OrderClosePrice(),5)){
err = GetLastError();
current_attempt++;
}else return;
}
Print( __LINE__,
"failed to close ticket#", ticket,
" at price", DoubleToStr( OrderClosePrice(), Digits ),
". err#", err
); // send notification
// instead of Print() if you need
}

No, sorry. The code is hard to get confirmed to be correct.
Sure, a few syntax errors could be fixed.
A big portion of processing is duplicated, which may work, but is hard to maintain in a longer run and is considered a poor software engineering practice/habit.You may benefit from rather retaining a unique OrderTicket() value once searching the db.POOL and then straight SELECT_BY_TICKET, which is robust against all order_state / order_relative_position changes in both of the { MODE_TRADES | MODE_HISTORY } parts of the db.POOL.
Next is the worse enemy for the proposed MQL4 code:
If one may believe this, never block the flow of the code. MQL4 code-execution environment is event-based, triggered by the external source of events ( The Market ) and calling Sleep( 60000 ) is worse than taking a sleep on the rails, right in the exit from the EuroTunnel. OUCH!!
Your code is envictimed not to be able to react, and worse, not to be able to let other parts of the MQL4 code eco-system breathe in sync with the flow of The Market Events. There are sure better ways, how to do "almost nothing", than Sleep(), believe me.
Efficiency tips:
Avoid code-duplicates and rather use Digits-specific formatting, be it via a variable set to actual number of decimal places, or via StringFormat() patterns.
May enjoy a bit different layout of code, that will help you avoid syntax errors, missed parentheses et al.
Prefer to use globally unique, direct-pointer-alike OrderTicket() numbers, as evaluated in OrderClose() and rather pre-store it's value, as you wish to re-use it later in the code, but not having it readily available from the OrderClose()-moment.
May enjoy another IDE for MQL4 code-effort, where collapsing and columnar blocks become very handy ( Geany, SciTe, JEdit, Notepad++ ).Here, you soon physically view the inefficiency in if(){}else if(){} code-blocks, where the natural mutual {True|False}-dichotomy was duplicated in the else part.
Anyway, enjoy the wild worlds of MQL4
//Order Close//
string sym = Symbol();
int ordersTotal = OrdersTotal();
for ( int PosSel = ordersTotal - 1; // loopVar .SET
PosSel >= 0; // loopVar .PRE-condition
PosSel-- // loopVar .DEC at loop-end
)
{
if ( OrderSelect( PosSel, SELECT_BY_POS, MODE_TRADES ) )
if ( OrderTicket() > 0 )
if ( OrderMagicNumber() == Period() )
if ( OrderSymbol() == Symbol() )
if ( OrderOpenTime() <= TimeCurrent() - ( 60 * Period() ) )
{
ClosePosition = OrderClose( OrderTicket(),
8,
MarketInfo( sym, MODE_BID )
+ MarketInfo( sym, MODE_SPREAD )
* MarketInfo( sym, MODE_POINT ),
300,
clrNONE
);
if ( ClosePosition == true )
{ // ===================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||====================
Sleep( 60000 ); //|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| BLOCKS EA-EXECUTION
// ===================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||====================
int PosSelHist = OrdersHistoryTotal() - 1;
bool reshist = OrderSelect( PosSelHist, SELECT_BY_POS, MODE_HISTORY );
if ( reshist == true
&& Digits == 5
)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail( "Trade Notification Email (TNE)",
"Order# " + DoubleToStr( Ticket, 0 )
+ " has been closed on the account " + AccountName()
+ "\n"
+ "\nThe order exit price for this trade is " + DoubleToStr( ClosingPrice, 5 )
+ "with a profit/loss of" + DoubleToStr( Profit, 2 )
+ "\n"
+ "\nThe spread charge for this position is £" + DoubleToStr( ( spread
* tickvalue
)
* LotSize, 2 )
+ "\n"
+ "\n-----------------------------------------------------------------------"
+ "\n"
+ SendNotification( "Ticket # "
+ IntegerToString( Ticket, 10 )
+ "has closed with a profit/loss of "
+ DoubleToStr( Profit, 2 )
)
);
}
else if ( reshist == true
&& Digits == 3
)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail( "Trade Notification Email (TNE)",
"Order# " + DoubleToStr( Ticket, 0 )
+ " has been placed on the account " + AccountName()
+ "\n"
+ "\nThe order entry price for this trade is " + DoubleToStr( ClosingPrice, 3 )
+ "with a profit/loss of" + DoubleToStr( Profit, 2 )
+ "\n"
+ "\nThe spread charge for this position is £" + DoubleToStr( ( spread
* tickvalue
)
* LotSize, 2 )
+ "\n"
+ "\n-----------------------------------------------------------------------"
+ SendNotification( "Ticket # "
+ IntegerToString( Ticket, 10 )
+ " has closed with a profit/loss of "
+ DoubleToStr( Profit, 2 )
)
);
}
}
else if ( ClosePosition == false )
{
int failedClosePosition = OrdersTotal() - 1;
bool fail = OrderSelect( failedClosePosition, SELECT_BY_POS, MODE_HISTORY );
if ( fail == true )
{
SendNotification( "Order Number #"
+ IntegerToString( OrderTicket(), 10 )
+ " has failed to close. Please refer to error code "
+ IntegerToString( GetLastError() )
);
}
}
}
}

Related

Invalid Ticket when closing orders

I'm trying to close all opened orders, they are all MarketOrders not PendingOrders and have SL and TP set to 0 so they shouldn't close themselves (they are still opened in Terminal). I am storing tickets in the array so my loop looks like:
for(int i = 0; i < trades.size(); ++i) OrderClose(tickets[i], lots[i], Bid, Slippage);
yet I'm still receiving "INVALID TICKET" error, can you tell me why?
It doesn't happen always, its like some orders are closed and some throw Invalid Ticket.
I didn't notice this behavior with only 1 order so I'm assuming it occurs only when there are more of them.
Code:
template < typename T >
struct vector {
vector() {}
vector(int arraySize) {
if (arraySize < 0) { arraySize *= -1; }
ArrayResize(m_data, arraySize);
}
vector(vector & rhs) {
if (size() < rhs.size()) { ArrayResize(m_data, rhs.size()); }
for(uint i = 0; i < size(); ++i) { m_data[i] = rhs.m_data[i]; }
}
vector operator=(vector & rhs) {
if (size() < rhs.size()) { ArrayResize(m_data, rhs.size()); }
for(uint i = 0; i < size(); ++i) { m_data[i] = rhs.m_data[i]; }
return this;
}
T operator[](uint index) { return m_data[index]; }
void push_back( T value ) {
ArrayResize(m_data, ArraySize(m_data) + 1);
m_data[ ArraySize(m_data) - 1 ] = value;
}
uint size() { return ArraySize(m_data); }
void resize(uint newSize) { ArrayResize(m_data, newSize); }
void erase() {
ZeroMemory(m_data);
ArrayResize(m_data, 0);
}
void assign(uint index, T value) {
m_data[index] = value;
}
private:
T m_data[];
};
string Buy(double lots) {
string alertString = "";
int __ticket;
if ( (__ticket = OrderSend (Symbol(), OP_BUY, lots, Ask, Slippage, 0, 0, NULL, m_magic)) != -1 )
{
m_buyTicket.push_back( __ticket );
m_buyLots.push_back( lots );
m_buyPrice.push_back( Ask );
m_buyAccel.push_back( lots / Lots );
m_buyPos.push_back( 0 );
alertString = "Buy function call." +
"\nAsk\t= " + (string)Round(Ask) +
"\nBid\t= " + (string)Round(Bid) +
"\nLots\t= " + (string)Round(lots) +
"\nSpread\t= " + (string)m_spread +
"\nID\t= " + (string)CountAll();
}
else {
int _error = GetLastError();
alertString = "Error " + (string)_error + "\n" + TranslateError( _error );
}
return alertString;
}
string CloseAll() {
string alertString = "CloseAll function call.";
// Buy closing
for (uint i = 0; i < m_buyPrice.size(); ++i)
{
if ( OrderClose ( m_buyTicket[i], m_buyLots[i], Bid, Slippage) )
{
alertString += "\nBuy " + (string)(i+1) + " closed with profit " +
(string)Shrink ( (Bid - m_buyPrice[i]) * m_buyAccel[i] );
}
else
{
int _error = GetLastError();
alertString += "\nError " + (string)_error + "\n" + TranslateError( _error ) +
"\n(while closing Buy " + (string)(i+1) + ")";
}
}
// Sell closing
for (uint i = 0; i < m_sellPrice.size(); ++i)
{
if ( OrderClose ( m_sellTicket[i], m_sellLots[i], Ask, Slippage) )
{
alertString += "\nSell " + (string)(i+1) + " closed with profit " +
(string)Shrink ( (m_sellPrice[i] - Ask) * m_sellAccel[i] );
}
else
{
int _error = GetLastError();
alertString += "\nError " + (string)_error + "\n" + TranslateError( _error ) +
"\n(while closing Sell " + (string)(i+1) + ")";
}
}
return alertString;
}
when you close some ticket successfully, you do not remove it from the list trades, right? And it seems you should. Use your struct to clear the elements if order close is successful.
By the way, there's probably no need to reinvent the wheel, use CArrayObj as a container for your elements and delete them once order is closed.

How to avoid Round-up from NormalizeDouble and OrderSend Pending Order (SELLLIMIT, BUYLIMIT) get Error -1 Invalid stops

Please advice me how to solve problem when OrderSend Pending Order ( BUYLIMIT, SELLLIMIT) got error -1 Invalid stops.
also tell me the rule of BUYLIMIT and SELLLIMIT.
the simple code like below:
`
double digit = MarketInfo(symbol,MODE_DIGITS);
POPRICE = NormalizeDouble(BBMVAL[0],digit);
TPPRICE = NormalizeDouble(POPRICE + (30*point),digit)
SLPRICE = NormalizeDouble(POPRICE - (30*point),digit)
ticket1=OrderSend(symbol,OP_BUYLIMIT,0.1, POPRICE,Slippage,SLPRICE,TPPRICE,BUYLIMIT,magic,(TimeCurrent()+(3600*2)),CLR_NONE);
Sleep(10);
while(IsTradeContextBusy()) Sleep(100);
RefreshRates();
if(ticket1 < 0)
{
SendMail
(
symbol+"-"+ IntegerToString(Period())+"-" + "FAILED-BUYLIMIT ",
symbol+"-"+ IntegerToString(Period())+"-" + "FAILED-BUYLIMIT "+"(#PO-Price:"+POPRICE+"#TP:"+TPPRICE++"#SL:"+SLPRICE+"#RespID:"+ticket1+"#Status: "+ErrorDescription(GetLastError())+")"
);
ticket1 = 0;
}
if (ticket1 > 0)
{
b_Status = 1;
SendMail
(
symbol+"-"+ IntegerToString(Period())+"-" + "SUCCESSED-BUYLIMIT ",
symbol+"-"+ IntegerToString(Period())+"-" + "SUCCESSED-BUYLIMIT "+"(#PO- Price:"+POPRICE+"#TP:"+TPPRICE+"#SL:"+SLPRICE+"#RespID:"+ticket1+"#Status: "+ErrorDescription(GetLastError())+")"
);
ticket1 = 0;
}
the objective is :
If the pair EURUSD 5-digit, How to make the SLPRICE, POPRICE, TPPRICE always with 5-digit. sometimes with 5 digit and sometime roundup with 4-digit. is it right to use NormalizeDouble ? how to avoid the roundup.
when got Failed ( tiket1 < 0 ), the error is -1 ( invalid stops), what is the real reason of this error. sometimes successed and sometime failed. what is the rules of selllimit and the buylimit.
and when got Failed, there are many emails send to email-address. how to avoid this problem too.
THank you very much.
It is perfectly okay to have a 4 digit price when 5 digit decimal is expected, but since double is a floating-point number, sometimes you don't get the exact price you might expect,
for example:
let's say you are calculating TP for a long trade, 1.10000 + 0.0020 = 1.10020(expected) but you might get something like this 1.10020001, in these cases the price level is rejected, causing errors. That is why price normalizing is important.
In some pairs, you might find that NormalizeDouble() sometimes gives false values, in those cases use the following function.
double NP(const double price)
{
double tickSize = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE);
return (MathRound(price / tickSize) * tickSize );
}
As for getting the many emails: you can limit the number of emails per period of time.
Here I made it so that you get 1 email per new candle:
if(ticket1 < 0)
{
static datetime prevTime = 0;
if(Time[0] > prevTime)
{
SendMail
(
symbol + "-" + IntegerToString(Period()) + "-" + "FAILED-BUYLIMIT ",
symbol + "-" + IntegerToString(Period()) + "-" + "FAILED-BUYLIMIT " + "(#PO-Price:" + POPRICE + "#TP:" + TPPRICE++"#SL:" + SLPRICE + "#RespID:" + ticket1 + "#Status: " + ErrorDescription(GetLastError()) + ")"
);
prevTime = Time[0];
}
ticket1 = 0;
}

not correct num histgram

Im trying to make a toString method that prints out a histogram that shows how often each character of the alphabet is used in a string. The most frequent character has to be 60 #s long, with the rest of the characters then scaled to match.
My issue is with making the equation that scales the rest of the letters to the correct length for the histogram. My current equation is (myArray[i]/max) * 60, but im getting really weird results.
If I put in "hello world" to be analyzed, L would be the most common occuring letter, seen 3 times. So L should have 60 #s for the histogram, h should have 20, o should have 40 etc. Instead im getting results like d : 10
e : 10
h : 10
l : 360
o : 20
r : 10
w : 10
Sorry for how sloppy this is right now, im just trying to figure out whats going on
public class LetterCounter
private static int[] alphabetArray;
private static String input;
/**
* Constructor for objects of class LetterCounter
*/
public LetterCounter()
{
alphabetArray = new int[26];
}
public void countLetters(String input) {
this.input = input;
this.input.toLowerCase();
//String s= input;
//s.toLowerCase();
for ( int i = 0; i < input.length(); i++ ) {
char ch= input.charAt(i);
if (ch >= 97 && ch <= 122){
alphabetArray[ch-'a']++;
}
}
}
public void getTotalCount() {
for (int i = 0; i < alphabetArray.length; i++) {
if(alphabetArray[i]>=0){
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i]);
}
}
}
public void reset() {
for (int i =0; i<alphabetArray.length; i++) {
if(alphabetArray[i]>=0){
alphabetArray[i]=0;
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i]);
}
}
}
public String toString() {
String s = "";
int max = alphabetArray[0];
int markCounter = 0;
for(int i =0; i<alphabetArray.length; i++) {
//finds the largest number of occurences for any letter in the string
if(alphabetArray[i] > max) {
max = alphabetArray[i];
}
}
for(int i =0; i<alphabetArray.length; i++) {
//trying to scale the rest of the characters down here
if(alphabetArray[i] > 0) {
markCounter = (alphabetArray[i] / max) * 60;
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i] + markCounter);
}
}
for (int i = 0; i < alphabetArray.length; i++) {
//prints the whole alphabet, total number of occurences for all chars
if(alphabetArray[i]>=0){
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i]);
}
}
return s;
}
}
There are many many problems with your code, but lets go one by one.
First of all, your print statement is simply misleading. Change it to
System.out.println(ch +" : "+alphabetArray[i] + " " + markCounter);
and you will see
d : 1 0
e : 1 0
h : 1 0
l : 3 60
o : 2 0
r : 1 0
w : 1 0
As you can see: the counters are correct (1,1,1,3,2,1,1). But the your scaling doesn't work:
1 / 3 --> 0 ... and 0 * 3 ... is still 0
3 / 3 --> 1 and 1 * 3 ... is 60
but of course, when you dont print a space between 1 and 0 and 3 and 60.
Thus to get correct scaling, just change to:
markCounter = alphabetArray[i] * 60 / max;
Other things worth mentioning:
You are overriding toString(). Then you should put #Override in fron t of that method
toLowerCase() returns a new string in lower case; just calling it without pushing the result back into your string ... just throws away the "lower casing".
toString() shouldnt print to the console. The whole idea is that you put all the information into the string that you return. In other words: in the end you do some System.out.println(someLetterCounter.toString()
Your code is extremely low-level. You don't iterate arrays using for (int), you can do (int letter : alphabetArray) instead
You might want to read about Map. You see, if you would be using a Map<Character, Integer> where the map key would represent the different characters, and the map value represents a counter for each character ... well, you could throw out most of your code; and come up with a solution that would require a few lines of code only!
( and seriously: because of all these issues, debugging your code was really much harder than it needed to be )
countLetters seems has some issues. You can not convert String to lowercase by just calling
this.input.toLowerCase();
Because String is immutable in java. You have to assign it like:
this.input = input.toLowerCase();
Another problem is you are using input variable from parameter instead of this.input which has lower case string. You can do this way to make work countLetters method:
public void countLetters(String input) {
this.input = input.toLowerCase();
for ( int i = 0; i < this.input.length(); i++ ) {
char ch= this.input.charAt(i);
if (ch >= 97 && ch <= 122) {
alphabetArray[ch-'a']++;
}
}
}

Why is my EA not moving my position to breakeven?

I'm attempting to modify my market orders to breakeven the position when the position get 100 pips to the good. This also accounts for the StopLevels which are around 20-30 pips for my broker. It checks the param's via a "for(){...} loop" function
The MagicNumber is the timeframe number for the chart it is on (i.e. 240=4H, 60=1H) I don't set a TakeProfit price & initially no StopLoss price.
The EA is not adding a SL to be equal to the opening price when the trade reaches 100 pip in profit (plus stoplevels). Profit points reaches well over 130 points.
My code is below for a OP_SELL order - any help would be appreciated. Regards, Todd
/*Global Declarations*/
double pnlPoints;
double price, sl, tp;
double point;
int stopLevel;
int breakeven;
double newSL;
/*Local Declaratons*/
pnlPoints = 0;
point = MarketInfo( Symbol(), MODE_POINT );
stopLevel = int( MarketInfo( Symbol(), MODE_STOPLEVEL )
+ MarketInfo( Symbol(), MODE_SPREAD )
);
sl = NormalizeDouble( OrderStopLoss(), Digits );
tp = OrderTakeProfit();
breakeven = 100;
for( int s = OrdersTotal() - 1; s >= 0; s-- )
{ if ( ( OrderSelect( s, SELECT_BY_POS, MODE_TRADES ) ) == true )
price = MarketInfo( Symbol(), MODE_ASK );
newSL = NormalizeDouble( OrderOpenPrice(), Digits );
pnlPoints = ( OrderOpenPrice() - price ) / point;
if ( OP_SELL == OrderType() )
if ( Period() == OrderMagicNumber() )
if ( stopLevel < ( newSL - price ) / point )
if ( breakeven < pnlPoints )
if ( newSL != sl )
ModSell = OrderModify( OrderTicket(),
OrderOpenPrice(),
newSL,
tp,
buycolor
);
else if ( ModBuy == false )
{ Print( "OrderModify failed with error #",
GetLastError()
);
}
}
For the moment being,refine the codeandadd self-debuging / tracing code
After OrderModify() use a self-debugging / journaling Print( StringFormat( ... ) ) to document all instructed values used in the actual OrderModify() call and also the remote-execution ( { server-side | StrategyTester } ) reported issues.
The current code does not enter into such self-diagnostics and ModSell is not inspected at all, ModBuy is inspected only at uncertain conditions / by-coincidence at some future visit of the for(){...} code-execution path to a part after newSL == sl ( and all above stated conditions are just by chance met too )
Next, check an assigned value of tp
As stated above,
/*Local Declarations*/
...
tp = OrderTakeProfit();
which introduces a reasonable doubt, that re-using of this ( inherently uncertain value, as no one knows, which OrderSelect() was the last one that set a db.Pool pointer to decide, from which record from the db.Pool this veryOrderTakeProfit() would accidentally read ( if any record is present in db.Pool already ) inside the whole for(){...} traversing the db.Pool records will not meet conditions for setting properly a TakeProfit price in the next series of OrderModify() calls.
This seems to be the root cause, or a source of unhandled exceptions to the valid, Broker-compliant, OrderModify() values.
Try this:
if (newSL != sl ) {
ModSell = OrderModify( OrderTicket(),
OrderOpenPrice(),
OrderOpenPrice(),
0,
OrderExpiration(),
clrRed
);
if(ModBuy == false )
Print( "OrderModify failed with error #", GetLastError());
}
Then check the Expert-tab for error-message if it fails to set the stop.
Also, you need to take note that StopLoss will ONLY occur if you are on the right chart-timeframe; Otherwise, it won't even get into the if-statements.

How to access the second if statement

I am totally drain out as the second if statement couldn't be executed.
My original idea was when volatility is in a range of 90 - 110, the program will send one and only one order. And it will wait and see till the volatility reaches in a range of 111 - 150, and then it will send the second order.
If I don't use a bool function here, the program will send countless order when the range is reached.
Could someone please help me?
if ( TodayMaxVolatilityPercentage >= 90.0
&& ( dayTrend == 1 )
&& orderOpened == false
)
{
Print( "Entered if clause" );
// Print( "Today volatility percentage is: ", TodayMaxVolatilityPercentage + "%" );
// ticket: Returns number of the ticket assigned to the order by the trade server or -1 if it fails.
ticket = OrderSend( Symbol(),
OP_SELL,
0.3,
Bid,
3,
0 * MyPoint,
30 * MyPoint,
NULL,
MagicNumber,
0,
Blue
);
Print( "Order is opened on", OrderOpenTime()+" at price: ", OrderOpenPrice() );
Print( "trend number is ",dayTrend );
if ( ticket > 0 )
{
if ( TakeProfit > 0 ) TheTakeProfit = Bid - TakeProfit * MyPoint;
OrderSelect( ticket, SELECT_BY_TICKET ); // bool value
/* OrderModify( OrderTicket(),
OrderOpenPrice(),
0,
NormalizeDouble( TheTakeProfit, Digits ),
0,
Green
);
*/
}
orderOpened = true;
if ( TodayMaxVolatilityPercentage >= 110.0 ) orderOpened = false;
}
if ( TodayMaxVolatilityPercentage >= 110.0
&& ( dayTrend == 1 )
&& orderOpened == false
)
{
Print( "Entered second if clause" );
// ticket: Returns number of the ticket assigned to the order by the trade server or -1 if it fails.
ticket = OrderSend( Symbol(),
OP_SELL,
0.3,
Bid,
3,
0 * MyPoint,
30 * MyPoint,
NULL,
MagicNumber,
0,
Blue
);
if ( ticket > 0 )
{
if ( TakeProfit > 0 ) TheTakeProfit = Bid - TakeProfit * MyPoint;
OrderSelect( ticket, SELECT_BY_TICKET ); // bool value
/* OrderModify( OrderTicket(),
OrderOpenPrice(),
0,
NormalizeDouble( TheTakeProfit, Digits ),
0,
Green
);
*/
}
orderOpened = true;
}
A hidden show-stopper:
By design, the first successful OrderSend() returns a value you assign into an ticket = OrderSend(...).
The devil is hidden in detail.
[MQL4-Help] says:
Returns number of the ticket assigned to the order by the trade server or -1 if it fails.
So the first successful OrderSend() ticket# returned is 0 ( in StrategyTester, a real MT4/Server rather runs into high numbers drawn from it's db.pool of tickets ).
Thus the second if ( ticket > 0 ) will never let you in.
It is common to rather use if ( ticket > EMPTY ) so as to also clarify the intention and use symbolic instead of a -1 integer constant.

Resources