Trade only the candle after histogram changes

 

Hi!

I have a histogram and I only want to trade the signal on candle close, or next candles open. I tried to capture the previous histogram value, hoping that the EA would only place a buy order as soon as it switched but it did not work and provided weird behavior.

I'm really lost here, attatched is a picture showing the behavior i want - only place a trade on the opening candle after the signal/histogram change

//+------------------------------------------------------------------+
//|                                                        danv6.mq4 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property strict
 int nolongs =0;
 int noshorts = 0;
  int waitU =0;
 int waitD = 0;
 input int smoothing = 3;
 input ENUM_MA_METHOD smoothingmethod = MODE_LWMA;
 input double vol_thresh = 1.5;
  input int period1 = 5;
   input int period2 = 8;
    input int period3 = 20;
 double input tpmult =1;
 double input slmult =1;
int ticket1;
int ticket2;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
static datetime candletime;
   if(Time[0]==candletime)
   return;

double atr = iATR(NULL, 0, 14, 1);

 
double stopLoss = (int)(atr * slmult / Point);
double takeProfit = (int)(atr * tpmult / Point);

double lotSize = calculateLotSize(stopLoss)/2;
double StopPriceB = Ask-(stopLoss*Point);
double TakeProfitPriceB = Ask+(takeProfit*Point);
double StopPriceS = Bid+(stopLoss*Point);
double TakeProfitPriceS = Bid-(takeProfit*Point);
  
double Spread;
   if (StringFind(Symbol(), "JPY") >= 0) {
      Spread = (Ask-Bid)*100;
   } else {
      Spread = (Ask-Bid)*10000;
   }


   //demo
   double vqu = iCustom(Symbol(),Period(),"vqhisto",smoothing,smoothingmethod,0,0);
   double vqd = iCustom(Symbol(),Period(),"vqhisto",smoothing,smoothingmethod,1,0);
   
   double vquPrev = iCustom(Symbol(),Period(),"vqhisto",smoothing,smoothingmethod,0,1);
   double vqdPrev = iCustom(Symbol(),Period(),"vqhisto",smoothing,smoothingmethod,1,1);
   
   double vold = iCustom(Symbol(),Period(),"damiani_volatmeter",7,50,vol_thresh,0,0);
   double volu = iCustom(Symbol(),Period(),"damiani_volatmeter",7,50,vol_thresh,2,0);
   double c2u = iCustom(Symbol(),Period(),"BraidFilter",50,1,period1,period2,period3,0,0);
   double c2d = iCustom(Symbol(),Period(),"BraidFilter",50,1,period1,period2,period3,1,0);
   
    //if one thing does not agree, dont take the trade and wait for next signal in opposite direction from vqu
    //maby we can just look at what happened last candle and only trade if the last candle was opposite to current?

   
   bool buyCondition    = vqu!=EMPTY_VALUE && c2u>c2d && volu>vold && (vqdPrev!=EMPTY_VALUE)   ;
   bool sellCondition   = vqd!=EMPTY_VALUE && c2d>c2u && volu>vold && (vquPrev!=EMPTY_VALUE)  ;
   bool exitbuy= (vqd!=EMPTY_VALUE || c2d>c2u);
   bool exitshort       = (vqu!=EMPTY_VALUE && c2u>c2d);  


   if(exitbuy)
   {
      CloseBuyPositions();
      nolongs = 0;
   }
   if(exitshort)
   {
   CloseSellPositions();
   noshorts=0;
   }

        
        if(buyCondition && nolongs==0 ){
      CloseSellPositions();
      nolongs = 1;
      noshorts =0;
      waitD=0;
           ticket1=OrderSend(_Symbol,OP_BUY, lotSize, Ask,1000, StopPriceB, TakeProfitPriceB, "long",1,0,clrWhite);
           ticket2=OrderSend(_Symbol,OP_BUY, lotSize, Ask,1000, StopPriceB, 0, "long",1,0,clrWhite);
        }
        else if (sellCondition && noshorts ==0 ){
      CloseBuyPositions();
      noshorts =1;
      nolongs = 0;
           ticket1=OrderSend(_Symbol,OP_SELL, lotSize, Bid,1000, StopPriceS, TakeProfitPriceS, "short",1,0,clrRed);
           ticket2=OrderSend(_Symbol,OP_SELL, lotSize, Bid,1000, StopPriceS, 0, "short",1,0,clrRed);
        }
    OrderSelect(ticket1,SELECT_BY_TICKET);
   if((OrderClosePrice() !=0)&& OrdersTotal()==1)
   {
     OrderModify(ticket2,OrderOpenPrice(),OrderOpenPrice(),0,0,clrLime);
   }
   candletime=Time[0];
  }
//+------------------------------------------------------------------+
double calculateLotSize(int stopLoss)
{
    // 1% risk per trade
    double risk = 2;
     
    // Fetch some symbol properties
    double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
    double minLot  = MarketInfo(Symbol(), MODE_MINLOT); 
    double maxLot  = MarketInfo(Symbol(), MODE_MAXLOT);
    double tickVal = MarketInfo(Symbol(), MODE_TICKVALUE);
 
    // Calculate the actual lot size
    double lotSize = AccountBalance() * risk / 100 / (stopLoss * tickVal);
 
    return MathMin(
        maxLot,
        MathMax(
            minLot,
            NormalizeDouble(lotSize / lotStep, 0) * lotStep // This rounds the lotSize to the nearest lotstep interval
        )
    ); 
}
void CloseSellPositions()
{
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      string CurrencyPair=OrderSymbol();
      if(_Symbol== CurrencyPair){
      if(OrderType()== OP_SELL)
         {
         OrderClose(OrderTicket(),OrderLots(),Ask, 1000, NULL);
         }
      }
   }
}

