// Downloaded From https://www.WiseStockTrader.com
// TerryH - afl@rivelle.com 3/9/2012
// Move AvgPrice computation before the loop so it's only done ONCE in an array.
// Replace SetBarsRequired with only computing visible bars...back to the start of the oldest time period even if it's "off screen".
// These 2 changes make it run in 1/12th the time. No doubt database dependent on how much time is saved.// VWAP code that also plots 3 standard deviations.
// I think more savings is possible, but will take a harder look to find.

// NOTE: the code is SLOOOOWWWW...can someone help speed it up?
// I tried my best, but can't really do much with the two for-loops...
//
// LarryJR - ljr500@hotmail.com

SetBarsRequired(-2,-2);
_TRACE( "!CLEAR!" );		//For trouble-shooting

//PlotOHLC( O, H, L, C, "Price", colorDefault, styleCandle );
_SECTION_BEGIN("Price");
    SetChartOptions(0,chartShowArrows|chartShowDates);
    _N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
    Plot( C, "Close", ParamColor("Color", colorBlack ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
_SECTION_END();

//Just do this once as an array. Saves 40% the compute time from ~ 1 second to ~ .6 seconds
AvgPrice = ( O + H + L + C ) / 4;	

// Store true/false based on a new calendar day...
// Added Weekly, Monthly breaks. 
// Also for futures, need to add break at new trading Day, which is NOT midnight.

period = ParamList( "What period?", "Daily|Weekly|Monthly", 0 );

switch ( period )
{

case "Daily":
    newPeriod = Day() != Ref( Day(), -1 );
    break;

case "Weekly":
    newPeriod = DayOfWeek() == 0 AND Ref( DayOfWeek(), -1 ) != 0;
    break;

case "Monthly":
    newPeriod = Month() != Ref( Month(), -1 );
    break;
}

//--Setup-----------

bi = BarIndex();		// Just shorthand
StartBar = StrToNum("2");	//1st bar == 0. Set to 1 so Ref(xxx, -1) doesn't give an error
EndBar = BarCount -1; 
ExtraBarsRequired = 0;

//CalcRangeAll = ParamToggle( "Calc ALL or VISIBLE?", "VISIBLE|ALL", 0 );		//Option to compute all bars in case of Backtesting or Explore if you add this kind of code.

if ( Status( "action" ) < 3 )		// Limit to visible range unless we're doing Backtest, Explore, Scan, Optimize.
    // In other words, for viewing/commentary we only compute what we can see.
    // Saves add'l 85% the compute time from ~ .6 second to ~ .09 seconds.
{
    //This code finds only the VISIBLE chart area, which may or may not be the most recent day. This let's me look at any day for evaulation purposes.
    FirstVisibleBar = FirstVisibleValue( bi );
    _TRACE( "1st Visible: " + FirstVisibleBar );
    LastVisibleBar = LastVisibleValue( bi );						//Testing shows this returns BarIndex (0 based) values. So, if you want to use in a loop the last value IS the last bar.
    VisibleBars = LastVisibleBar - FirstVisibleBar;			//Used in trouble-shooting.
    _TRACE( "1st Visible: " + FirstVisibleBar + "    Last Visible: " + LastVisibleBar + "    #bars: " + VisibleBars );

    StartBar = FirstVisibleBar;		//We get variable results when there are not 2 periods of data available so we won't show them at all.
    EndBar = LastVisibleBar;
    flag = StrToNum( "0" );				//Force a numeric value

    for ( k = FirstVisibleBar; k > 0; k-- )
    {
        if ( newPeriod[k] )
        {
            flag++;

            if ( flag == 2 ) 							//Need to lookback 2 periods if possible
            {
                StartBar = k;							//Set starting location
                k = 0;										//End the loop
            }
        }
    }

    if ( flag < 2 )												//We have less than 2 periods of history to the left, so we must start displaying no sooner than the 1st newPeriod that is on-screen
    {
        for ( k = 1; k < EndBar; k++ )
        {
            if ( newPeriod[k] )
            {
                StartBar = k;
                k = EndBar;
            }
        }
    }
}

_TRACE("1st Required: " + StartBar + "    Last Required: " + EndBar + "    Extra Bars: " + ExtraBarsRequired + "    Bar in Database: " + BarCount );

// Initialize loop variables
SumPriceVolume = 0;
totVolume = 0;
VWAP = 0;
stddev = 0;
newPeriodindex = EndBar;		//Move way out until we find a "real one"
Variance = 0;
//Initialize the plotted variables for early data we cannot compute without getting variable results.
VWAP = C[1];
stddev_1_pos = stddev_1_neg = stddev_2_pos = stddev_2_neg = stddev_3_pos = stddev_3_neg = C[1];

// we must use a loop here because we need to save the vwap for each bar to calc the variance later

for ( i = startBar; i <= EndBar; i++ )
{
    // only want to reset our values at the start of a new period
    if ( newPeriod[i] )
    {
        SumPriceVolume = 0;
        totVolume = 0;
        newPeriodindex = i;  // this is the index at the start of a new period
        Variance = 0;
    }

    // Sum of Volume*price for each bar
    sumPriceVolume += AvgPrice[i] * ( Volume[i] );

    // running total of volume each bar
    totVolume += ( Volume[i] );

    if ( totVolume[i] > 0 )
    {
        VWAP[i] = Sumpricevolume / totVolume ;
        VWAPtemp = VWAP[i];
    }

    // now the hard part...calculate the variance...
    // a separate calc from the start of each day - note it requires the vwap from above
    // also note, we calculate starting at the first bar in the new day to today to the curent bar
    Variance = 0;

    for ( j = newPeriodindex; j < i; j++ )
    {
        Variance += ( Volume[j] / totVolume ) * ( Avgprice[j] - VWAPtemp ) * ( Avgprice[j] - VWAPtemp );
    }

    sqrtVariance = sqrt( Variance );

    stddev_1_pos[i] = VWAPtemp + sqrtVariance;
    stddev_1_neg[i] = VWAPtemp - sqrtVariance;

    stddev_2_pos[i] = VWAPtemp + sqrtVariance * 2;
    stddev_2_neg[i] = VWAPtemp - sqrtVariance * 2;

    stddev_3_pos[i] = VWAPtemp + sqrtVariance * 3;
    stddev_3_neg[i] = VWAPtemp - sqrtVariance * 3;
}

//Prior period VWAP centerline
PPC = ValueWhen( newPeriod == True, Ref(VWAP, -1), 1);
Plot ( PPC, "PPC", colorBlue, styleDots|styleNoLine|styleNoRescale );
Plot ( VWAP, "VWAP", colorBlue, styleLine );
Plot ( stddev_1_pos, "VWAP_std+1", ColorRGB( 128, 0, 0 ), styleDashed );
Plot ( stddev_1_neg, "VWAP_std-1", ColorRGB( 0, 128, 0 ), styleDashed );
Plot ( stddev_2_pos, "VWAP_std+2", colorRed, styleDashed | styleThick );
Plot ( stddev_2_neg, "VWAP_std-2", colorGreen, styleDashed | styleThick );
Plot ( stddev_3_pos, "VWAP_std+3", colorDarkRed, styleDots | styleThick );
Plot ( stddev_3_neg, "VWAP_std-3", colorDarkGreen, styleDots | styleThick );

_SECTION_BEGIN("VAP");
segments = IIf( Interval() < inDaily, Day(), Month() );
segments = segments != Ref( segments , -1 );

PlotVAPOverlayA( segments , Param("Lines", 300, 100, 1000, 1 ), Param("Width", 80, 1, 100, 1 ), ParamColor("Color", ColorRGB(255,245,200) ), ParamToggle("Side", "Left|Right" ) | 2 * ParamToggle("Style", "Fill|Lines", 0) | 4*ParamToggle("Z-order", "On top|Behind", 1 ) );
Plot(segments, "", colorLightGrey, styleHistogram | styleOwnScale );
_SECTION_END();