#property copyright "Copyright © 2012, Gadi."
#property link      "Gadi @ CompIT mod by Chris Jungen"

// Constant definitions
#define INDICATOR_NAME "GAD_OBV"
#define INDICATOR_VERSION "2.3b"


#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 Lavender
#property indicator_color2 DodgerBlue
#property indicator_color3 Red

extern int TF = 0;
extern bool AlertsON = TRUE;
extern bool DrawChannel = TRUE;
extern string NameOfStartRangeLine = "OVBSTART";
extern string NameOfEndRangeLine = "OVBEND";

extern double PercentIncrease = 0.5;
int priceField = 0;
double bufOBV[];
double val;
double bufTopLevel[];
double bufBotLevel[];
double maxLevel;
double minLevel;
double maxLevelExt;
double minLevelExt;
double lastOVBvalue;

int j;
int level1 = 0;
int level2 = 0;
string gs_204;
int shiftStart = 0;
int shiftEnd = 0;
int shiftStartLast = 0;
int shiftEndLast = 0;

string indiename;
string objName;

datetime lastTimeUp;
datetime lastTimeDn;
bool firstTime;


int init()
{
    firstTime = true;
    lastTimeUp = 0;
    lastTimeDn = 0;

    SetIndexBuffer(0, bufOBV);
    SetIndexBuffer(1, bufTopLevel);
    SetIndexBuffer(2, bufBotLevel);
    SetIndexStyle(0, DRAW_LINE);
    SetIndexStyle(1, DRAW_LINE);
    SetIndexStyle(2, DRAW_LINE);
    IndicatorDigits(0);
    if (TF == 0)
        TF = Period();
    indiename = "Gadi_OBV_" + INDICATOR_VERSION + " cust. (TF = " + TF + " Min.)  ";
    IndicatorShortName(indiename);
    SetIndexLabel(0, indiename);
    SetIndexLabel(1, "Channel High");
    SetIndexLabel(2, "Channel Low");

    int xPos = 10;
    objName = "LBLOBVIX";
    ObjectCreate(objName, OBJ_LABEL, WindowFind(indiename), 0, 0);
    ObjectSet(objName, OBJPROP_CORNER, 1);
    ObjectSet(objName, OBJPROP_XDISTANCE, xPos);
    ObjectSet(objName, OBJPROP_YDISTANCE, 5);

    return (0);
}


int deinit()
{
    shiftStartLast = 0; // force arrayfill
    shiftEndLast = 0;
    ObjectDelete(objName);

    return (0);
}


int start()
{
    double curVal;
    double prevVal;
    int i, j;
    string labelTxt = "";

    int numBars = IndicatorCounted();
    if (numBars > 0)
        numBars--;
    int count = Bars - numBars - 1;

    for (i = count; i >= 0; i--)
    {
        if (i == Bars - 1)
            bufOBV[i] = iVolume(NULL, TF, i);
        else
        {
            curVal = GetCandleValue(priceField, i);
            prevVal = GetCandleValue(priceField, i + 1);
            if (curVal == prevVal)
                bufOBV[i] = bufOBV[i + 1];
            else
            {
                if (curVal < prevVal)
                {
                    if (iHigh(NULL, TF, i) - iLow(NULL, TF, i) > 0.0)
                    {
                        val = (iOpen(NULL, TF, i) - iClose(NULL, TF, i)) / (iHigh(NULL, TF, i) - iLow(NULL, TF, i));
                        bufOBV[i] = bufOBV[i + 1] - iVolume(NULL, TF, i) *val;
                        continue;
                    }
                    bufOBV[i] = bufOBV[i + 1];
                }
                else
                {
                    if (iHigh(NULL, TF, i) - iLow(NULL, TF, i) > 0.0)
                    {
                        val = (iClose(NULL, TF, i) - iOpen(NULL, TF, i)) / (iHigh(NULL, TF, i) - iLow(NULL, TF, i));
                        bufOBV[i] = bufOBV[i + 1] + iVolume(NULL, TF, i) *val;
                    }
                    else
                        bufOBV[i] = bufOBV[i + 1];
                }
            }
        }
    }


    if (DrawChannel == TRUE)
    {
        shiftStart = -1; // assume bars not found (mark them with -1)
        shiftEnd   = -1;

        // find start and end vertical line
        val = ObjectGet(NameOfStartRangeLine, OBJPROP_TIME1);
        if ( GetLastError() != 4202 )        // ERR_OBJECT_DOES_NOT_EXIST
            shiftStart = iBarShift( 0, 0, val, true );        // get candle index

        val = ObjectGet(NameOfEndRangeLine, OBJPROP_TIME1);
        if ( GetLastError() != 4202 )        // ERR_OBJECT_DOES_NOT_EXIST
            shiftEnd = iBarShift( 0, 0, val, true );        // get candle index


        if ( shiftStart > shiftEnd )        // make sure, start < end
        {
            int temp = shiftStart;
            shiftStart = shiftEnd;
            shiftEnd = temp;
        }

        // any user change? then clear old levels
        if ( shiftStart != shiftStartLast || shiftEnd != shiftEndLast )
        {
            ArrayInitialize(bufBotLevel, EMPTY_VALUE);
            ArrayInitialize(bufTopLevel, EMPTY_VALUE);
            shiftStartLast = shiftStart;
            shiftEndLast = shiftEnd;
        }

        if ( shiftStart != -1 && shiftEnd != -1 )
        {
            minLevel = bufOBV[shiftStart];
            maxLevel = bufOBV[shiftStart];
            for ( j = shiftStart + 1; j <= shiftEnd; j++ )
            {
                if ( minLevel > bufOBV[j] )
                    minLevel = bufOBV[j];
                if ( maxLevel < bufOBV[j] )
                    maxLevel = bufOBV[j];
            }

            for ( j = shiftStart; j <= shiftEnd; j++ )
            {
                bufBotLevel[j] = minLevel;
                bufTopLevel[j] = maxLevel;
            }

            maxLevelExt = maxLevel + MathAbs( maxLevel * PercentIncrease * 0.01 );
            minLevelExt = minLevel - MathAbs( minLevel * PercentIncrease * 0.01 );
            SetLevelValue( 0, maxLevelExt );
            SetLevelValue( 1, minLevelExt );

            labelTxt = "Num Bars in Range = " + (shiftEnd - shiftStart);

            // handle alerts
            if (AlertsON)
            {
                if (bufOBV[0] > maxLevelExt && lastOVBvalue <= maxLevelExt)
                {
                    if (Time[0] != lastTimeUp && !firstTime)
                    {
                        Alert("OBV Breakout UP on " + Symbol() + " period = " + Period());

                        lastTimeUp = Time[0];
                    }
                }
                if (bufOBV[0] < minLevelExt && lastOVBvalue >= minLevelExt)
                {
                    if (Time[0] != lastTimeDn && !firstTime)
                    {
                        Alert("OBV Breakout DOWN on " + Symbol() + " period = " + Period());

                        lastTimeDn = Time[0];
                    }
                }
            }


        }
        else
        {
            if (shiftStart ==  - 1 && shiftEnd ==  - 1)
                labelTxt = "Vertical bars named " + NameOfStartRangeLine + "," + NameOfEndRangeLine + " missing";
            if (shiftStart ==  - 1 && shiftEnd !=  - 1)
                labelTxt = "Vertical bar named " + NameOfStartRangeLine + " missing";
            if (shiftStart !=  - 1 && shiftEnd ==  - 1)
                labelTxt = "Vertical bar named " + NameOfEndRangeLine + " missing";
        }

    }
    else
    {
        SetLevelValue(0, 0);
        SetLevelValue(1, 0);
    }

    ObjectSetText(objName, labelTxt, 8, "Arial", Silver);


    lastOVBvalue = bufOBV[0];
    firstTime = false;

    /*
    if ( DrawChannel == TRUE )
    {
    level1 = 0;
    level2 = 0;
    Comment( "\nChannel Start: ", TimeString( StartHour ), ":", TimeString( StartMinute ), "\nChannel End: ", TimeString( EndHour ), ":", TimeString( EndMinute ));
    for ( int j = 0; j <= 1440; j++ )
    {
    if ( TimeHour( Time[j] ) == StartHour && TimeMinute( Time[j] ) == StartMinute )
    level1 = j;
    if ( TimeHour( Time[j] ) == EndHour && TimeMinute( Time[j] ) == EndMinute )
    level2 = j;
    if ( level1 > 0 )
    break;
    }
    maxLevel = bufOBV[level1];
    minLevel = bufOBV[level1];
    if ( level2 > 0 )
    {
    for ( j = level2+1; j <= level1; j++ )
    {
    maxLevel = MathMax( bufOBV[j], maxLevel );
    minLevel = MathMin( bufOBV[j], minLevel );
    }
    for ( j = level2+1; j <= level1; j++ )
    {
    bufTopLevel[j] = maxLevel;
    bufBotLevel[j] = minLevel;
    }
    SetLevelValue( 1, maxLevel+MathAbs( maxLevel * PercentIncrease*0.01 ));
    SetLevelValue( 2, minLevel-MathAbs( minLevel * PercentIncrease*0.01 ));
    }
    }
    else
    {
    Comment( "" );
    SetLevelValue( 1, 0 );
    SetLevelValue( 2, 0 );
    }
     */

    return (0);
}

double GetCandleValue(int ai_0, int ai_4)
{
    double ld_ret_8;
    switch (ai_0)
    {
        case 0:
            ld_ret_8 = iClose(NULL, TF, ai_4);
            break;
        case 1:
            ld_ret_8 = iOpen(NULL, TF, ai_4);
            break;
        case 2:
            ld_ret_8 = iHigh(NULL, TF, ai_4);
            break;
        case 3:
            ld_ret_8 = iLow(NULL, TF, ai_4);
            break;
        case 4:
            ld_ret_8 = (iHigh(NULL, TF, ai_4) + iLow(NULL, TF, ai_4)) / 2.0;
            break;
        case 5:
            ld_ret_8 = (iHigh(NULL, TF, ai_4) + iLow(NULL, TF, ai_4) + iClose(NULL, TF, ai_4)) / 3.0;
            break;
        case 6:
            ld_ret_8 = (iHigh(NULL, TF, ai_4) + iLow(NULL, TF, ai_4) + 2.0 * iClose(NULL, TF, ai_4)) / 4.0;
            break;
        default:
            ld_ret_8 = 0.0;
    }
    return (ld_ret_8);
}

/*
string TimeString( int ai_0 )
{
if ( StringLen( DoubleToStr( ai_0, 0 )) < 2 )
gs_204 = "0"+ai_0;
else
gs_204 = DoubleToStr( ai_0, 0 );
return ( gs_204 );
}
 */