EA closes every trade on the new candle (unintended) MQL4

 

Hi guys; I've been coding for years, and playing in stocks/forex a long while besides... fairly new to MQL4, however.

I've made several EA's successfully and have a pit of a workflow going now for all my ideas, which is nice. However, I've run into an issue that I can't get to the bottom of;

When I run this EA in backtesting it works perfectly, but on live accounts, not so...

intended:
Open multiple trades in a trend direction; close al trades when the end of the trend is detected (checks once per candle close)

actual:
closes all trades on the candle change, reopens all trades that were previously open - as opposed to just 'holding' them.

Here's some snippets with the guts pulled out; call me greedy but i've been working on my ssytem for years and I dont want to share it because;
1. it represents 7 years of work
2. i dont want some kid to just take that work in it's entirety for 'free'
3. i dont' want to give out 'any' complete script to someone who hasn't 'earned' it by making the effort to learn to code it themselves.

//+------------------------------------------------------------------+
//|                                                      HA_Trader.mq4|
//|                        Dual Heikin Ashi Signals                  |
//+------------------------------------------------------------------+
#property strict

input int len = 30;       // Length for first EMAs
input int len2 = 1;       // Length for second EMAs

double haOpen1[], haClose1[], haHigh1[], haLow1[];
double haOpen2[], haClose2[], haHigh2[], haLow2[];
datetime lastCalcTime = 0;
double prevTradeOpenPrice = 0;


input int atrPeriod = 14; // ATR period for stop loss
input double atrMultiplier = 2.0; // Multiplier for ATR
input double InitialTargetPercentPerTrade = 0.01; // Target loss in dollars
input double takeProfitMultiplier = 1.3; // Multiplier for take profit
bool trendDirection = true; // Initialize as true for buy
double InitialTargetLoss = (AccountBalance()) * (InitialTargetPercentPerTrade / 100);

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{

// sets arrays.....

    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Calculate Heikin Ashi values for both sets                       |
//+------------------------------------------------------------------+
void CalculateHeikinAshi()

(sipmly calcs the HA) then add another thing to it
    }
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{

InitialTargetLoss = (AccountBalance()) * (InitialTargetPercentPerTrade / 100);
InitialTargetLoss = NormalizeDouble(InitialTargetLoss, 2);


//+------------------------------------------------------------------+
//| check to run once per candle                                     |
//+------------------------------------------------------------------+

datetime currentTime = iTime(NULL, 0, 0);
if (currentTime == lastCalcTime) return;
lastCalcTime = currentTime;


  ()
    
//------------------------------------------------------------------------------
//  perform math to see if trend has changed directons
//------------------------------------------------------------------------------

(calc o2 and c2)

    static double prevO2 = 0, prevC2 = 0;
    bool bullishCrossover = (prevO2 >= prevC2) && (o2 < c2);
    bool bearishCrossover = (prevO2 <= prevC2) && (o2 > c2);


          //-----------------------------------------------------------------
          //perform bullish or bearish actions: NOTE this occurs only once at the crossover - this could be part of the issue
          //-----------------------------------------------------------------

if (bullishCrossover) {
    DrawVerticalLine("BullLine" + TimeToString(TimeCurrent()), TimeCurrent(), clrGreen); //I had to invert these
     trendDirection = true;
     CloseAllTrades();
}
 else if (bearishCrossover) {
    DrawVerticalLine("BearLine" + TimeToString(TimeCurrent()), TimeCurrent(), clrRed); //I had to invert these
      trendDirection = false;
      CloseAllTrades();
}

    prevO2 = o2;
    prevC2 = c2;



//------------------------------------------------------------------------------
//   should be all set; now we open a trade
//------------------------------------------------------------------------------


(simply calcs the trade based on some parameters and opens based on trend direction)
    

}
}

______________________

}

bool NewCandle() {
    static datetime lastTime = 0;
    datetime currentTime = Time[0];
    if (currentTime != lastTime) {
        lastTime = currentTime;
        return true;
    }
    return false;
}

