Duplicating PineScript's bgcolor() function in MQL5

 

Greetings,

I'm trying to duplicate PineScript's bgcolor() function call in MQL5 - so far I've come up with:

color canvasColor = clrLightGreen; // Choose the color you want for the canvas
ObjectCreate(0, "BackgroundCanvas", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "BackgroundCanvas", OBJPROP_COLOR, canvasColor);
ObjectSetInteger(0, "BackgroundCanvas", OBJPROP_XDISTANCE, 0);
ObjectSetInteger(0, "BackgroundCanvas", OBJPROP_YDISTANCE, 0);
ObjectSetInteger(0, "BackgroundCanvas", OBJPROP_XSIZE, 100); 
ObjectSetInteger(0, "BackgroundCanvas", OBJPROP_YSIZE, 100); 

But of course all this does is draw a static rectangle at the top left corner of the chart, which does not move with the chart as new bars are created.

The PineScript bgcolor() function changes the current bar's background color and it "sticks" to that bar, moving left/right with the chart.

Can someone point me in the right direction or ideally an existing MQL5 indicator which does this so I can examine it's code?

/disclaimer: I'm very new to MQL5 (coming from PineScript)

Thanks

 
HenZen:

Greetings,

I'm trying to duplicate PineScript's bgcolor() function call in MQL5 - so far I've come up with:

But of course all this does is draw a static rectangle at the top left corner of the chart, which does not move with the chart as new bars are created.

The PineScript bgcolor() function changes the current bar's background color and it "sticks" to that bar, moving left/right with the chart.

Can someone point me in the right direction or ideally an existing MQL5 indicator which does this so I can examine it's code?

/disclaimer: I'm very new to MQL5 (coming from PineScript)

Thanks

You need to use OBJ_RECTANGLE instead of OBJ_RECTANGLE_LABEL

Documentation on MQL5: Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_RECTANGLE
Documentation on MQL5: Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_RECTANGLE
  • www.mql5.com
OBJ_RECTANGLE - Object Types - Objects Constants - Constants, Enumerations and Structures - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
Navdeep Singh #:

You need to use OBJ_RECTANGLE instead of OBJ_RECTANGLE_LABEL

Thanks, but that does not address my question. I don't want to draw a rectangle, I want to change the background color of the chart behind the current candle.

 
HenZen #:

Thanks, but that does not address my question. I don't want to draw a rectangle, I want to change the background color of the chart behind the current candle.

The answer you got is actually addressing your question.

MQL doesn't provide high level function like pinescript bgcolor. So you need to draw rectangle anchored to the chart (by time/price) according to your rules.

Or you can try to find some code that already did it in the Codebase, or the Market.

 
HenZen #:

Thanks, but that does not address my question. I don't want to draw a rectangle, I want to change the background color of the chart behind the current candle.

You can actually cheat this with a histogram. But, the problem will be the drawing. In front or behind the candles can only be set globally, so you cannot have a buffer shown in front of the candles and another behind the candles.

If I am not mistaking, this can be set per indicator on chart individually, not sure though, but definitely not per buffer inside one indicator.


 
HenZen:

Greetings,

I'm trying to duplicate PineScript's bgcolor() function call in MQL5 - so far I've come up with:

But of course all this does is draw a static rectangle at the top left corner of the chart, which does not move with the chart as new bars are created.

The PineScript bgcolor() function changes the current bar's background color and it "sticks" to that bar, moving left/right with the chart.

Can someone point me in the right direction or ideally an existing MQL5 indicator which does this so I can examine it's code?

/disclaimer: I'm very new to MQL5 (coming from PineScript)

Thanks

Hello 

Consult this indicator .

Cheers  🏄 ☀️ 🌴 🍺 🍦

