//Volume source inputs
groupSource = "Volume source"
i_symbolBool = input.bool(false, "Override chart volume with custom symbol volume", group=groupSource)
i_symbolVolume = input.symbol("BTCUSDT", "Symbol for volume data", group=groupSource)
//Timeframe inputs
groupTf = "Timeframe settings"
i_tf1 = input.timeframe("1", "LTF for charts <= 30 min", group=groupTf, tooltip="Choose which timeframes are used for volume data when viewed within a given timeframe bracket. E.g. volume data is pulled from 1 minute timeframe when viewing charts at or below 30 min. The lower the chosen timeframe, the more precision you get, but with the cost of less historical data.")
i_tf2 = input.timeframe("5", "LTF for charts > 30 min & <= 3 hours", group=groupTf)
i_tf3 = input.timeframe("15", "LTF for charts > 3 hours & <= 8 hours", group=groupTf)
i_tf4 = input.timeframe("60", "LTF for charts > 8 hours & <= 1D", group=groupTf)
i_tf5 = input.timeframe("120", "LTF for charts > 1D & <= 3D", group=groupTf)
i_tf6 = input.timeframe("240", "LTF for charts > 3D", group=groupTf)
i_highlightDomBuyVol = input.bool(false, "Buy volume threshold exceeded", group=groupAnomaly, inline="buyvol")
i_domBuyVolCol = input.color(color.teal, "", group=groupAnomaly, inline="buyvol", tooltip="Colorizes candles on your chart where selected volume anomaly has occured. Useful for gaining reference from the past to get an idea what to expect in the future. Note that context matters a lot.")
//Directional volume % of total volume and directional active volume % of total active volume
buyVolPerc = (totalBuyVol / totalVol)
sellVolPerc = (totalSellVol / totalVol)
buyVolPercA = (totalBuyVolA / totalVolA)
sellVolPercA = (totalSellVolA / totalVolA)
//Open and close position
closePos = (close - low) / (high - low)
openPos = (open - low) / (high - low)
//Engulfings. Defined by higher high, lower low with a close at 60%/40% of bar range (0% being the very low, 100% being the very high)
engulfingUp = high > high[1] and low < low[1] and closePos > 0.60
engulfingDown = high > high[1] and low < low[1] and closePos < 0.40
//Wicks. Defined by higher high, higher low or lower high, lower low with a close at 60%/40% and open at 40%/60% of bar range.
wickUp = high < high[1] and low < low[1] and closePos > 0.60 and openPos > 0.40
wickDown = high > high[1] and low > low[1] and closePos < 0.40 and openPos < 0.60
//Expansions. Defined by higher high, higher low or lower high, lower low with a close at 70% of bar range and range 1.5x higher than previous.
barRange = high - low
expUp = high > high[1] and low > low[1] and closePos > 0.70 and barRange > (barRange[1] * 1.5)
expDown = high < high[1] and low < low[1] and closePos < 0.30 and barRange > (barRange[1] * 1.5)
//Specified price related condition
candleFormStudy = i_multiCondition and i_candleFormation == "Close ▲" and i_candleFormationBool ? close > close[1] :
i_multiCondition and i_candleFormation == "Close ▼" and i_candleFormationBool ? close < close[1] :
i_multiCondition and i_candleFormation == "Reversal ▲" and i_candleFormationBool ? wickUp or engulfingUp :
i_multiCondition and i_candleFormation == "Reversal ▼" and i_candleFormationBool ? wickDown or engulfingDown :
i_multiCondition and i_candleFormation == "Expansion ▲" and i_candleFormationBool ? expUp :
i_multiCondition and i_candleFormation == "Expansion ▼" and i_candleFormationBool ? expDown : na(close) == false
//Spcified anomaly
studiedAnomaly = highBuyVolStudy and highBuyAVolStudy and highSellVolStudy and highSellAVolStudy and volDivStudy and candleFormStudy and volMultStudy
//No studies selected condition
allStudiesNa = i_highlightDomBuyVol == false and i_highlightDomABuyVol == false and
i_highlightDomSellVol == false and i_highlightDomASellVol == false and i_highlightDivergence == false and i_candleFormationBool == false and i_volMultiplierBool == false
//Defining multi-condition anomaly
multiCondAnomaly = i_multiCondition and studiedAnomaly and allStudiesNa == false
//Initializing anomaly counter var int anomalyCount = 0
//If multi-condition anomaly found, add 1 to counter
if multiCondAnomaly
anomalyCount += 1
//Anomaly counter text for table
countText = i_multiCondition and allStudiesNa == true ? "Matches: " + str.tostring(0) + "┃" :
i_multiCondition and allStudiesNa == false ? "Matches: " + str.tostring(anomalyCount) + "┃" : ""
//If volume data is NA (holidays, weekends etc.), plot no text instead of NaN
dataNotNa = na(totalVol) == false and totalVol > 0
aDataNotNa = na(totalVolA) == false and totalVolA > 0
//Label text for active volume direction and () to indicate divergences
ActiveText = totalBuyVolA >= totalSellVolA and ActiveVolDisagreement == false ? "+" :
totalBuyVolA >= totalSellVolA and ActiveVolDisagreement == true ? "(+)" :
totalBuyVolA < totalSellVolA and ActiveVolDisagreement == false ? "-" :
totalBuyVolA < totalSellVolA and ActiveVolDisagreement == true ? "(-)" : ""
//Label text for indicating high active volume
ActiveText2 = highBuyVolA or highSellVolA ? "▲" : ""
//Line to fill gap between current bar index and next bar index, where real-time volume columns are halfway plotted.
line.new(bar_index, 0, bar_index+1, 0, xloc=xloc.bar_index, color=color.rgb(38, 38, 38), width=18)
//Grouped
alertcondition((highBuyVol or highSellVol) and barstate.isconfirmed, "Buy volume or sell volume threshold exceeded", "Buy volume or sell volume threshold exceeded anomaly detected.")
alertcondition((highBuyVolA or highSellVolA) and barstate.isconfirmed, "Active buy volume or active sell volume threshold exceeded", "Active buy volume or sell volume threshold exceeded anomaly detected.")
alertcondition((highBuyVolA or highSellVolA or highBuyVol or highSellVol or ActiveVolDisagreement) and barstate.isconfirmed, "Any volume anomaly (any type of volume threshold exceeded or volume/active volume divergence)", "A volume anomaly (any type of volume threshold exceeded or volume/active volume divergence) detected.")