//------------------------------------------------------------------------------
// function to open a trade
//------------------------------------------------------------------------------
void OpenTrade(double atr, double spread) {
     double stopLoss = MathAbs(prevTradeOpenPrice-Open[0]) + spread;
    double price = !trendDirection ? Ask : Bid;
    double slPrice = !trendDirection ? price - stopLoss : price + stopLoss; // Adjust stop loss based on trade direction



    if (trendDirection) {
        // Buy order
        int ticket = OrderSend(Symbol(), OP_SELL, CalculateLotSize(OP_SELL, slPrice, InitialTargetLoss), price, 3, 0 , 0, "", 0, 0, clrRed);
        if (ticket < 0) {
            Print("OrderSend failed: ", GetLastError());
        }
    } else {
        // Sell order
        int ticket = OrderSend(Symbol(), OP_BUY, CalculateLotSize(OP_BUY, slPrice, InitialTargetLoss), price, 3, 0 , 0, "", 0, 0, clrBlue);
        if (ticket < 0) {
            Print("OrderSend failed: ", GetLastError());
        }
    }
        prevTradeOpenPrice = price;
}
//+------------------------------------------------------------------+
//| Calculate Lot Size                                               |
//+------------------------------------------------------------------+
double CalculateLotSize(int tradeType, double stopLoss, double targetLoss)
  {
merely a function to calculate lotsizes dynamially per trade
  }

                  //+------------------------------------------------------------------+
                  //| Draw vertical lines for signals                                  |
                  //+------------------------------------------------------------------+
{codesnip merely draws vertical lines to denote logic changes graphically}

//------------------------------------------------------------------------------
// Close all open trades
//------------------------------------------------------------------------------

void CloseAllTrades() {
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        if (OrderSelect(i, SELECT_BY_POS) && OrderType() <= OP_SELL) {
            OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrRed);
        }
    }
}





hmm..
ok I just noticed that I'm checking the candle time twice.....

 
  1. Why did you post your MT4 question in the MT5 General section instead of the MQL4 section, (bottom of the Root page)?
              General rules and best pratices of the Forum. - General - MQL5 programming forum? (2017)
    Next time, post in the correct place. I have moved this thread.

  2. InitialTargetLoss = (AccountBalance()) * (InitialTargetPercentPerTrade / 100);
    InitialTargetLoss = NormalizeDouble(InitialTargetLoss, 2);
    

    Risk depends on your initial stop loss, lot size, and the value of the symbol. It does not depend on margin or leverage. No SL means you have infinite risk (on leveraged symbols). Never risk more than a small percentage of your trading funds, certainly less than 2% per trade, 6% account total.

    1. You place the stop where it needs to be — where the reason for the trade is no longer valid. E.g. trading a support bounce, the stop goes below the support. Then you compute your lot size.

    2. AccountBalance * percent/100 = RISK = OrderLots * (|OrderOpenPrice - OrderStopLoss| * DeltaPerLot + CommissionPerLot) (Note OOP-OSL includes the spread, and DeltaPerLot is usually around $10/PIP, but it takes account of the exchange rates of the pair vs. your account currency.)

    3. Do NOT use TickValue by itself - DeltaPerLot and verify that MODE_TICKVALUE is returning a value in your deposit currency, as promised by the documentation, or whether it is returning a value in the instrument's base currency.
                MODE_TICKVALUE is not reliable on non-fx instruments with many brokers - MQL4 programming forum (2017)
                Is there an universal solution for Tick value? - Currency Pairs - General - MQL5 programming forum (2018)
                Lot value calculation off by a factor of 100 - MQL5 programming forum (2019)

    4. You must normalize lots properly and check against min and max.

    5. You must also check Free Margin to avoid stop out

    6. For MT5, see 'Money Fixed Risk' - MQL5 Code Base (2017)

    Most pairs are worth about $10 per PIP. A $5 risk with a (very small) 5 PIP SL is $5/$10/5 or 0.1 Lots maximum.

  3.   ()
        
    //------------------------------------------------------------------------------
    //  perform math to see if trend has changed directons
    //------------------------------------------------------------------------------
    
    (calc o2 and c2)

    Does that actually compile? Post your actual code.

  4.    double slPrice = !trendDirection ? price - stopLoss : price + stopLoss; // Adjust stop loss based on trade direction
    

    You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit by the Ask.

    1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

    2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close at a specific Bid price, add the average spread.
                MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

    3. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)

      Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes.
      My GBPJPY shows average spread = 26 points, average maximum spread = 134.
      My EURCHF shows average spread = 18 points, average maximum spread = 106.
      (your broker will be similar).
                Is it reasonable to have such a huge spreads (20 PIP spreads) in EURCHF? - General - MQL5 programming forum (2022)

 