#property copyright "Go to forum"
#property link      "https://www.mql5.com/en/forum/452353"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#include <Canvas/Canvas.mqh>
/* expalanation : 
   ->create a constant underchart bitmap
   ->it resizes and adjusts based on the chart
   ->it draws rectangles based on a buffer
   ->we want it to be as plug and play as possible 
     so link , setup , link to events etc.
   ->We will use the sexy canvas library provided by mt5
*/
//so first let's wrap everything nicely in a package
struct underChartRectangles{
        private:
   bool ready;
CCanvas display;
 string tether;//the object name 
   long chart_id;//the chart id 
    int subwindow;//the chart subwindow
        //next thing we need is a config that associates values with colors 
    int codes[];//
   uint palette[];//
        /*
        the codes and palette are parallel , when we add a code we 
        also add a color 
        So we say 1 is red 2 is blue etc 
        */ 
        //we also need to recall the size of the chart
    int chartSX,chartSY;
        public:
        //the functions 
        underChartRectangles(void){reset();}
       ~underChartRectangles(void){reset();}
   void reset(){
        ArrayFree(codes);
        ArrayFree(palette);
        display.Destroy();
        if(StringLen(tether)>0){ObjectDelete(ChartID(),tether);}
        chart_id=0;
        subwindow=0;
        ready=false;
        }
        //setup
   void setup(long _chart_id,
               int _subwindow,
            string _name){
        tether=_name;
        chart_id=_chart_id;
        subwindow=_subwindow;
        chartSX=(int)ChartGetInteger(chart_id,CHART_WIDTH_IN_PIXELS,subwindow);
        chartSY=(int)ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,subwindow);    
        display.CreateBitmapLabel(chart_id,subwindow,tether,0,0,chartSX,chartSY,COLOR_FORMAT_ARGB_NORMALIZE);
        ObjectSetInteger(chart_id,tether,OBJPROP_BACK,true);
        display.Erase(0);
        ready=true;
        }
        //add a color code
   void add_code(int _code,
                 color _color,
                 uchar _opacity){
        int ns=ArraySize(codes)+1;
        ArrayResize(codes,ns,0);
        ArrayResize(palette,ns,0);
        codes[ns-1]=_code;
        palette[ns-1]=ColorToARGB(_color,_opacity);
        }
        //find a color by code
   bool find_by_code(int _code,
                     uint &_result){
        for(int i=0;i<ArraySize(codes);i++){
           if(_code==codes[i]){
             _result=palette[i];
             return(true);
             }
           }
        return(false);
        }
   bool find_by_code(double _code,uint &_result){
        return(find_by_code((int)MathFloor(_code),_result));
        }
   bool is_ready(){return(ready);}
   bool check_size(){//returns true if needs update
        int w=(int)ChartGetInteger(chart_id,CHART_WIDTH_IN_PIXELS,subwindow);
        int h=(int)ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,subwindow);
        if(w!=chartSX||h!=chartSY){
          display.Erase(0);
          display.Resize(w,h);
          chartSX=w;
          chartSY=h;
          return(true);
          }
        return(false);
        }
        //draw based on buffer
   void update(double &buffer[],
               double &time_copy[]){
        display.Erase(0);
        //get size in bars 
          int size_in_bars=(int)ChartGetInteger(chart_id,CHART_WIDTH_IN_BARS,subwindow);
        //get first visible bar , this goes from right [0] to left [rates_total]
          int fvb=(int)ChartGetInteger(chart_id,CHART_FIRST_VISIBLE_BAR,subwindow);
        //background area per bar
          int x_per_bar=(int)MathFloor(((double)chartSX)/((double)size_in_bars));
        /*
          now we need to ninja our way into the buffer
          the display starts from fvb with the newest bar being at [0]
          but in the buffer -untouched , not as series- the newest bar is rates_total (or Bars) -1
          so loop from first visible bar till [0]
        */
          for(int i=fvb;i>=0;i--){
             //find index in buffer 
               int ix=Bars(_Symbol,_Period)-1-i;
             //get color 
               uint colo=0;
               if(find_by_code(buffer[ix],colo)){
                 int draw_x=0,draw_y=0;
                 ChartTimePriceToXY(chart_id,subwindow,(datetime)(time_copy[ix]),0.0,draw_x,draw_y);
                 display.FillRectangle(draw_x-(x_per_bar/2),0,draw_x+(x_per_bar/2),chartSY-1,colo);                   
                 }            
             }
        display.Update(true);
        ChartRedraw(chart_id);
        }
};

underChartRectangles UCR;
//the indicator buffers 
  double CODES[];//the codes per bar , you fill this in the indicator with your calculations
//the time copy
  double TIMECOPY[];//for display purpose 
  
int OnInit()
  {
  UCR.reset();
  SetIndexBuffer(0,CODES,INDICATOR_DATA);
  SetIndexBuffer(1,TIMECOPY,INDICATOR_DATA);
  //now we setup 2 colors for demonstration
    UCR.setup(ChartID(),0,"UC_DISPLAY");
    UCR.add_code(1,clrGreen,255);
    UCR.add_code(2,clrRed,255);
  return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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=prev_calculated;i<rates_total-1;i++){
  TIMECOPY[i]=(double)time[i];
    CODES[i]=0;
    //if the bar is bullish assign code 1 
    if(close[i]>open[i]){CODES[i]=1;}
    else if(close[i]<open[i]){CODES[i]=2;}
  }
  UCR.update(CODES,TIMECOPY);
  return(rates_total);
  }

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
  if(UCR.is_ready()){
    UCR.check_size();
    UCR.update(CODES,TIMECOPY);
    }
  }
void OnDeinit(const int reason)
  {
//---
  UCR.reset();
  }
edit : forgot to mention this is where you assign the background color code to a bar . 
 
Lorentzos Roussos #:

Hello 

Consult this indicator .

Cheers  🏄 ☀️ 🌴 🍺 🍦

edit : forgot to mention this is where you assign the background color code to a bar . 

This is EXACTLY what I was looking for, thanks Lorentzos!

 
Lorentzos Roussos #:
OnCalculate

Update: Since I'm trying to code an EA, using OnCalculate() results in the target being changed to an indicator, and OnTick() no longer being called.

 
HenZen #:

Update: Since I'm trying to code an EA, using OnCalculate() results in the target being changed to an indicator, and OnTick() no longer being called.

Yes you will have to tailor it to your needs . If its on an EA you might have to do some custom management of buffers

Reason: