//+------------------------------------------------------------------+
//| OBVMTF.mq4 |
//| Copyright 2019, Roberto Jacobs (3rjfx) |
//| https://www.mql5.com/en/users/3rjfx |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Roberto Jacobs (3rjfx) ~ By 3rjfx ~ Created: 2019/02/23"
#property link "https://www.mql5.com/en/users/3rjfx"
#property description "Indicator OBVMTF base on the On Balance Volume indicator with Signal"
#property description "and Alert for MetaTrader 4 and options to display signal on the chart."
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
//--
#property indicator_color1 clrNONE
#property indicator_color2 clrNONE
//--
enum YN
{
No,
Yes
};
//--
enum corner
{
NotShow=-1, // Not Show Arrow
topchart=0, // On Top Chart
bottomchart=1 // On Bottom Chart
};
//--
//--
input ENUM_APPLIED_PRICE obv_prc = PRICE_CLOSE; // OBV Applied Price
input corner cor = topchart; // Arrow Move Position
input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No)
input YN EmailAlert = No; // Email Alert (Yes) or (No)
input YN sendnotify = No; // Send Notification (Yes) or (No)
input YN displayinfo = Yes; // Display Trade Info
input color textcolor = clrSnow; // Text Color
input color ArrowUp = clrLime; // Arrow Up Color
input color ArrowDn = clrRed; // Arrow Down Color
input color NTArrow = clrYellow; // Arrow No Signal
//---
//---- indicator buffers
double OBVMoveUp[];
double OBVMoveDn[];
//--
//--- spacing
int scaleX=35,scaleY=40,scaleYt=18,offsetX=250,offsetY=3,fontSize=7; // coordinate
int txttf,
arrtf;
color arclr;
ENUM_BASE_CORNER bcor;
//--- arrays for various things
int OBVTF[]={1,5,15,30,60,240,1440,10080,43200};
int XOBV[10];
string periodStr[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN","MOVE"}; // Text Timeframes
//--
double
pricepos;
datetime
cbartime;
int cur,prv;
int imnn,imnp;
int cmnt,pmnt;
int arr;
long CI;
static int fbar;
string posisi,
sigpos,
iname,
msgText;
string frtext="obvwave";
//---------//
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
IndicatorBuffers(2);
//--
SetIndexBuffer(0,OBVMoveUp);
SetIndexBuffer(1,OBVMoveDn);
//--
SetIndexStyle(0,DRAW_NONE);
SetIndexStyle(1,DRAW_NONE);
//--
//----
//-- name for DataWindow
SetIndexLabel(0,"OBV_Up");
SetIndexLabel(1,"OBV_Dn");
//--
SetIndexEmptyValue(0,0.0);
SetIndexEmptyValue(1,0.0);
//---- indicator short name
IndicatorDigits(_Digits);
iname=WindowExpertName();
IndicatorShortName(iname);
CI=ChartID();
arr=ArraySize(XOBV);
//--
if(cor>=0)
{
if(cor==topchart) {bcor=CORNER_LEFT_UPPER; txttf=45; arrtf=-20;}
if(cor==bottomchart) {bcor=CORNER_LEFT_LOWER; txttf=45; arrtf=-12;}
}
else
{
string name;
for(int i=ObjectsTotal()-1; i>=0; i--)
{
name=ObjectName(i);
if(StringFind(name,frtext,0)>-1) ObjectDelete(0,name);
}
}
//--
//---
return(INIT_SUCCEEDED);
}
//---------//
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
Comment("");
string name;
for(int i=ObjectsTotal()-1; i>=0; i--)
{
name=ObjectName(i);
if(StringFind(name,frtext,0)>-1) ObjectDelete(0,name);
}
//--
GlobalVariablesDeleteAll();
//----
return(0);
}
//---------//
//+------------------------------------------------------------------+
//| 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[])
{
//---
ArraySetAsSeries(open,true);
ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);
ArraySetAsSeries(close,true);
ArraySetAsSeries(time,true);
ArraySetAsSeries(volume,true);
int trn=0,xbup=0,xbdn=0,i;
cbartime=time[0];
arclr=NTArrow;
//--
imnn=Minute();
if(imnn!=imnp)
{
ResetLastError();
RefreshRates();
if(cor>=0)
{
for(int x=0; x<arr; x++)
{
CreateArrowLabel(CI,frtext+"_tfx_arrow_"+string(x),periodStr[x],"Bodoni MT Black",fontSize,textcolor,bcor,
txttf+x*scaleX+offsetX,scaleY+offsetY+7,true); //"Georgia" "Bodoni MT Black" "Verdana" "Arial Black"
}
}
//--
for(i=0; i<arr-1; i++)
{
XOBV[i]=GetDirection(OBVTF[i]);
if(cor>=0)
{
if(XOBV[i]>0) arclr=ArrowUp;
if(XOBV[i]<0) arclr=ArrowDn;
CreateArrowLabel(CI,frtext+"_win_arrow_"+string(i),CharToString(108),"Wingdings",14,arclr,bcor,
txttf+i*scaleX+offsetX,arrtf+scaleY+offsetY+7,true);
}
if(i<6)
{
if(XOBV[i]>0) xbup++;
if(XOBV[i]<0) xbdn++;
}
}
if(i==9)
{
if(xbup>=4)
{
trn=1;
XOBV[i]=xbup; arclr=ArrowUp; OBVMoveUp[0]=GetPrice(_Period,trn);
pricepos=OBVMoveUp[0];
cur=1;
fbar=iBarShift(_Symbol,0,cbartime,false);
}
else
if(xbdn>=4)
{
trn=-1;
XOBV[i]=xbdn; arclr=ArrowDn; OBVMoveDn[0]=GetPrice(_Period,trn);
pricepos=OBVMoveDn[0];
cur=-1;
fbar=iBarShift(_Symbol,0,cbartime,false);
}
else
{
XOBV[i]=0;
arclr=NTArrow;
OBVMoveDn[0]=0.0;
OBVMoveUp[0]=0.0;
pricepos=close[0];
cur=0;
fbar=iBarShift(_Symbol,0,time[0],false);
}
//--
if(cor>=0) CreateArrowLabel(CI,frtext+"_win_arrow_"+string(i),CharToString(108),"Wingdings",14,arclr,bcor,
txttf+i*scaleX+offsetX+8,arrtf+scaleY+offsetY+7,true);
}
//--
imnp=imnn;
}
//--
if(alerts==Yes||EmailAlert==Yes||sendnotify==Yes) Do_Alerts(cur,fbar);
if(displayinfo==Yes) ChartComm();
//--
//--- return value of prev_calculated for next call
return(rates_total);
}
//---------//
// Getting the applied price index shift
double GetAppliedPrice(int xtf,int nIndex)
{
//---
double dPrice=0.0;
//--
switch(obv_prc)
{
case PRICE_OPEN: dPrice=iOpen(_Symbol,xtf,nIndex); break;
case PRICE_HIGH: dPrice=iHigh(_Symbol,xtf,nIndex); break;
case PRICE_LOW: dPrice=iLow(_Symbol,xtf,nIndex); break;
case PRICE_CLOSE: dPrice=iClose(_Symbol,xtf,nIndex); break;
case PRICE_MEDIAN: dPrice=(iHigh(_Symbol,xtf,nIndex)+iLow(_Symbol,xtf,nIndex))/2.0; break;
case PRICE_TYPICAL: dPrice=(iHigh(_Symbol,xtf,nIndex)+iLow(_Symbol,xtf,nIndex)+iClose(_Symbol,xtf,nIndex))/3.0; break;
case PRICE_WEIGHTED: dPrice=(iHigh(_Symbol,xtf,nIndex)+iLow(_Symbol,xtf,nIndex)+2*iClose(_Symbol,xtf,nIndex))/4.0; break;
}
//--
return(dPrice);
//---
}
//---------//
// getting the price direction
int GetDirection(int xtf)
{
//---
int ret=0,
bar=4,
i;
RefreshRates();
//--
double OBV[];
ArrayResize(OBV,bar);
ArraySetAsSeries(OBV,true);
OBV[bar-1]=(double)iVolume(_Symbol,xtf,bar-1);
//--
for(i=bar-2; i>=0; i--)
{
double dCurrentPrice=GetAppliedPrice(xtf,i);
double dPreviousPrice=GetAppliedPrice(xtf,i+1);
if(dCurrentPrice==dPreviousPrice)
OBV[i]=OBV[i+1];
else
{
if(dCurrentPrice<dPreviousPrice)
OBV[i]=OBV[i+1]-(double)iVolume(_Symbol,xtf,i);
else
OBV[i]=OBV[i+1]+(double)iVolume(_Symbol,xtf,i);
}
}
//--
if(OBV[0]>OBV[1]) ret=1;
if(OBV[0]<OBV[1]) ret=-1;
//--
return(ret);
//---
}
//---------//
// getting the price position
double GetPrice(int xtf,int bb)
{
//---
int bar=(int)480/xtf < 9 ? 5 : (int)480/xtf;
if(bar>100) bar=100;
double ppos=0;
double hih[],
lol[];
ArrayResize(hih,bar);
ArrayResize(lol,bar);
ArraySetAsSeries(hih,true);
ArraySetAsSeries(lol,true);
//--
for(int x=bar-1; x>=0; x--)
{
hih[x]=iHigh(_Symbol,xtf,x);
lol[x]=iLow(_Symbol,xtf,x);
}
if(bb>0) {ppos=iLow(_Symbol,xtf,ArrayMinimum(lol,bar,0)); cbartime=iTime(_Symbol,xtf,ArrayMinimum(lol,bar,0));}
if(bb<0) {ppos=iHigh(_Symbol,xtf,ArrayMaximum(hih,bar,0)); cbartime=iTime(_Symbol,xtf,ArrayMaximum(hih,bar,0));}
//--
return(ppos);
//---
}
//---------//
void Do_Alerts(int fcur,int fb)
{
//--
cmnt=Minute();
if(cmnt!=pmnt)
{
//--
if(fcur==1)
{
msgText="On Balance Volume Up Start"+" at bars: "+string(fb);
posisi="Bullish";
sigpos="Open BUY Order";
}
else
if(fcur==-1)
{
msgText="On Balance Volume Down Start"+" at bars: "+string(fb);
posisi="Bearish";
sigpos="Open SELL Order";
}
else
{
msgText="On Balance Volume Signal Not Found!";
posisi="Not Found!";
sigpos="Wait for Confirmation!";
}
//--
if(fcur!=prv)
{
Print(iname,"--- "+_Symbol+" "+TF2Str(_Period)+": "+msgText+
"\n--- at: ",TimeToString(iTime(_Symbol,0,0),TIME_DATE|TIME_MINUTES)+" - "+sigpos);
//--
if(alerts==Yes)
Alert(iname,"--- "+_Symbol+" "+TF2Str(_Period)+": "+msgText+
"--- at: ",TimeToString(iTime(_Symbol,0,0),TIME_DATE|TIME_MINUTES)+" - "+sigpos);
//--
if(EmailAlert==Yes)
SendMail(iname,"--- "+_Symbol+" "+TF2Str(_Period)+": "+msgText+
"\n--- at: "+TimeToString(iTime(_Symbol,0,0),TIME_DATE|TIME_MINUTES)+" - "+sigpos);
//--
if(sendnotify==Yes)
SendNotification(iname+"--- "+_Symbol+" "+TF2Str(_Period)+": "+msgText+
"\n--- at: "+TimeToString(iTime(_Symbol,0,0),TIME_DATE|TIME_MINUTES)+" - "+sigpos);
//--
prv=fcur;
//pbartime=fbartime;
}
//--
pmnt=cmnt;
}
//--
return;
//---
}
//---------//
string TF2Str(int period)
{
switch(period)
{
//--
case PERIOD_M1: return("M1");
case PERIOD_M5: return("M5");
case PERIOD_M15: return("M15");
case PERIOD_M30: return("M30");
case PERIOD_H1: return("H1");
case PERIOD_H4: return("H4");
case PERIOD_D1: return("D1");
case PERIOD_W1: return("W1");
case PERIOD_MN1: return("MN");
//--
}
return(string(period));
}
//---------//
string AccountMode() // function: to known account trade mode
{
//----
//--- Demo, Contest or Real account
ENUM_ACCOUNT_TRADE_MODE account_type=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
//---
string trade_mode;
//--
switch(account_type)
{
case ACCOUNT_TRADE_MODE_DEMO:
trade_mode="Demo";
break;
case ACCOUNT_TRADE_MODE_CONTEST:
trade_mode="Contest";
break;
default:
trade_mode="Real";
break;
}
//--
return(trade_mode);
//----
} //-end AccountMode()
//---------//
void ChartComm() // function: write comments on the chart
{
//----
//--
Comment("\n :: Server Date Time : ",(string)Year(),".",(string)Month(),".",(string)Day(), " ",TimeToString(TimeCurrent(),TIME_SECONDS),
"\n ------------------------------------------------------------",
"\n :: Broker : ",TerminalCompany(),
"\n :: Acc. Name : ",AccountName(),
"\n :: Acc, Number : ",(string)AccountNumber(),
"\n :: Acc,TradeMode : ",AccountMode(),
"\n :: Acc. Leverage : 1 : ",(string)AccountLeverage(),
"\n :: Acc. Balance : ",DoubleToString(AccountBalance(),2),
"\n :: Acc. Equity : ",DoubleToString(AccountEquity(),2),
"\n --------------------------------------------",
"\n :: Indicator Name : ",iname,
"\n :: Currency Pair : ",_Symbol,
"\n :: Current Spread : ",IntegerToString(SymbolInfoInteger(_Symbol,SYMBOL_SPREAD),0),
"\n :: Signal Start : at bar ",string(fbar),
"\n :: Price Start : ",DoubleToString(pricepos,_Digits),
"\n :: Indicator Signal : ",posisi,
"\n :: Suggested : ",sigpos);
//---
ChartRedraw();
return;
//----
} //-end ChartComm()
//---------//
bool CreateArrowLabel(long chart_id,
string lable_name,
string label_text,
string font_model,
int font_size,
color label_color,
int chart_corner,
int x_cor,
int y_cor,
bool price_hidden)
{
//---
//--
ObjectDelete(chart_id,lable_name);
//--
if(!ObjectCreate(chart_id,lable_name,OBJ_LABEL,0,0,0,0,0))
{
Print(__FUNCTION__,
": failed to create \"Arrow Label\" sign! Error code = ",GetLastError());
return(false);
}
//--
ObjectSetString(chart_id,lable_name,OBJPROP_TEXT,label_text);
ObjectSetString(chart_id,lable_name,OBJPROP_FONT,font_model);
ObjectSetInteger(chart_id,lable_name,OBJPROP_FONTSIZE,font_size);
ObjectSetInteger(chart_id,lable_name,OBJPROP_COLOR,label_color);
ObjectSetInteger(chart_id,lable_name,OBJPROP_CORNER,chart_corner);
ObjectSetInteger(chart_id,lable_name,OBJPROP_XDISTANCE,x_cor);
ObjectSetInteger(chart_id,lable_name,OBJPROP_YDISTANCE,y_cor);
ObjectSetInteger(chart_id,lable_name,OBJPROP_HIDDEN,price_hidden);
//--- successful execution
return(true);
//--
}
//---------//
//+------------------------------------------------------------------+
Comments