William Roeder #:
  1. Why did you post your MT4 question in the MT5 General section instead of the MQL4 section, (bottom of the Root page)?
              General rules and best pratices of the Forum. - General - MQL5 programming forum? (2017)
    Next time, post in the correct place. I have moved this thread.

  2. Risk depends on your initial stop loss, lot size, and the value of the symbol. It does not depend on margin or leverage. No SL means you have infinite risk (on leveraged symbols). Never risk more than a small percentage of your trading funds, certainly less than 2% per trade, 6% account total.

    1. You place the stop where it needs to be — where the reason for the trade is no longer valid. E.g. trading a support bounce, the stop goes below the support. Then you compute your lot size.

    2. AccountBalance * percent/100 = RISK = OrderLots * (|OrderOpenPrice - OrderStopLoss| * DeltaPerLot + CommissionPerLot) (Note OOP-OSL includes the spread, and DeltaPerLot is usually around $10/PIP, but it takes account of the exchange rates of the pair vs. your account currency.)

    3. Do NOT use TickValue by itself - DeltaPerLot and verify that MODE_TICKVALUE is returning a value in your deposit currency, as promised by the documentation, or whether it is returning a value in the instrument's base currency.
                MODE_TICKVALUE is not reliable on non-fx instruments with many brokers - MQL4 programming forum (2017)
                Is there an universal solution for Tick value? - Currency Pairs - General - MQL5 programming forum (2018)
                Lot value calculation off by a factor of 100 - MQL5 programming forum (2019)

    4. You must normalize lots properly and check against min and max.

    5. You must also check Free Margin to avoid stop out

    6. For MT5, see 'Money Fixed Risk' - MQL5 Code Base (2017)

    Most pairs are worth about $10 per PIP. A $5 risk with a (very small) 5 PIP SL is $5/$10/5 or 0.1 Lots maximum.

  3. Does that actually compile? Post your actual code.

  4. You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit by the Ask.

    1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

    2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close at a specific Bid price, add the average spread.
                MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

    3. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)

      Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes.
      My GBPJPY shows average spread = 26 points, average maximum spread = 134.
      My EURCHF shows average spread = 18 points, average maximum spread = 106.
      (your broker will be similar).
                Is it reasonable to have such a huge spreads (20 PIP spreads) in EURCHF? - General - MQL5 programming forum (2022)

OK wow; thanks for going through it;
First can I just preface by saying that i genuinely appreciate your time (and knowledge) in going thru this and i mean no disrespect or attitude at any point; I have a lot to reply to here and if I seem arrogant then apologies - I kinda am IRL but i appreciate that you're coming from a place of wanting to help and I mean no disrespect here. I'm not disrespectful IRL eihter it's just that... internet things and meaning/tone can go awry without body language, vocal modulation, etc.

I wish I could figure out how to quote inline; maybe I'm just a muppet, maybe the forum tools haven't been updated since 1993.