void CloseBuyPositions()
{
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      string CurrencyPair=OrderSymbol();
      if(_Symbol== CurrencyPair){
      if (OrderType()== OP_BUY)
         {
            OrderClose(OrderTicket(),OrderLots(),Bid, 1000, NULL);
         }
      }
   }
}

void breakeven()
{
   
}
 
Here is a picture of how I imagine the buy logic to be. Only make an order on new signals and when the other conditions are met (line 85-86)
 
  1.  int nolongs =0;
    ⋮
    void OnTick()
      {
         ⋮
         if(buyCondition && nolongs==0 ){

    EAs must be coded to recover. If the power fails, OS crashes, terminal or chart is accidentally closed, on the next tick, any static/global ticket variables will have been lost. You will have an open order but don't know it, so the EA will never try to close it, trail SL, etc. How are you going to recover?

    Use a OrderSelect / Position select loop on the first tick to recover, or persistent storage (GV+flush or files) of ticket numbers required.

  2. double StopPriceB       = Ask-(stopLoss*Point);
    double TakeProfitPriceB = Ask+(takeProfit*Point);

    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 to 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, but average maximum spread = 134 (your broker will be similar).

  3. Daniel Smith: I have a histogram and I only want to trade the signal on candle close, or next candles open. I tried to capture the previous histogram value, hoping that the EA would only place a buy order as soon as it switched but it did not work and provided weird behavior.

    You never know when a candle closes, only when the next opens.

  4. Stop looking at the current candle, your change is candle one vs. two.
 
William Roeder #:
  1. EAs must be coded to recover. If the power fails, OS crashes, terminal or chart is accidentally closed, on the next tick, any static/global ticket variables will have been lost. You will have an open order but don't know it, so the EA will never try to close it, trail SL, etc. How are you going to recover?

    Use a OrderSelect / Position select loop on the first tick to recover, or persistent storage (GV+flush or files) of ticket numbers required.

  2. 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 to 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, but average maximum spread = 134 (your broker will be similar).

  3. You never know when a candle closes, only when the next opens.

  4. Stop looking at the current candle, your change is candle one vs. two.

Hi! Thank you for the advice.


For number 1, can I just put some logic to look for open orders and positions in the onInit function? Is this what magic numbers are for? And for number 4, does this mean my shifts in iCustom() should be 1 and 2, instead of 0 and 1?


I am still a bit confused on what you mean in number 2, seems I got bid and ask mixed up. Should be like this right?

double StopPriceB       = Bid-(stopLoss*Point);
double TakeProfitPriceB = Bid+(takeProfit*Point);
 

Daniel Smith #:

For number 1, can I just put some logic to look for open orders and positions in the onInit function? Is this what magic numbers are for?

And for number 4, does this mean my shifts in iCustom() should be 1 and 2, instead of 0 and 1?

I am still a bit confused on what you mean in number 2, seems I got bid and ask mixed up. Should be like this right?

  1. No. Don't try to use any price (or indicator) or server related functions in OnInit (or on load or in OnTimer before you've received a tick), as there may be no connection/chart yet:
    1. Terminal starts.
    2. Indicators/EAs are loaded. Static and globally declared variables are initialized. (Do not depend on a specific order.)
    3. OnInit is called.
    4. For indicators OnCalculate is called with any existing history.
    5. Human may have to enter password, connection to server begins.
    6. New history is received, OnCalculate called again.
    7. A new tick is received, OnCalculate/OnTick is called. Now TickValue, TimeCurrent, account information and prices are valid.
  2. Yes.
  3. Yes, for the buy.
 
Ok I got it! Even the recovery feature, all seems to working normally except that it only opens one order at a time. Its supposed to open two, and move the other at breakeven after the other hits tp.
if(buyCondition && nolongs==0 ){
      CloseSellPositions();
      nolongs = 1;
      noshorts =0;
      waitD=0;
           ticket1=OrderSend(_Symbol,OP_BUY, lotSize, Ask,1000, StopPriceB, TakeProfitPriceB, "long",1,0,clrWhite);
           ticket2=OrderSend(_Symbol,OP_BUY, lotSize, Ask,1000, StopPriceB, 0, "long",1,0,clrWhite);
        }
        else if (sellCondition && noshorts ==0 ){
      CloseBuyPositions();
      noshorts =1;
      nolongs = 0;
           ticket1=OrderSend(_Symbol,OP_SELL, lotSize, Bid,1000, StopPriceS, TakeProfitPriceS, "short",1,0,clrRed);
           ticket2=OrderSend(_Symbol,OP_SELL, lotSize, Bid,1000, StopPriceS, 0, "short",1,0,clrRed);
        }
    OrderSelect(ticket1,SELECT_BY_TICKET);
   if((OrderClosePrice() !=0)&& OrdersTotal()==1)
   {
     OrderModify(ticket2,OrderOpenPrice(),OrderOpenPrice(),0,0,clrLime);
   }
   candletime=Time[0];
  }

de now. 
 
Daniel Smith # except that it only opens one order at a time. Its supposed to open two,

Probably because your broker's implementation of FIFO rules.

Since 2009, hedging is not permitted for US traders.
          NFA Enforces FIFO Rule, Bans Forex Hedging in US Forex Accounts - Trading Heroes (2016)
          FAQ: FIFO in the Forex Market - BabyPips.com (2011)

I suggest only opening one order, no TP. and do a partial close when reached.

 
William Roeder #:

Probably because your broker's implementation of FIFO rules.

I suggest only opening one order, no TP. and do a partial close when reached.

Thanks! I got it :)

Reason: