I have an EA with closes a trade on button click
//void CloseCurrentTrade(). It's called after successfull OrderSelect
int orderType = OrderType();
double price;
if (orderType == OP_BUY)
price = return MarketInfo(OrderSymbol(), MODE_BID);
else if (orderType == OP_SELL)
price = return MarketInfo(OrderSymbol(), MODE_ASK);
else
return;
int slippage = 20;
bool closed = OrderClose(OrderTicket(), OrderLots(), price, slippage);
if (closed)
return;
int lastError = GetLastError();
Sometimes it closes the trade and sometimes it returns error #129 (Invalid price). I can't figure out why. Most of the cases people just misuse bid/ask or don't have enouth slippage. I've try to use slippage up to 200, still the same error. Some EA's just try to close it several times (and it looks like a hack for me), but it does not help as well. There are some mentions that you need to call RefreshRates() before bid/ask, but documentaion says that you don't need to do that for MarketInfo.
I've run out of ideas what it could be. Why it can happen and how to avoid that? I'm testing it on FXCM Demo (if it is the case).
First make sure that you've selected the order properly, and try to use OrderClosePrice where possible(this will eliminate the need for checking the OP_SELL/OP_BUY)
//+------------------------------------------------------------------+
//| Close the latest order for this current symbol |
//+------------------------------------------------------------------+
void CloseCurrentTrade()
{
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol()) continue;
if(OrderMagicNumber()!=MagicNum) continue; // if there is no magic number set, then no need for this(manual orders)
if(OrderType()>OP_SELL) continue;
if(!OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage))
Print("Error in Closing the Order, Error : ",ErrorDescription(GetLastError()));
break; // assuming you want to close the latest trade only, exit the order closing loop
}
}
Also note that your broker might have restrictions on how far the closing price must be from the Order Opened price and other levels(sl/tp), in order to close an order. Refer here
Print and compare Ask/Bid && price when closed!=true. Beware that MarketInfo mode data is stored at Ask/Bid predefined variables already, so you can eliminate that if you OrderSelect in current symbol.
Related
I'm trying to return the current profit on an open order based on the order comment.
Right now, my code below but is getting the profit of all open orders as opposed to just the order with a specific comment.
So, what I want to return is the profit for the order that the order comment is "Testing".
double Profit=0;
for(int i=0; i<OrdersTotal(); i++ )
{
if(OrderSelect(i, SELECT_BY_POS)==true)
{
if (OrderComment()=="Testing")
Profit+= (OrderProfit()+OrderSwap()+OrderCommission());
}
You should not use OrderComment() for isolating/identifying trades, the broker can overwrite/alter/delete the comments at any time for any reason.
You should also count orders down, not up. If an order is deleted or created mid check, your function will exit with an error or produce unexpected results.
All the above given, the following works when I've tested it.
double Profit=0;
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS))
{
if(OrderComment()=="Testing") Profit+= (OrderProfit()-OrderSwap()-OrderCommission());
}
}
Comment(Profit);
Will following code be executed atomically?
const int oldId = id.exchange((id.load()+1) % maxId);
Where id is std::atomic<int>, and maxId is some integer value.
I searched google and stackoverflow for std::atomic modulo increment. And I found some topics but I can't find clear answer how to do that properly.
In my case even better would be to use:
const int newId = id.exchange((++id) % maxId);
But I am still not sure if it will be executed atomically.
No, this is not atomic, because the load() and the exchange() are separate operations, and nothing is preventing id from getting updated after the load, but before the exchange. In that case your exchange would write a value that has been calculated based on a stale input, so you end up with a missed update.
You can implement a modulo increment using a simple compare_exchange loop:
int val = id.load();
int newVal = (val + 1) % maxId;
while (!id.compare_exchange_weak(val, newVal) {
newVal = (val + 1) % maxId;
}
If the compare_exchange fails it performs a reload and populates val with the updated value. So we can re-calculate newVal and try again.
Edit:
The whole point of the compare-exchange-loop is to handle the case that between the load and the compare-exchange somebody might change id. The idea is to:
load the current value of id
calculate the new value
update id with our own value if and only if the value currently stored in id is the same one as we read in 1. If this is the case we are done, otherwise we restart at 1.
compare_exchange is allows us to perform the comparison and the conditional update in one atomic operation. The first argument to compare_exchange is the expected value (the one we use in our comparison). This value is passed by reference. So when the comparison fails, compare_exchange automatically reloads the current value and updates the provided variable (in our case val).
And since Peter Cordes pointed out correctly that this can be done in a do-while loop to avoid the code duplication, here it is:
int val = id.load();
int newVal;
do {
newVal = (val + 1) % maxId;
} while (!id.compare_exchange_weak(val, newVal);
#property strict
int ticket;
void OnTick()
{
double AccountBal;
double MAfast = iMA(_Symbol,PERIOD_CURRENT,20,0,MODE_EMA,PRICE_CLOSE,0);
double MAslow = iMA(_Symbol,PERIOD_CURRENT,30,0,MODE_EMA,PRICE_CLOSE,0);
AccountBal = AccountBalance()/10000;
double Force = iForce(_Symbol,PERIOD_CURRENT,13,MODE_SMA,PRICE_CLOSE,0);
double rsi = iRSI(_Symbol,PERIOD_CURRENT,7,PRICE_CLOSE,0);
if((rsi> 70)&&(OrdersTotal()==0)&&(MAfast>MAslow)){
ticket = OrderSend(_Symbol,OP_BUY,AccountBal,Ask,10,Ask-0.007,Ask+0.007,"This iS Buy",33,0,clrBlue);
}
if((rsi <30)&&(OrdersTotal()==0)&&(MAslow>MAfast)){
ticket = OrderSend(_Symbol,OP_SELL,AccountBal,Bid,10,Bid+0.007,Bid-0.007,"This is a Sell",33,0,clrRed);
}
}
The code works and everything is great but when a order is open like a buy order, even if the the conditions are true for sell order it wont place the order until the open one hits take profit or stop loss, the Orders Total function is screwing me over is there anyway I can replace it?
Unfortunately I am not able to post the code I am debugging as it is not mine and I am bound not to show it... BUT I will describe it as detailed as possible.
There are 4 strategies base on 4 indicators, custom, and not-custom ones. So basically instead of 4 different EAs running in 4 different charts with the same 4 indicators each... The client asked me to optimise them by putting them all in one to run 4 into 1 EAs in the same chart.
EVERYTHING is the same. They are tested as well that they are the same. They open the same trades, on the same moments. Nothing is changed 100%. The only thing I did (for this part of the debugging, because obviously I had a lot more to do before that) is to copy functions and code. And I seperated all different strategies with an "if" as input
input bool strategy1enabled = true; etc... so he/she can disable/enable individual strategies if wanted.
everything works BUT....
All but 1 strategies, does not show the Comment on the trades.
All 4 use the same Buy/Sell/CloseOrder functions so I just input the values to keep the code shorter.
//---
bool OrdClose (int ticket_number, double lt, int slp)
{
return OrderClose(ticket_number,lt,iClose(NULL,0,0),slp,clrViolet);
}
//---
int Buy(double lt, int slp, int slss, int tpft, string cmt, int mgc)
{
return OrderSend(NULL,OP_BUY,lt,Ask,slp,Ask-slss*Point,Ask+tpft*Point,cmt,mgc,0,clrDarkBlue);
}
//---
int Sell(double lt, int slp, int slss, int tpft, string cmt, int mgc)
{
return OrderSend(NULL,OP_SELL,lt,Bid,slp,Bid+slss*Point,Bid-tpft*Point,cmt,mgc,0,clrDarkRed);
}
1 strategy just refuses to put comment. Any ideas why? When used seperated WITH THE SAME CODE and the EXACT SAME functions... comment shows...
EDIT:
2021.05.04 18:30:48.670 The_Big_Holla_v1_8_EA CADJPY,H1: open #85710545 buy 0.06 CADJPY at 88.755 sl: 88.655 tp: 88.955 ok
2021.05.04 18:30:48.462 The_Big_Holla_v1_8_EA CADJPY,H1: Holla v4.9 || GreedInjectionMode
2021.05.04 18:30:48.462 The_Big_Holla_v1_8_EA CADJPY,H1: Holla v4.9 || GreedInjectionMode
Comment is passed properly and checked before being passed to function and before OrderSend within function:
The function:
int Sell(double lt, int slp, int slss, int tpft, string cmt, int mgc)
{
Print(cmt);
return OrderSend(NULL,OP_SELL,lt,Bid,slp,Bid+slss*Point,Bidtpft*Point,cmt,mgc,0,clrDarkRed);
}
How the function is called:
Print(EACommentInj);
ticket_val_inj = Buy(lotsizeInj,slippageInj,stoplossInj,takeprofitInj,EACommentInj,MagicInj);
This is how it is initialised and it NEVER changes. It is mentioned only where it is passed. Where I showed you above.
const string EACommentInjGreed = "Holla v4.9 || GreedInjectionMode Greed Mode";
Although this is undocumented, the "string comment=NULL" parameter of the trade function OrderSend() in MQL4 is limited to 31 characters. If this limit is exceeded then the string is rejected as a whole and treated as NULL.
In your code, just before the OrderSend() function, add the following line:
cmt=StringSubstr(cmt,0,31);
I'm trying to modify an Order, but I always get Error #1.
From my research, I have discovered that error 1 means I have input parameter in a wrong way. How can I fix my OrderModify() function?
stoploss = NormalizeDouble(Ask - Point * TrailingStop,Digits);
int ticket;
takeprofit = NormalizeDouble(Ask + Point * TrailingStopTP,Digits);
double minstoplevel = MarketInfo( Symbol(), MODE_STOPLEVEL );
if(stoploss > NormalizeDouble(Ask - Point*minstoplevel,Digits)) {
stoploss = NormalizeDouble(Ask - Point*minstoplevel,Digits);
}
if(takeprofit < NormalizeDouble( Ask + Point*minstoplevel2, Digits )) {
takeprofit = NormalizeDouble( Ask + Point*minstoplevel2, Digits );
}
if(AccountFreeMarginCheck(Symbol(),OP_SELL,lotsize)>0) {
ticket=OrderSend(Symbol(),OP_BUY,lotsize,Ask, 0, 0.0, 0.0, "comment", MagicNumber, 0, Lime);
if(ticket<0) {
Print("Order send failed with error #",GetLastError());
} else {
Print("Order send sucesso!! Ticket#", ticket);
res=OrderModify(ticket,OrderOpenPrice(),stoploss,takeprofit,0,Blue);
if(res==false) {
Print("Error modifying order!, error#",GetLastError());
} else {
Print("Order modified successfully, res#", res);
}
}
} else {
Print("Sem dinheiro na conta D=");
}
}
Not exactly "wrong", OrderModify() legally sets _LastError == 1
There might be a bit surprise, but OrderModify() has an obligation to signal _LastError == 1 in case, the call was both syntactically and semantically correct, however, the values supplied for modification(s) were actually the very same, as the identified ticket# has already had in database.
This means, there was nothing to modify, as all the attributes already had the "quasi-new" target value(s).
One may pre-check all fields for a potential identity, which might allow our code to skip the OrderModify() call in this very case of an identity-of-{ current | target } values.
ERR_NO_RESULT == 1 // No error returned, but the result is unknown
GetLastError() - returns a last generated error-code. The same value is available via a system variable named _LastError. It's value can be reset before a critical activity to zero by calling ResetLastError().
Error codes are defined in stderror.mqh.
To print the error description you can use the ErrorDescription() function, defined in stdlib.mqh file
#include <stderror.mqh>
#include <stdlib.mqh>
The problem is that even though the entry price, stoploss, and take profit parameters to the OrderModify() call appear to be the same, they likely differ by a fraction of a unit ( smaller than "Digits" ).
To fix this,simply normalize the parameters to make sure they are a maximum of Digits decimal places long.
double entryPrice = NormalizeDouble( entryPrice, Digits );
double stoploss = NormalizeDouble( stoploss, Digits );
double target = NormalizeDouble( target, Digits );
Then pass them into the OrderModify() call.