#1 -
I posted int the wrong forum; i've been around a while, but not active at all so 'basically new' to the forum forgive me for the oversight but i didnt' see that there was a separate mql4 forum; call m noob or ijit or whatever but it wasn't clear and obvious to me - in fact I SEARCHED for mql4 and it still didnt' really pop up.... thus i added the mql4 disclaimer in the title. Thanks for moving it, though and I'll try to keep my **** together next time; learning by increments; please forgive my transgression.



#2
I basically do all that in the calculatelotprice() which is LARGELY snipped.
to call that vairable slPrice would be erroneous TBH - it's more like a 'starting point in relation to other trades to make calculations at a later time'. I 'call' it SL because I used to drag an SL line to that zone by eye then calculate it all based on that; but it's not 'really' a stoploss - so I can see the concern/confusion there.


#3
no that won't compile. I've snipped a hundred lines of code.


#4
buy sell at ask/bid. I know; I handle it like this

void OpenTrade(double atr, double spread) {
     double stopLoss = MathAbs(prevTradeOpenPrice-Open[0]) + spread;
    double price = !trendDirection ? Ask : Bid;
    double slPrice = !trendDirection ? price - stopLoss : price + stopLoss; // Adjust stop loss based on trade direction


Hopefully this helps a little; i 'think' i have a resemblance of competence, I share his added code so that hopefull we can share that we are mostly on the same page here;

Regarding this:

  • Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

  • Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close at a specific Bid price, add the average spread.
              MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

yeah, nah. I trigger based on a series of market conditions, not on discrete  SL/TP's.



___
The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)

Yep I discovered that one straight away - I learned that trick from TradingView and it was among the first changes I made when getting into MT4 (my broker uses MT4 therefore I do)

___
Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes.
Yep there is a check that holds placing trades if (spread > 1/2 * iATR(somecode);)




_____
Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?
--> first of all, I'm not using the limit system, I'm just opening the trade at market price. I use "(Ask ? Bid) + n" to get the numbers that I want; it's finely attuned and checked/balanced in my snipped code; but good catch. I also have hard limit catchalls set in my broker account that act as hard SL's if things go really badly against me; but in 7 years I've never hit those limits once. That might help explain why I don't expressly limit them in code. No, I don't want the specified amount in eihter direction; it's a check that's calculated relative to the previous trade to keep each trade relative to another - it's a complex system that's snipped - I do not have my SL/TP at a specified amount, and the setup is designed to allow my to make 10-100 R returns per run. some will win, some will lose, but the win runs are longer than the losing runs so i win on the trend overall. TLDR; its intentional

I'll check this; but pretty sure you'll find it's intentional.



Thanks for the trading advice; I'm familiar with it.... and there's a reason why most traders fail. here's a concept that I build my core  systems by; if most traders fail and most traders do a thing; do the other thing. whether you agree or disagree is fine, but yes I understand, and yes that is intentional. You clearly understand the code and what I'm doing, which is awesome; there are added checks and balances further down to mitigate that are.... snipped.... my trading system is not in question and not really up for debate - but i do APPRECIATE that you see it and have thought to bring it to my attention. - translating it into mql4 is the question - specifically 'why does it close trades and re-open them?' in saying that you did ask some stuff, hopefully i've answered most of it.

If code looks like it doesnt compile that's because it's snipped, and snipped HARD. The full script is hundreds of lines.

I just wanted to know if there was a valid reason for it to work in backtest (every tick) but have a different behaviour in Live/Demo.

The key to this script is that it has no TP/SL, opens multiple trades at a time, and closes them all when a certain market conditions are met via

void CloseAllTrade()
<code here>

The issue is that it closes/reopens them every hour (candle) instead of holding them until close is triggered;


The only time that CloseAllTrades() is called is here:

    static double prevO2 = 0, prevC2 = 0;
    bool bullishCrossover = (prevO2 >= prevC2) && (o2 < c2);
    bool bearishCrossover = (prevO2 <= prevC2) && (o2 > c2);


          //-----------------------------------------------------------------
          //perform bullish or bearish actions: NOTE this occurs only once at the crossover
          //-----------------------------------------------------------------

