string oName="Name"; string text= "my text string"; datetime tim=iTime(_Symbol,PERIOD_CURRENT,1); double price=iHigh(_Symbol,PERIOD_CURRENT,1); ObjectCreate(0,oName,OBJ_TEXT,0,tim,price); ObjectSetString(0,oName,OBJPROP_TEXT,text);
Thank you.
Putting that into the context of the built-in MT4 [Bollinger] Bands Indicator, the below is creating Text Objects. However, all the Text Objects seem to be being created at the same time/price position - so I have numerous objects on top of each other. I discovered this by double clicking an object, selecting it then dragging it to another bar/price on the chart. What am I missing? Can you tell me why they are not being added to the bars where the if conditions are true as the for loop is iterating from the start of the chart to the current bar?
//+------------------------------------------------------------------+ //| Bands.mq4 | //| Copyright 2005-2014, MetaQuotes Software Corp. | //| http://www.mql4.com | //+------------------------------------------------------------------+ #property copyright "2005-2014, MetaQuotes Software Corp." #property link "http://www.mql4.com" #property description "Bollinger Bands" #property strict #include <MovingAverages.mqh> #property indicator_chart_window #property indicator_buffers 3 #property indicator_color1 LightSeaGreen #property indicator_color2 LightSeaGreen #property indicator_color3 LightSeaGreen //--- indicator parameters input int InpBandsPeriod=20; // Bands Period input int InpBandsShift=0; // Bands Shift input double InpBandsDeviations=2.0; // Bands Deviations //--- buffers double ExtMovingBuffer[]; double ExtUpperBuffer[]; double ExtLowerBuffer[]; double ExtStdDevBuffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- 1 additional buffer used for counting. IndicatorBuffers(4); IndicatorDigits(Digits); //--- middle line SetIndexStyle(0,DRAW_LINE); SetIndexBuffer(0,ExtMovingBuffer); SetIndexShift(0,InpBandsShift); SetIndexLabel(0,"Bands SMA"); //--- upper band SetIndexStyle(1,DRAW_LINE); SetIndexBuffer(1,ExtUpperBuffer); SetIndexShift(1,InpBandsShift); SetIndexLabel(1,"Bands Upper"); //--- lower band SetIndexStyle(2,DRAW_LINE); SetIndexBuffer(2,ExtLowerBuffer); SetIndexShift(2,InpBandsShift); SetIndexLabel(2,"Bands Lower"); //--- work buffer SetIndexBuffer(3,ExtStdDevBuffer); //--- check for input parameter if(InpBandsPeriod<=0) { Print("Wrong input parameter Bands Period=",InpBandsPeriod); return(INIT_FAILED); } SetIndexDrawBegin(2,InpBandsPeriod+InpBandsShift); //--- initialization done return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Bollinger Bands | //+------------------------------------------------------------------+ 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 i,pos; //--- if(rates_total<=InpBandsPeriod || InpBandsPeriod<=0) return(0); //--- counting from 0 to rates_total ArraySetAsSeries(ExtMovingBuffer,false); ArraySetAsSeries(ExtUpperBuffer,false); ArraySetAsSeries(ExtLowerBuffer,false); ArraySetAsSeries(ExtStdDevBuffer,false); ArraySetAsSeries(close,false); //--- initial zero if(prev_calculated<1) { for(i=0; i<InpBandsPeriod; i++) { ExtMovingBuffer[i]=EMPTY_VALUE; ExtUpperBuffer[i]=EMPTY_VALUE; ExtLowerBuffer[i]=EMPTY_VALUE; } } //--- starting calculation if(prev_calculated>1) pos=prev_calculated-1; else pos=0; //--- main cycle for(i=pos; i<rates_total && !IsStopped(); i++) { //--- middle line ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,close); //--- calculate and write down StdDev ExtStdDevBuffer[i]=StdDev_Func(i,close,ExtMovingBuffer,InpBandsPeriod); //--- upper line ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations*ExtStdDevBuffer[i]; //--- lower line ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations*ExtStdDevBuffer[i]; //--- //--------------- creating text object (with time/price coordinates) -----------------// if (i>0) { if (Close[i] < ExtUpperBuffer[i] && Close[i-1] > ExtUpperBuffer[i-1]) { string objName="object_"+(string)i; // unique object name to prevent Error #4200 long current_chart_id=ChartID(); string l_sLabel= "Sell"; datetime tim=iTime(_Symbol,PERIOD_CURRENT,1); double price=iHigh(_Symbol,PERIOD_CURRENT,1); ObjectCreate(current_chart_id,objName,OBJ_TEXT,0,tim,price); ObjectSetString(current_chart_id,objName,OBJPROP_TEXT,l_sLabel); //Print("Close crossed from above to below Upper BB at: ",Time[i]); } else if (Close[i] > ExtLowerBuffer[i] && Close[i-1] < ExtLowerBuffer[i-1]) { string objName="object_"+(string)i; // unique object name to prevent Error #4200 long current_chart_id=ChartID(); string l_sLabel= "Buy"; datetime tim=iTime(_Symbol,PERIOD_CURRENT,1); double price=iLow(_Symbol,PERIOD_CURRENT,1); ObjectCreate(current_chart_id,objName,OBJ_TEXT,0,tim,price); ObjectSetString(current_chart_id,objName,OBJPROP_TEXT,l_sLabel); //Print("Close crossed from below to above Lower BB at: ",Time[i]); } } //------------------------------------------------------------------------------------// } //---- OnCalculate done. Return new prev_calculated. return(rates_total); } //+------------------------------------------------------------------+ //| Calculate Standard Deviation | //+------------------------------------------------------------------+ double StdDev_Func(int position,const double &price[],const double &MAprice[],int period) { //--- variables double StdDev_dTmp=0.0; //--- check for position if(position>=period) { //--- calcualte StdDev for(int i=0; i<period; i++) StdDev_dTmp+=MathPow(price[position-i]-MAprice[position],2); StdDev_dTmp=MathSqrt(StdDev_dTmp/period); } //--- return calculated value return(StdDev_dTmp); } //+------------------------------------------------------------------+
I need to experiment with font attributes and price levels to get it looking right, but how do I ensure the Text Objects are removed when I remove the Indicator from the chart?
string objName="object_"+(string)i; // unique object name to prevent Error #4200
The above will not necessarily create a unique name
datetime tim=iTime(_Symbol,PERIOD_CURRENT,i); string objName="object_"+TimeToString(tim); // unique object name to prevent Error #4200 long current_chart_id=ChartID(); string l_sLabel= "Sell"; double price=iHigh(_Symbol,PERIOD_CURRENT,i); ObjectCreate(current_chart_id,objName,OBJ_TEXT,0,tim,price); ObjectSetString(current_chart_id,objName,OBJPROP_TEXT,l_sLabel);
how do I ensure the Text Objects are removed when I remove the Indicator from the chart?
In OnDeinit()
ObjectsDeleteAll(0,"object_");
The above will not necessarily create a unique name
how do I ensure the Text Objects are removed when I remove the Indicator from the chart?
In OnDeinit()
Thanks Keith.
I changed the code according to your feedback to the below, but now it seems to only print the last object and it is still in the wrong place:
//+------------------------------------------------------------------+ //| Bands.mq4 | //| Copyright 2005-2014, MetaQuotes Software Corp. | //| http://www.mql4.com | //+------------------------------------------------------------------+ #property copyright "2005-2014, MetaQuotes Software Corp." #property link "http://www.mql4.com" #property description "Bollinger Bands" #property strict #include <MovingAverages.mqh> #property indicator_chart_window #property indicator_buffers 3 #property indicator_color1 LightSeaGreen #property indicator_color2 LightSeaGreen #property indicator_color3 LightSeaGreen //--- indicator parameters input int InpBandsPeriod=20; // Bands Period input int InpBandsShift=0; // Bands Shift input double InpBandsDeviations=2.0; // Bands Deviations //--- buffers double ExtMovingBuffer[]; double ExtUpperBuffer[]; double ExtLowerBuffer[]; double ExtStdDevBuffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- 1 additional buffer used for counting. IndicatorBuffers(4); IndicatorDigits(Digits); //--- middle line SetIndexStyle(0,DRAW_LINE); SetIndexBuffer(0,ExtMovingBuffer); SetIndexShift(0,InpBandsShift); SetIndexLabel(0,"Bands SMA"); //--- upper band SetIndexStyle(1,DRAW_LINE); SetIndexBuffer(1,ExtUpperBuffer); SetIndexShift(1,InpBandsShift); SetIndexLabel(1,"Bands Upper"); //--- lower band SetIndexStyle(2,DRAW_LINE); SetIndexBuffer(2,ExtLowerBuffer); SetIndexShift(2,InpBandsShift); SetIndexLabel(2,"Bands Lower"); //--- work buffer SetIndexBuffer(3,ExtStdDevBuffer); //--- check for input parameter if(InpBandsPeriod<=0) { Print("Wrong input parameter Bands Period=",InpBandsPeriod); return(INIT_FAILED); } SetIndexDrawBegin(2,InpBandsPeriod+InpBandsShift); //--- initialization done return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Bollinger Bands | //+------------------------------------------------------------------+ 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 i,pos; //--- if(rates_total<=InpBandsPeriod || InpBandsPeriod<=0) return(0); //--- counting from 0 to rates_total ArraySetAsSeries(ExtMovingBuffer,false); ArraySetAsSeries(ExtUpperBuffer,false); ArraySetAsSeries(ExtLowerBuffer,false); ArraySetAsSeries(ExtStdDevBuffer,false); ArraySetAsSeries(close,false); //--- initial zero if(prev_calculated<1) { for(i=0; i<InpBandsPeriod; i++) { ExtMovingBuffer[i]=EMPTY_VALUE; ExtUpperBuffer[i]=EMPTY_VALUE; ExtLowerBuffer[i]=EMPTY_VALUE; } } //--- starting calculation if(prev_calculated>1) pos=prev_calculated-1; else pos=0; //--- main cycle for(i=pos; i<rates_total && !IsStopped(); i++) { //--- middle line ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,close); //--- calculate and write down StdDev ExtStdDevBuffer[i]=StdDev_Func(i,close,ExtMovingBuffer,InpBandsPeriod); //--- upper line ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations*ExtStdDevBuffer[i]; //--- lower line ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations*ExtStdDevBuffer[i]; //--- //--------------- creating text object (with time/price coordinates) -----------------// if (i>0) { if (Close[i] < ExtUpperBuffer[i] && Close[i-1] > ExtUpperBuffer[i-1]) { datetime tim=iTime(_Symbol,PERIOD_CURRENT,i); string objName="object_"+TimeToString(tim); // unique object name to prevent Error #4200 long current_chart_id=ChartID(); string l_sLabel= "Sell"; double price=iHigh(_Symbol,PERIOD_CURRENT,i); ObjectCreate(current_chart_id,objName,OBJ_TEXT,0,tim,price); ObjectSetString(current_chart_id,objName,OBJPROP_TEXT,l_sLabel); //Print("Close crossed from above to below Upper BB at: ",Time[i]); } else if (Close[i] > ExtLowerBuffer[i] && Close[i-1] < ExtLowerBuffer[i-1]) { datetime tim=iTime(_Symbol,PERIOD_CURRENT,i); string objName="object_"+TimeToString(tim); // unique object name to prevent Error #4200 long current_chart_id=ChartID(); string l_sLabel= "Buy"; double price=iLow(_Symbol,PERIOD_CURRENT,i); ObjectCreate(current_chart_id,objName,OBJ_TEXT,0,tim,price); ObjectSetString(current_chart_id,objName,OBJPROP_TEXT,l_sLabel); //Print("Close crossed from below to above Lower BB at: ",Time[i]); } } //------------------------------------------------------------------------------------// } //---- OnCalculate done. Return new prev_calculated. return(rates_total); } //+------------------------------------------------------------------+ //| Indicator Deinitialisation Function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0,"object_"); //--- deinitialization done } //+------------------------------------------------------------------+ //| Calculate Standard Deviation | //+------------------------------------------------------------------+ double StdDev_Func(int position,const double &price[],const double &MAprice[],int period) { //--- variables double StdDev_dTmp=0.0; //--- check for position if(position>=period) { //--- calcualte StdDev for(int i=0; i<period; i++) StdDev_dTmp+=MathPow(price[position-i]-MAprice[position],2); StdDev_dTmp=MathSqrt(StdDev_dTmp/period); } //--- return calculated value return(StdDev_dTmp); } //+------------------------------------------------------------------+
if (Close[i] < ExtUpperBuffer[i] && Close[i-1] > ExtUpperBuffer[i-1]) { datetime tim=iTime(_Symbol,PERIOD_CURRENT,i);You set your buffers to non-series, and then use the as-series predefined Close and as-series iTime with your non-series index.
Sorry, but you will have to check through your code and see what it is not doing that you think it should. I don't have time.
No worries - appreciate your help so far.
Thanks.
You set your buffers to non-series, and then use the as-series predefined Close and as-series iTime with your non-series index.
Thanks so much. I see what you're getting at now...I was wondering whether I had this backwards.
I'll change it and see how it goes. Much appreciated.

- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I am trying to automatically create a TextObject on the chart as a specific Bar/Time and Price, but I can't get it working. I tried the examples given in the MQL Help, but they don't show any text, they don't seem to work at all.
What is the minimum amount of code needed to draw a Text Object with:
> String = "my text string"
> at Time[time_x]
> at price [price_y]
?