This tool is designed to help traders understand the relative strength or weakness of different currencies by analyzing how they behave across multiple currency pairs simultaneously. Instead of looking at just one chart, it scans a wide variety of major pairings to provide a "big picture" view of market sentiment.
How the Logic Works
1. Currency Identification When you load this tool onto a chart, it automatically identifies the two currencies involved in that specific pair (for example, if you are looking at EURUSD, it identifies EUR as the base and USD as the quote).
2. Multi-Pair Analysis The script scans a predefined list of major global currency pairs. It filters these pairs to find every instance where your "Base" currency or "Quote" currency appears. For example, if you are on an EUR chart, it will look at all different pairs involving the Euro (like EURJPY, EURGBP, etc.).
3. Price Difference Calculation The tool calculates a specific mathematical difference for each of these relevant pairs based on a user-selected mode:
- Current Open vs. Close: It compares where the price is now versus where it started at the beginning of the current candle.
- Previous Close vs. Current Close: It compares the current price to the closing price of the previous candle.
By calculating these differences, the tool determines if a currency is gaining value (positive) or losing value (negative) relative to other currencies in the market.
4. Strength Determination This is the core "intelligence" of the script. It counts how many of those pairs are moving in a favorable direction for your specific currency:
- Strong: If a high number of pairs (based on a threshold you set) show your currency gaining value, the tool labels that currency as "Strong."
- Weak: If the majority of those pairs show your currency losing value, it labels it as "Weak."
- Neutral: If the movement is mixed and does not meet your threshold, it remains "Neutral."
Visual Output
The tool provides a clean, real-time dashboard on your chart. It displays:
- Live Status: Clear text labels telling you immediately if the Base currency is Strong, Neutral, or Weak, along with a corresponding color (Green for strength, Red for weakness).
- Detailed Data: If enabled, it lists the specific price differences for every relevant pair in a organized list.
- Dynamic Updates: The data refreshes automatically as the market moves, allowing you to see shifts in sentiment instantly without having to manually check multiple tabs or charts.
//+------------------------------------------------------------------+
//| I_CloseDifference_v-08.mq4 |
//| Luca Spinello |
//| https://mql4tradingautomation.com |
//+------------------------------------------------------------------+
#property copyright "Luca Spinello"
#property link "https://mql4tradingautomation.com"
#property version "0.8"
#property strict
#property description "This indicator analyses the price difference"
#property description "comparing different values across multiple pairs"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1 clrBlue
#property indicator_color2 clrRed
#property indicator_color3 clrDeepSkyBlue
#property indicator_color4 clrMagenta
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 2
#property indicator_width4 2
//--- indicator parameters
enum Enum_CalculationMode{
Mode_CurrentOpen=0, //CURR CLOSE vs CURR OPEN
Mode_PreviousClose=1, //CURR CLOSE vs PREVIOUS CLOSE
};
string CalculationModeDesc[]={
"CURR CLOSE vs CURR OPEN",
"CURR CLOSE vs PREVIOUS CLOSE",
};
input string comment_0="=========="; //Comparator Indicator
input string IndicatorName="CloseDifference"; //Indicator's Name
input string comment_1="=========="; //Currencies to Analyse
input bool UseEUR=true; //EUR
input bool UseUSD=true; //USD
input bool UseGBP=true; //GBP
input bool UseJPY=true; //JPY
input bool UseCAD=true; //CAD
input bool UseAUD=true; //AUD
input bool UseNZD=true; //NZD
input bool UseCHF=true; //CHF
input string comment_2="=========="; //Value to compare
input Enum_CalculationMode CalculationMode=Mode_CurrentOpen; //Compare Method
input string comment_3="=========="; //Threshold for Strength
input int PairsToCount=7; //Pairs in favor/against to be considered Strong/Weak
input string comment_4="=========="; //Show All Values
input bool ShowPartial=false; //Show Detailed Pairs
input string comment_1b="=========="; //Positive and Negative Colors
input color PositiveColor=clrGreen; //Positive Color
input color NegativeColor=clrRed; //Negative Color
string Font="Lucida Console";
//List all the pairs
string AllPairs[]=
{
"AUDCAD",
"AUDCHF",
"AUDJPY",
"AUDNZD",
"AUDUSD",
"CADCHF",
"CADJPY",
"CHFJPY",
"EURAUD",
"EURCAD",
"EURCHF",
"EURGBP",
"EURJPY",
"EURNZD",
"EURUSD",
"GBPAUD",
"GBPCAD",
"GBPCHF",
"GBPJPY",
"GBPNZD",
"GBPUSD",
"NZDCAD",
"NZDCHF",
"NZDJPY",
"NZDUSD",
"USDCAD",
"USDCHF",
"USDJPY"
};
//List all the currencies
string AllCurrencies[]=
{
"EUR",
"USD",
"GBP",
"JPY",
"AUD",
"NZD",
"CAD",
"CHF"
};
//Define working variables
string CurrBase_Pairs[7];
string CurrQuote_Pairs[7];
double CurrBase_Diff[7];
double CurrQuote_Diff[7];
string CurrBase="";
string CurrQuote="";
double CurrBase_Strength[1]; //1-Strong, 0-Neutral, -1-Weak
double CurrQuote_Strength[1]; //1-Strong, 0-Neutral, -1-Weak
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit(void)
{
IndicatorDigits(4);
//---
IndicatorShortName(IndicatorName);
SetIndexStyle(0,DRAW_NONE);
SetIndexBuffer(0,CurrBase_Strength); //1-Strong, 0-Neutral, -1-Weak
SetIndexLabel(0,"BaseStrength");
SetIndexStyle(1,DRAW_NONE);
SetIndexBuffer(1,CurrQuote_Strength); //1-Strong, 0-Neutral, -1-Weak
SetIndexLabel(1,"QuoteStrength");
//Clean the chart from existing objects
CleanChart();
//--- check for input parameters
//--- initialization done
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence |
//+------------------------------------------------------------------+
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[])
{
PopulatePairs();
DetectCurrencies();
PopulateDiffValues();
CleanChart();
UpdateLabels();
return(0);
}
//+------------------------------------------------------------------+
//Remove existing labels
void CleanChart(){
int Window=0;
for(int i=0;i<ObjectsTotal(ChartID(),Window,-1);i++){
if(StringFind(ObjectName(ChartID(),i,Window,OBJ_LABEL),IndicatorName,0)!=-1) ObjectDelete(ChartID(),ObjectName(ChartID(),i,Window,OBJ_LABEL));
}
}
//Create and update the labels
void UpdateLabels(){
int LabelsBase=0;
int LabelsQuote=0;
int Window=0;
if(ShowPartial){
for(int i=0;i<7;i++){
if(CurrBase_Pairs[i]!=NULL){
CreateLabel("BASE",CurrBase_Pairs[i],CurrBase_Diff[i],Window,LabelsBase);
LabelsBase++;
}
else{
DeleteLabel("BASE",CurrBase_Pairs[i]);
}
if(CurrQuote_Pairs[i]!=NULL){
CreateLabel("QUOTE",CurrQuote_Pairs[i],CurrQuote_Diff[i],Window,LabelsQuote);
LabelsQuote++;
}
else{
DeleteLabel("QUOTE",CurrQuote_Pairs[i]);
}
}
}
string CalcModeLabel=StringConcatenate(IndicatorName,"CalculationMode");
if(ObjectFind(ChartID(),CalcModeLabel)>=0) ObjectDelete(ChartID(),CalcModeLabel);
ObjectCreate(ChartID(),CalcModeLabel,OBJ_LABEL,Window,0,0);
ObjectSet(CalcModeLabel,OBJPROP_XDISTANCE,5);
ObjectSet(CalcModeLabel,OBJPROP_YDISTANCE,20);
ObjectSetText(CalcModeLabel,"Period : "+Period()+" - Compare : "+CalculationModeDesc[CalculationMode],8,Font,clrDimGray);
string BaseCurrLabel=StringConcatenate(IndicatorName,"BaseLabel");
string BaseTitle=CurrBase;
color BaseTitleColor=clrDimGray;
string StrTmp;
if(MathRound(CurrBase_Strength[0])==1){
StrTmp=" is Strong";
BaseTitleColor=PositiveColor;
}
if(MathRound(CurrBase_Strength[0])==0){
StrTmp=" is Neutral";
BaseTitleColor=clrDimGray;
}
if(MathRound(CurrBase_Strength[0])==-1){
StrTmp=" is Weak";
BaseTitleColor=NegativeColor;
}
BaseTitle=StringConcatenate(BaseTitle,StrTmp);
ObjectCreate(ChartID(),BaseCurrLabel,OBJ_LABEL,Window,0,0);
ObjectSet(BaseCurrLabel,OBJPROP_XDISTANCE,5);
ObjectSet(BaseCurrLabel,OBJPROP_YDISTANCE,40);
ObjectSetText(BaseCurrLabel,BaseTitle,8,Font,BaseTitleColor);
string QuoteCurrLabel=StringConcatenate(IndicatorName,"QuoteLabel");
string QuoteTitle=CurrQuote;
color QuoteTitleColor=clrDimGray;
if(MathRound(CurrQuote_Strength[0])==1){
StrTmp=" is Strong";
QuoteTitleColor=PositiveColor;
}
if(MathRound(CurrQuote_Strength[0])==0){
StrTmp=" is Neutral";
QuoteTitleColor=clrDimGray;
}
if(MathRound(CurrQuote_Strength[0])==-1){
StrTmp=" is Weak";
QuoteTitleColor=NegativeColor;
}
QuoteTitle=StringConcatenate(QuoteTitle,StrTmp);
ObjectCreate(ChartID(),QuoteCurrLabel,OBJ_LABEL,Window,0,0);
ObjectSet(QuoteCurrLabel,OBJPROP_XDISTANCE,120);
ObjectSet(QuoteCurrLabel,OBJPROP_YDISTANCE,40);
ObjectSetText(QuoteCurrLabel,QuoteTitle,8,Font,QuoteTitleColor);
}
//Create individual label
void CreateLabel(string Type, string Pair, double Value, int Window, int L){
string LabelName=StringConcatenate(IndicatorName,"Label",Type,Pair);
int Xoff;
int Yoff=L*15;
if(Type=="BASE") Xoff=5;
if(Type=="QUOTE") Xoff=120;
string LabelString=StringConcatenate(Pair," ",Value>=0 ? "+":"",DoubleToStr(Value,4));
color Color;
if(Value>=0) Color=PositiveColor;
else Color=NegativeColor;
ObjectCreate(ChartID(),LabelName,OBJ_LABEL,Window,0,0);
ObjectSet(LabelName,OBJPROP_XDISTANCE,Xoff);
ObjectSet(LabelName,OBJPROP_YDISTANCE,Yoff+60);
ObjectSetText(LabelName,LabelString,8,Font,Color);
}
void DeleteLabel(string Type, string Pair){
int Window=0;
ObjectsDeleteAll(ChartID(),IndicatorName,Window);
}
//Calculate the pairs to analyze
void PopulatePairs(){
int j=0;
int k=0;
for(int i=0;i<ArraySize(AllPairs);i++){
if(StringFind(AllPairs[i],CurrBase,0)!=-1){
if(UseEUR && StringFind(AllPairs[i],"EUR",0)!=-1 && CurrBase!="EUR") CurrBase_Pairs[j]=AllPairs[i];
if(UseAUD && StringFind(AllPairs[i],"AUD",0)!=-1 && CurrBase!="AUD") CurrBase_Pairs[j]=AllPairs[i];
if(UseGBP && StringFind(AllPairs[i],"GBP",0)!=-1 && CurrBase!="GBP") CurrBase_Pairs[j]=AllPairs[i];
if(UseUSD && StringFind(AllPairs[i],"USD",0)!=-1 && CurrBase!="USD") CurrBase_Pairs[j]=AllPairs[i];
if(UseNZD && StringFind(AllPairs[i],"NZD",0)!=-1 && CurrBase!="NZD") CurrBase_Pairs[j]=AllPairs[i];
if(UseCAD && StringFind(AllPairs[i],"CAD",0)!=-1 && CurrBase!="CAD") CurrBase_Pairs[j]=AllPairs[i];
if(UseCHF && StringFind(AllPairs[i],"CHF",0)!=-1 && CurrBase!="CHF") CurrBase_Pairs[j]=AllPairs[i];
if(UseJPY && StringFind(AllPairs[i],"JPY",0)!=-1 && CurrBase!="JPY") CurrBase_Pairs[j]=AllPairs[i];
j++;
}
//Print(UseCAD);
if(StringFind(AllPairs[i],CurrQuote,0)!=-1){
if(UseEUR && StringFind(AllPairs[i],"EUR",0)!=-1 && CurrQuote!="EUR") CurrQuote_Pairs[k]=AllPairs[i];
if(UseAUD && StringFind(AllPairs[i],"AUD",0)!=-1 && CurrQuote!="AUD") CurrQuote_Pairs[k]=AllPairs[i];
if(UseGBP && StringFind(AllPairs[i],"GBP",0)!=-1 && CurrQuote!="GBP") CurrQuote_Pairs[k]=AllPairs[i];
if(UseUSD && StringFind(AllPairs[i],"USD",0)!=-1 && CurrQuote!="USD") CurrQuote_Pairs[k]=AllPairs[i];
if(UseNZD && StringFind(AllPairs[i],"NZD",0)!=-1 && CurrQuote!="NZD") CurrQuote_Pairs[k]=AllPairs[i];
if(UseCAD && StringFind(AllPairs[i],"CAD",0)!=-1 && CurrQuote!="CAD") CurrQuote_Pairs[k]=AllPairs[i];
if(UseCHF && StringFind(AllPairs[i],"CHF",0)!=-1 && CurrQuote!="CHF") CurrQuote_Pairs[k]=AllPairs[i];
if(UseJPY && StringFind(AllPairs[i],"JPY",0)!=-1 && CurrQuote!="JPY") CurrQuote_Pairs[k]=AllPairs[i];
k++;
}
}
}
//Detect current currencies in the chart
void DetectCurrencies(){
string Curr1="";
string Curr2="";
int Curr1Pos,Curr2Pos;
for(int i=0;i<ArraySize(AllCurrencies);i++){
int Curr1PosTmp=StringFind(Symbol(),AllCurrencies[i],0);
int Curr2PosTmp=StringFind(Symbol(),AllCurrencies[i],0);
if(Curr1=="" && Curr1PosTmp!=-1){
Curr1=AllCurrencies[i];
Curr1Pos=Curr1PosTmp;
}
if(Curr1!="" && Curr2PosTmp!=-1){
Curr2=AllCurrencies[i];
Curr2Pos=Curr2PosTmp;
}
}
if(Curr1Pos<Curr2Pos){
CurrBase=Curr1;
CurrQuote=Curr2;
}
else{
CurrBase=Curr2;
CurrQuote=Curr1;
}
}
//Populate the current values
void PopulateDiffValues(){
int BaseStrong=0;
int QuoteStrong=0;
int BaseWeak=0;
int QuoteWeak=0;
for(int i=0;i<7;i++){
if(CurrBase_Pairs[i]!=NULL){
CurrBase_Diff[i]=CalculateDiff(CurrBase_Pairs[i]);
if((StringFind(CurrBase_Pairs[i],CurrBase,0)==0 && CurrBase_Diff[i]>=0) || (StringFind(CurrBase_Pairs[i],CurrBase,0)>0 && CurrBase_Diff[i]<0)) BaseStrong++;
if((StringFind(CurrBase_Pairs[i],CurrBase,0)==0 && CurrBase_Diff[i]<0) || (StringFind(CurrBase_Pairs[i],CurrBase,0)>0 && CurrBase_Diff[i]>=0)) BaseWeak++;
}
if(CurrQuote_Pairs[i]!=NULL){
CurrQuote_Diff[i]=CalculateDiff(CurrQuote_Pairs[i]);
if((StringFind(CurrQuote_Pairs[i],CurrQuote,0)==0 && CurrQuote_Diff[i]>=0) || (StringFind(CurrQuote_Pairs[i],CurrQuote,0)>0 && CurrQuote_Diff[i]<0)) QuoteStrong++;
if((StringFind(CurrQuote_Pairs[i],CurrQuote,0)==0 && CurrQuote_Diff[i]<0) || (StringFind(CurrQuote_Pairs[i],CurrQuote,0)>0 && CurrQuote_Diff[i]>=0)) QuoteWeak++;
}
}
if(BaseStrong>=PairsToCount) CurrBase_Strength[0]=1;
else if(BaseWeak>=PairsToCount) CurrBase_Strength[0]=-1;
else CurrBase_Strength[0]=0;
if(QuoteStrong>=PairsToCount) CurrQuote_Strength[0]=1;
else if(QuoteWeak>=PairsToCount) CurrQuote_Strength[0]=-1;
else CurrQuote_Strength[0]=0;
}
//Calculate individual value
double CalculateDiff(string Pair){
double Evalue=iClose(Pair,0,0);
double Svalue=0;
switch(CalculationMode){
case 0:
Svalue=iOpen(Pair,0,0);
break;
case 1:
Svalue=iClose(Pair,0,1);
break;
}
double Diff=NormalizeDouble((Evalue*1000/Svalue)-1000,4);
return Diff;
}
Comments