Pivot Points MQL5 Indicator: Daily, Weekly & Monthly Support/Resistance Levels
Display daily, weekly and monthly pivot reference levels from the previous completed broker period. This object-based indicator uses CopyRates, standard P/R/S formulas and time-price labels, with separate ownership for each chart instance. It contains no entry signals or verified trading results.
How the indicator signal works
Calculation and signal conditions
Read the preceding D1, W1 or MN1 high, low and close and calculate P=(H+L+C)/3 plus R1–R3 and S1–S3. Each enabled source period has a labeled object group. The indicator refreshes from source history on calculation callbacks, so it does not wait for the current chart timeframe to roll before detecting a new source period.
Interpretation and limitations
There is no trade execution, stop management, candle rejection test, RSI check, volume threshold or scale-out rule. The plotted levels can inform a separately specified strategy, but touching a level is not proof of support or a profitable trade. Broker period boundaries and revisions to historical prices affect the calculated references.
MQL5 Custom Indicator Code
#property strict
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0
input string InstanceId="Pivots"; // Use a distinct ID for another copy on this chart.
input bool ShowDaily=true;
input bool ShowWeekly=false;
input bool ShowMonthly=false;
input bool ShowOuterLevels=false;
input color PivotColor=clrYellow;
input color ResistanceColor=clrRed;
input color SupportColor=clrGreen;
input int LineWidth=1;
input ENUM_LINE_STYLE LineStyle=STYLE_DASH;
string prefix="";
bool ownsObjects=false;
int OnInit()
{
if(StringLen(InstanceId)<1 || StringLen(InstanceId)>20 || LineWidth<1 || LineWidth>5)
return INIT_PARAMETERS_INCORRECT;
prefix="PIVOT"+IntegerToString(StringLen(InstanceId))+"_"+InstanceId+"_";
string marker=prefix+"owner";
if(ObjectFind(0,marker)>=0) { Print("InstanceId already in use on this chart"); return INIT_FAILED; }
if(!ObjectCreate(0,marker,OBJ_LABEL,0,0,0)) return INIT_FAILED;
ownsObjects=true;
ObjectSetString(0,marker,OBJPROP_TEXT,"");
ObjectSetInteger(0,marker,OBJPROP_HIDDEN,true);
return INIT_SUCCEEDED;
}
void RemoveGroup(const string group)
{
for(int i=ObjectsTotal(0,0,-1)-1;i>=0;i--)
{
string name=ObjectName(0,i,0,-1);
if(StringFind(name,group)==0 && !ObjectDelete(0,name))
Print("Object delete failed: ",name," ",GetLastError());
}
}
void OnDeinit(const int reason)
{
if(ownsObjects) RemoveGroup(prefix);
}
bool DrawLine(const string name,const double price,const color colour,
const string label,const datetime anchor)
{
if(ObjectFind(0,name)<0 && !ObjectCreate(0,name,OBJ_HLINE,0,0,price)) return false;
if(!ObjectSetDouble(0,name,OBJPROP_PRICE,price)
|| !ObjectSetInteger(0,name,OBJPROP_COLOR,colour)
|| !ObjectSetInteger(0,name,OBJPROP_STYLE,LineStyle)
|| !ObjectSetInteger(0,name,OBJPROP_WIDTH,LineWidth)
|| !ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false)) return false;
string text=name+"_label";
if(ObjectFind(0,text)<0 && !ObjectCreate(0,text,OBJ_TEXT,0,anchor,price)) return false;
if(!ObjectMove(0,text,0,anchor,price)
|| !ObjectSetString(0,text,OBJPROP_TEXT,label+" "+DoubleToString(price,_Digits))
|| !ObjectSetInteger(0,text,OBJPROP_COLOR,colour)
|| !ObjectSetInteger(0,text,OBJPROP_ANCHOR,ANCHOR_LEFT)
|| !ObjectSetInteger(0,text,OBJPROP_SELECTABLE,false)) return false;
return true;
}
bool UpdateGroup(const ENUM_TIMEFRAMES tf,const string tag,const datetime anchor)
{
MqlRates bar[1];
string group=prefix+tag+"_";
if(CopyRates(_Symbol,tf,1,1,bar)!=1 || bar[0].high<bar[0].low)
{
RemoveGroup(group); // Do not display stale levels as current when data are unavailable.
return false;
}
double h=bar[0].high,l=bar[0].low,c=bar[0].close;
double p=(h+l+c)/3;
double values[7]={p,2*p-l,2*p-h,p+h-l,p-h+l,h+2*(p-l),l-2*(h-p)};
string labels[7]={"P","R1","S1","R2","S2","R3","S3"};
int count=ShowOuterLevels?7:5;
for(int i=0;i<count;i++)
{
color colour=i==0?PivotColor:((i%2)==1?ResistanceColor:SupportColor);
if(!DrawLine(group+labels[i],values[i],colour,tag+" "+labels[i],anchor))
{ Print("Object update failed: ",GetLastError()); return false; }
}
return true;
}
int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[])
{
if(!ownsObjects || rates_total<1) return 0;
datetime anchor=iTime(_Symbol,_Period,0);
if(anchor<=0) return prev_calculated;
bool ok=true;
if(ShowDaily && !UpdateGroup(PERIOD_D1,"D",anchor)) ok=false;
if(ShowWeekly && !UpdateGroup(PERIOD_W1,"W",anchor)) ok=false;
if(ShowMonthly && !UpdateGroup(PERIOD_MN1,"M",anchor)) ok=false;
ChartRedraw(0);
return ok?rates_total:prev_calculated;
}Copy this code into MetaEditor, save it in the MQL5/Indicators folder, and compile with F7.
Change the settings or add your own signal filter
Describe the inputs, buffers, alerts, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.
Frequently Asked Questions
Related MQL5 pages
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.