#VM_Ord_Volume_v01
#by GrOwEx
#growex: I've read a book by Tim Ord....about price and volume
#growex: and i've written a study that calculates average volume on a swing...
#growex: it is similar to Weis Wave
#growex: WeisWave indicator calculates total volume of swing and TimOrd's one
#adapted from ZigZagSign study.
#calculate average volume on each candle
declare upper;
input price = close;
input reversalAmount = 1.0;
input showBubbles = no;
input showLabel = no;
input volumedivider = 1000;
Assert(reversalAmount > 0, "'reversal amount' should be positive: " + reversalAmount);
def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(price), 0, barNumber));
def state = {default init, undefined, uptrend, downtrend};
def minMaxPrice;
if (GetValue(state, 1) == GetValue(state.init, 0)) {
minMaxPrice = price;
state = state.undefined;
} else if (GetValue(state, 1) == GetValue(state.undefined, 0)) {
if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
state = state.downtrend;
minMaxPrice = price;
} else if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
state = state.uptrend;
minMaxPrice = price;
} else {
state = state.undefined;
minMaxPrice = GetValue(minMaxPrice, 1);
}
} else if (GetValue(state, 1) == GetValue(state.uptrend, 0)) {
if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
state = state.downtrend;
minMaxPrice = price;
} else {
state = state.uptrend;
minMaxPrice = Max(price, GetValue(minMaxPrice, 1));
}
} else {
if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
state = state.uptrend;
minMaxPrice = price;
} else {
state = state.downtrend;
minMaxPrice = Min(price, GetValue(minMaxPrice, 1));
}
}
def isCalculated = GetValue(state, 0) != GetValue(state, 1) and barNumber >= 1;
def futureDepth = barCount - barNumber;
def tmpLastPeriodBar;
if (isCalculated) {
if (futureDepth >= 1 and GetValue(state, 0) == GetValue(state, -1)) {
tmpLastPeriodBar = fold lastPeriodBarI = 2 to futureDepth + 1 with lastPeriodBarAcc = 1
while lastPeriodBarAcc > 0
do if (GetValue(state, 0) != GetValue(state, -lastPeriodBarI))
then -lastPeriodBarAcc
else lastPeriodBarAcc + 1;
} else {
tmpLastPeriodBar = 0;
}
} else {
tmpLastPeriodBar = Double.NaN;
}
def lastPeriodBar = if (!IsNaN(tmpLastPeriodBar)) then -AbsValue(tmpLastPeriodBar) else -futureDepth;
def currentPriceLevel;
def currentPoints;
if (state == state.uptrend and isCalculated) {
currentPriceLevel =
fold barWithMaxOnPeriodI = lastPeriodBar to 1 with barWithMaxOnPeriodAcc = minMaxPrice
do Max(barWithMaxOnPeriodAcc, GetValue(minMaxPrice, barWithMaxOnPeriodI));
currentPoints =
fold maxPointOnPeriodI = lastPeriodBar to 1 with maxPointOnPeriodAcc = Double.NaN
while IsNaN(maxPointOnPeriodAcc)
do if (GetValue(price, maxPointOnPeriodI) == currentPriceLevel)
then maxPointOnPeriodI
else maxPointOnPeriodAcc;
} else if (state == state.downtrend and isCalculated) {
currentPriceLevel =
fold barWithMinOnPeriodI = lastPeriodBar to 1 with barWithMinOnPeriodAcc = minMaxPrice
do Min(barWithMinOnPeriodAcc, GetValue(minMaxPrice, barWithMinOnPeriodI));
currentPoints =
fold minPointOnPeriodI = lastPeriodBar to 1 with minPointOnPeriodAcc = Double.NaN
while IsNaN(minPointOnPeriodAcc)
do if (GetValue(price, minPointOnPeriodI) == currentPriceLevel)
then minPointOnPeriodI
else minPointOnPeriodAcc;
} else if (!isCalculated and (state == state.uptrend or state == state.downtrend)) {
currentPriceLevel = GetValue(currentPriceLevel, 1);
currentPoints = GetValue(currentPoints, 1) + 1;
} else {
currentPoints = 1;
currentPriceLevel = GetValue(price, currentPoints);
}
plot "ZZ$" = if (barNumber == barCount or barNumber == 1) then price else if (currentPoints == 0) then currentPriceLevel else Double.NaN;
def zzSave = if !IsNaN("ZZ$") then price else GetValue(zzSave, 1);
def chg = price - GetValue(zzSave, 1);
def isUp = chg >= 0;
def isConf = AbsValue(chg) >= reversalAmount or (IsNaN(GetValue("ZZ$", 1)) and GetValue(isConf, 1));
rec v = if isUp then volume + v[1] else 0;
rec vd = if !isUp then volume + vd[1] else 0;
rec countup = if isUp then countup[1] + 1 else 0;
rec countdn = if !isUp then countdn[1] + 1 else 0;
def vline = countup;
def vdline = countdn;
def valueup = if v > v[-1] then Round(v / volumedivider, 2) else Double.NaN;
def valuedn = if vd > vd[-1] then Round(vd / volumedivider, 2) else Double.NaN;
def valuecountup = if vline > vline[-1] then vline else Double.NaN;
def valuecountdn = if vdline > vdline[-1] then vdline else Double.NaN;
#def avg = Round(valueup / valuecountup, 2);
#plot ord_up = Round(valueup / valuecountup, 2);
#plot ord_dn = Round(valuedn / valuecountdn, 2);
#ord_dn.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);
#ord_up.SetPaintingStrategy(PaintingStrategy.VALUES_ABOVE);
"ZZ$".EnableApproximation();
"ZZ$".DefineColor("Up Trend", Color.UPTICK);
"ZZ$".DefineColor("Down Trend", Color.DOWNTICK);
"ZZ$".DefineColor("Undefined", Color.DARK_ORANGE);
"ZZ$".AssignValueColor(if !isConf then "ZZ$".Color("Undefined") else if isUp then "ZZ$".Color("Up Trend") else "ZZ$".Color("Down Trend"));
DefineGlobalColor("Unconfirmed", Color.DARK_ORANGE);
DefineGlobalColor("Up", Color.UPTICK);
DefineGlobalColor("Down", Color.DOWNTICK);
AddChartBubble(showBubbles and !IsNaN("ZZ$") and barNumber != 1, price,
if v > v[-1] then Round(valueup / valuecountup, 2) else if vd > vd[-1] then Round(valuedn / valuecountdn, 2) else double.nan, if !isConf then GlobalColor("Unconfirmed") else if isUp then GlobalColor("Up") else GlobalColor("Down"), isUp);
AddLabel(showLabel and barNumber != 1, (if isConf then "Confirmed " else "Unconfirmed ") + "ZigZag: " + chg, if !isConf then GlobalColor("Unconfirmed") else if isUp then GlobalColor("Up") else GlobalColor("Down"));