if (bullishCrossover) {
    DrawVerticalLine("BullLine" + TimeToString(TimeCurrent()), TimeCurrent(), clrGreen); //I had to invert these
     trendDirection = true;
     CloseAllTrades();
}
 else if (bearishCrossover) {
    DrawVerticalLine("BearLine" + TimeToString(TimeCurrent()), TimeCurrent(), clrRed); //I had to invert these
      trendDirection = false;
      CloseAllTrades();
}




again it works in backtest but not IRL. why, man; why?


  • I've been working on this for MONTHS as it's my first script and foray into MQL4. I've overcome so much on my own - learning, bugtesting, reiterating, reading up documentation..... I CANNOT find any reason why this would close early, unless it's something 'else' that I dont knwo about (first real script with mt4). I'd wondered if it might happen if there was a momentary internet outatge; if that would stop my EA from tracking the orders /whatever and 'reset' - thus closing everything on it's "first" run every hour.
  • I added the vertical green/red line to verify this wasn't the issue.
  • I dont know now I'm so close, i'm so tired, and I'm so stumped.
 
well, update;
After my original post where I noticedthat I seem to have two separate calculations that check the time; I removed one of those and tested again for a couple of hours, and now it seems to be working as expected on live accounts. In this particular moment I don't know why it works exactly, but it does; so now all I have to do is spend the time to figure out why the logic didn't work. I understand that it added something somewhere that causes an issue, but I'm not sure how or what exactly or where it failed, especially considering the fact that it actually worked in the "back testing" phase.

I'll be running it for the next few hours to make sure that the results are consistent, until then if anyone has some insights on this then I'd love to hear it, otherwise I suppose that we can consider this thread "potentially solved" for now.
Again, thanks to William Roeder for engaging with me.
EA closes every trade on the new candle (unintended) MQL4
EA closes every trade on the new candle (unintended) MQL4
  • 2024.07.02
  • hotmatrixx
  • www.mql5.com
Hi guys; I've been coding for years, and playing in stocks/forex a long while besides... fairly new to MQL4, however...
 
OK I solved it;
For anyone reading this far; I closed all trades like this:

---
// Close all open trades
//------------------------------------------------------------------------------

void CloseAllTrades() {
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        if (OrderSelect(i, SELECT_BY_POS) && OrderType() <= OP_SELL) {
            OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrRed);
        }
    }
}
BUT what I haven't mentioned, is that I would run this EA on multiple currencies simultaniously; and ANY ONE of my EA's closing it's trades, woudl close every trade for every EA.

So, the fix in my case is either for each EA to identify and close it's own currency pair, or to use Magic Numbers; I'm going wtih the Magic Numbers Route - I haven't done it yet; but I'm envisioning using a date/time with formatting stripped out for my MN's to ensure that every EA i start has a unique number, without having to hardcode multiple instances.


somethign like:
int MagicNumber;

int OnInit() {
    // Get the current date and time
    datetime now = TimeLocal();
    
    // Format the date and time to a unique MagicNumber
    string timeString = TimeToStr(now, TIME_DATE | TIME_MINUTES | TIME_SECONDS);
    // Remove non-numeric characters
    timeString = StringReplace(timeString, ".", "");
    timeString = StringReplace(timeString, ":", "");
    timeString = StringReplace(timeString, " ", "");
    
    // Convert the formatted string to an integer
    MagicNumber = StringToInteger(timeString);
    
    // Print the MagicNumber for verification
    Print("MagicNumber assigned: ", MagicNumber);

    return INIT_SUCCEEDED;
}

// Your existing CloseAllTrades function
void CloseAllTrades() {
    string currentSymbol = Symbol();
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        if (OrderSelect(i, SELECT_BY_POS) && OrderType() <= OP_SELL && OrderSymbol() == currentSymbol && OrderMagicNumber() == MagicNumber) {
            OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrRed);
        }
    }
}
***havent tested this, don't care to yet

anyway, thanks for stopping by!