mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-02 03:37:42 +00:00
86fe32a682
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat> Co-authored-by: Warp <agent@warp.dev>
71 lines
2.3 KiB
Plaintext
71 lines
2.3 KiB
Plaintext
// The MIT License (MIT)
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Close-to-Close Volatility (CCV)", "CCV", overlay=false)
|
|
|
|
//@function Calculates Close-to-Close Volatility using closing price returns
|
|
//@param length Period for volatility calculations
|
|
//@param method Smoothing method (1=SMA, 2=EMA, 3=WMA)
|
|
//@returns float Volatility value
|
|
//@optimized Beta precomputation for RMA warmup compensation
|
|
ccv(simple int length, simple int method) =>
|
|
if length <= 0
|
|
runtime.error("Length must be greater than 0")
|
|
if method < 1 or method > 3
|
|
runtime.error("Method must be 1 (SMA), 2 (EMA), or 3 (WMA)")
|
|
var int p = math.max(1, length)
|
|
var int head = 0
|
|
var int count = 0
|
|
var array<float> buffer = array.new_float(p, na)
|
|
var float sum = 0.0
|
|
var float wsum = 0.0
|
|
float priceReturn = math.log(close / close[1])
|
|
float oldest = array.get(buffer, head)
|
|
if not na(oldest)
|
|
sum -= oldest
|
|
count -= 1
|
|
sum += priceReturn
|
|
count += 1
|
|
array.set(buffer, head, priceReturn)
|
|
head := (head + 1) % p
|
|
float mean = nz(sum / count)
|
|
float squaredSum = 0.0
|
|
for i = 0 to length - 1
|
|
float val = array.get(buffer, (head - i - 1 + p) % p)
|
|
if not na(val)
|
|
squaredSum += math.pow(val - mean, 2)
|
|
float annualizedStdDev = math.sqrt(squaredSum / count) * math.sqrt(252)
|
|
float alpha = 1.0 / float(length)
|
|
float beta = 1.0 - alpha
|
|
var float EPSILON = 1e-10
|
|
var float raw_rma = 0.0
|
|
var float e = 1.0
|
|
float result = na
|
|
if method == 1
|
|
result := annualizedStdDev
|
|
else if method == 2
|
|
raw_rma := (raw_rma * (length - 1) + annualizedStdDev) / length
|
|
e *= beta
|
|
result := e > EPSILON ? raw_rma / (1.0 - e) : raw_rma
|
|
else
|
|
float sumWeight = length * (length + 1) / 2
|
|
float weightedSum = 0.0
|
|
float weight = length
|
|
for i = 0 to length - 1
|
|
weightedSum += annualizedStdDev * weight
|
|
weight -= 1.0
|
|
result := weightedSum / sumWeight
|
|
result
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_length = input.int(20, "Length", minval=1, maxval=500, tooltip="Number of bars for volatility calculation")
|
|
i_method = input.int(1, "Method", minval=1, maxval=3, tooltip="1=SMA, 2=EMA, 3=WMA")
|
|
|
|
// Calculation
|
|
ccvValue = ccv(i_length, i_method)
|
|
|
|
// Plot
|
|
plot(ccvValue, "CCV", color=color.yellow, linewidth=2)
|