Making a graphic show up under the candle when it is unsafe to trade at that moment (code tutorial)

 

I had this funny idea to make a red spike appear under the candle when it is unsafe to buy. As a warning signal. When the price is high, the red spike gets larger in dimension...the larger the spike, the more the trader needs to be certain about their entry... the smaller the spike...the better for a long entry. Because as it goes qualitatively.... when price is high, is is usually not the safest time to buy, and when price is low, it is always safer to buy.

Image attached.

So how did I do this in MQL5? A very creative approach.


I'm using OBJ_TRIANGLE to create the spike, and here is the function I made:

void WarningSignal(const int rates_total, const long chartID, const string name, const datetime& time[], double price, int index, const double& high[], const double& low[])
{ 
    double len = low[index];
    
    datetime x1 = NULL, x2 = NULL, x3 = NULL;
    double y1 = 0.0, y2 = 0.0, y3 = 0.0;
   
      if(index<rates_total && (index+3)<rates_total){   
          // Set the triangle vertices
          x1 = time[index];
          y1 = price/len;
          x2 = time[index];
          y2 = price;
          x3 = time[index+3];
          y3 = price/len;
      }
        
    // Create the triangle object
    ObjectCreate(chartID, name, OBJ_TRIANGLE, 0, x1, y1, x2, y2, x3, y3);
    
    // Set the object properties
    ObjectSetInteger(chartID, name, OBJPROP_BACK, true); // Set the background property 
    ObjectSetInteger(chartID, name,OBJPROP_FILL, true);                  
    ObjectSetInteger(chartID, name, OBJPROP_COLOR, clrLightCoral); // Set the fill color
}


I call the function when my condition is met inside the for loop in OnCalculate:

 
   int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[],
    const double& open[], const double& high[], const double& low[], const double& close[],
    const long& tick_volume[], const long& volume[], const int& spread[])
{
    int lastProcessedBar = 0;
    int startBar = prev_calculated;

    if (ChartPeriod() != prevPeriod) {
        prevPeriod = ChartPeriod(); // Store the current timeframe for comparison in the next calculation
        ChartRedraw(); // Refresh the chart to remove previous objects
    }

    for (int i = startBar; i < rates_total && !_StopFlag; i++)
    {
        if (i > 0)
        {
              // Calculate the difference between high and low prices
              double priceDifference = 0.0;
              priceDifference = high[i] - low[i];
                
              // Convert difference from points to pips
              double pointSize = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
              double pipDifference = priceDifference / pointSize;
              double warningGraphicSize = low[i] - (160 * _Point);              
              string _name = "TradeWarningGraphic" + DoubleToString(i); // Unique name for the arrow object        
                
            // Check for crossover points
            if (pipDifference > 40.0 && GreenLineBuffer[i - 1] < RedLineBuffer[i - 1] && GreenLineBuffer[i] > RedLineBuffer[i])
            {
                WarningSignal(rates_total, 0, _name, time, warningGraphicSize, i, high, low);   

            }      
        }  
        
        lastProcessedBar = i;
    }
   
   return lastProcessedBar; 
}


You could definitely add more functionality or use an OBJPROP object instead of a custom object. If you ever want to implement this your own indicator by all means feel free, but give credit. :-)

Documentation on MQL5: Constants, Enumerations and Structures / Objects Constants / Object Types
Documentation on MQL5: Constants, Enumerations and Structures / Objects Constants / Object Types
  • www.mql5.com
Object Types - Objects Constants - Constants, Enumerations and Structures - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
Files:
chart_image.png  17 kb
 
phade: I had this funny idea to make a red spike appear under the candle when it is unsafe to buy.

The only way to know when it is “unsafe to buy” is to see the future.

 
William Roeder #:

The only way to know when it is “unsafe to buy” is to see the future.

I keep asking psychics, I quit talking to economic analysts, but now they keep giving me the wrong predictions!  😁

 
William Roeder #:

The only way to know when it is “unsafe to buy” is to see the future.

But to take you up on this very pessimistic statement, there are A LOT of price prediction mechanisms.
And what do you think price momentum indicators and trend followers are for in the first place?
 

Another usage example:


input bool Enable_Entry_Warning_Graphic = true;


int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[],
    const double& open[], const double& high[], const double& low[], const double& close[],
    const long& tick_volume[], const long& volume[], const int& spread[])
{
    for (int i = startBar; i < rates_total && !_StopFlag; i++)
    {            
        if(Enable_Entry_Warning_Graphic==true && open[i] >= (prevDayClose() + 40*_Point)){
                   
                WarningSignal(rates_total, 0, "TradeWarning", time, low[i]-160*_Point, i, high, low);
        }
    }
}
    
   
   return rates_total; 
}



void WarningSignal(const int rates_total, const long chartID, const string name, const datetime& time[], double price, int index, const double& high[], const double& low[])
{ 
    double len = low[index];
    
    datetime x1 = NULL, x2 = NULL, x3 = NULL;
    double y1 = 0.0, y2 = 0.0, y3 = 0.0;
   
      if(index<rates_total && (index+3)<rates_total){   
          // Set the triangle vertices
          x1 = time[index];
          y1 = price/len;
          x2 = time[index];
          y2 = price;
          x3 = time[index+3];
          y3 = price/len;
      }
        
    // Create the triangle object
    ObjectCreate(chartID, name, OBJ_TRIANGLE, 0, x1, y1, x2, y2, x3, y3);
    
    // Set the object properties
    ObjectSetInteger(chartID, name, OBJPROP_BACK, true); // Set the background property 
    ObjectSetInteger(chartID, name,OBJPROP_FILL, true);                  
    ObjectSetInteger(chartID, name, OBJPROP_COLOR, clrLightCoral); // Set the fill color
}


double prevDayClose(){

    datetime prevDay = iTime(_Symbol, PERIOD_D1, 0); // Get the time of the previous day
    int prevBar = iBarShift(_Symbol, PERIOD_D1, prevDay); // Get the bar index of the previous day

    double closePrice = iClose(_Symbol, PERIOD_D1, prevBar); // Get the close price of the previous day

    return closePrice;
}

This logic can still be deemed inconsequential as market conditions may always change, but I think it does have the potential to be a helpful aid on occasion, and for specific markets.

 
string warningIndicator = "TradeWarningGraphic" + DoubleToString(i); // Unique name for the object    

int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[],
    const double& open[], const double& high[], const double& low[], const double& close[],
    const long& tick_volume[], const long& volume[], const int& spread[])
{
    for (int i = startBar; i < rates_total && !_StopFlag; i++)
  1. How can you create your object name outside the loop. There is no i there.

  2. Do not use series index in object names, as they are not unique. As soon as a new bar starts, you will be trying to create a new name (e.g., “name0”), same, existing, previous, name (e.g., “name0” now on bar one.)

    Use time (as int) or a non-series index:

    #define  SERIES(I)   (Bars - 1 - I) // As-series to non-series or back.
 
William Roeder #:
  1. How can you create your object name outside the loop. There is no i there.

  2. Do not use series index in object names, as they are not unique. As soon as a new bar starts, you will be trying to create a new name (e.g., “name0”), same, existing, previous, name (e.g., “name0” now on bar one.)

    Use time (as int) or a non-series index:

I haphazardly pasted in the code instead of posting a full script with unnecessary detail (so I fixed that now to avoid confusion). I would also use OBJ_PREFIX to make object names unique. so how I'm really doing it is OBJ_PREFIX + "myobjectname" + DoubleToString(i)