mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-20 03:28:05 +00:00
pine files
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Beta Function (BETA)", "BETA", overlay=false)
|
||||
|
||||
//@function Calculates the financial Beta indicator comparing src1 volatility to src2
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/beta.md
|
||||
//@param src1 series float Series to analyze
|
||||
//@param src2 series float src2 series to compare against
|
||||
//@param period simple int Lookback period for calculation
|
||||
//@returns float Beta value showing src1 volatility relative to src2
|
||||
//@optimized for performance and dirty data
|
||||
beta(series float src1, series float src2, simple int period) =>
|
||||
if period <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var float last_src1 = na
|
||||
var float last_src2 = na
|
||||
src1_return = last_src1 != 0 and not na(last_src1) ? (src1 - last_src1) / last_src1 : na
|
||||
bench_return = last_src2 != 0 and not na(last_src2) ? (src2 - last_src2) / last_src2 : na
|
||||
last_src1 := src1
|
||||
last_src2 := src2
|
||||
var int count = 0
|
||||
var float sum_sr = 0.0, var float sum_br = 0.0
|
||||
var float sum_sr2 = 0.0, var float sum_br2 = 0.0
|
||||
var float sum_sbr = 0.0
|
||||
var sr_buf = array.new_float(period)
|
||||
var br_buf = array.new_float(period)
|
||||
var int index = 0
|
||||
if not na(src1_return) and not na(bench_return)
|
||||
old_sr = array.get(sr_buf, index)
|
||||
old_br = array.get(br_buf, index)
|
||||
if count >= period
|
||||
sum_sr -= old_sr, sum_br -= old_br
|
||||
sum_sr2 -= old_sr * old_sr, sum_br2 -= old_br * old_br
|
||||
sum_sbr -= old_sr * old_br
|
||||
else
|
||||
count += 1
|
||||
sum_sr += src1_return, sum_br += bench_return
|
||||
sum_sr2 += src1_return * src1_return
|
||||
sum_br2 += bench_return * bench_return
|
||||
sum_sbr += src1_return * bench_return
|
||||
array.set(sr_buf, index, src1_return)
|
||||
array.set(br_buf, index, bench_return)
|
||||
index := (index + 1) % period
|
||||
if count > 0
|
||||
mean_sr = sum_sr / count
|
||||
mean_br = sum_br / count
|
||||
cov = (sum_sbr / count) - (mean_sr * mean_br)
|
||||
var_bench = (sum_br2 / count) - (mean_br * mean_br)
|
||||
if var_bench > 1e-10
|
||||
cov / var_bench
|
||||
else
|
||||
na
|
||||
else
|
||||
na
|
||||
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_symbol = input.symbol("SPY", "src2 Symbol")
|
||||
i_period = input.int(14, "Period", minval=1)
|
||||
i_src1 = input.source(close, "src1")
|
||||
|
||||
// Get src2 data
|
||||
src2Price = request.security(i_symbol, timeframe.period, close)
|
||||
|
||||
// Calculate beta
|
||||
beta_value = beta(i_src1, src2Price, i_period)
|
||||
|
||||
// Plot
|
||||
plot(beta_value, "Beta", color=color.yellow, linewidth=2)
|
||||
@@ -0,0 +1,35 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Cumulative Moving Average", "CMA", overlay=true)
|
||||
|
||||
//@function Calculates Cumulative Moving Average (Running Average / Cumulative Mean)
|
||||
//@doc Calculates the arithmetic mean of ALL data points seen so far.
|
||||
//@doc Uses Welford's algorithm for numerical stability, O(1) per update.
|
||||
//@param source Series to calculate CMA from
|
||||
//@returns CMA value - running mean of all historical values
|
||||
cma(series float source) =>
|
||||
// Persistent state
|
||||
var float mean = 0.0
|
||||
var int count = 0
|
||||
|
||||
float val = nz(source, mean)
|
||||
count += 1
|
||||
|
||||
// Welford's algorithm: M_n = M_(n-1) + alpha * (x_n - M_(n-1))
|
||||
float alpha = 1.0 / count
|
||||
float delta = val - mean
|
||||
mean := mean + alpha * delta
|
||||
|
||||
mean
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_source = input.source(close, "Source")
|
||||
|
||||
// Calculation
|
||||
cma_value = cma(i_source)
|
||||
|
||||
// Plot
|
||||
plot(cma_value, "CMA", color=color.yellow, linewidth=2)
|
||||
@@ -0,0 +1,56 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Covariance (COVARIANCE)", "COVARIANCE", overlay=false)
|
||||
|
||||
//@function Calculates covariance using single pass with circular buffer
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/covariance.md
|
||||
//@param src1 series float First series to analyze
|
||||
//@param src2 series float Second series to analyze
|
||||
//@param len simple int Lookback period for calculation
|
||||
//@returns float Covariance between src1 and src2
|
||||
//@optimized for performance using circular buffer
|
||||
covariance(series float src1, series float src2, simple int len) =>
|
||||
if len <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var int p = math.max(1, len)
|
||||
var array<float> buffer1 = array.new_float(p, na)
|
||||
var array<float> buffer2 = array.new_float(p, na)
|
||||
var int head = 0, var int count = 0
|
||||
var float sum1 = 0.0, var float sum2 = 0.0
|
||||
var float sumProd = 0.0
|
||||
float oldest1 = array.get(buffer1, head)
|
||||
float oldest2 = array.get(buffer2, head)
|
||||
if not na(oldest1) and not na(oldest2)
|
||||
sum1 -= oldest1
|
||||
sum2 -= oldest2
|
||||
sumProd -= oldest1 * oldest2
|
||||
count -= 1
|
||||
if not na(src1) and not na(src2)
|
||||
sum1 += src1
|
||||
sum2 += src2
|
||||
sumProd += src1 * src2
|
||||
count += 1
|
||||
array.set(buffer1, head, src1)
|
||||
array.set(buffer2, head, src2)
|
||||
else
|
||||
array.set(buffer1, head, na)
|
||||
array.set(buffer2, head, na)
|
||||
head := (head + 1) % p
|
||||
count > 1 ? (sumProd / count) - (sum1 / count) * (sum2 / count) : na
|
||||
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_source1 = input.source(close, "Source 1")
|
||||
i_source2_ticker = input.symbol("SPY", "Source 2 Ticker (e.g., SPY, AAPL)")
|
||||
i_period = input.int(20, "Period", minval=2)
|
||||
|
||||
i_source2 = request.security(i_source2_ticker, timeframe.period, close, lookahead=barmerge.lookahead_off)
|
||||
|
||||
// Calculation
|
||||
variance_value = covariance(i_source1, i_source2, i_period)
|
||||
|
||||
// Plot
|
||||
plot(variance_value, "Covariance", color=color.yellow, linewidth=2)
|
||||
@@ -0,0 +1,59 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Linear Regression (LINREG)", "LINREG", overlay=false, precision=8)
|
||||
|
||||
//@function Calculates linear regression and slope over the specified period
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/linreg.md
|
||||
//@param src Source series to calculate linear regression from
|
||||
//@param len Lookback period for the calculation
|
||||
//@returns Tuple containing [intercept, slope]
|
||||
linreg(series float src, simple int len) =>
|
||||
if len < 2
|
||||
[na, na]
|
||||
else
|
||||
var float lastValid = na
|
||||
var array<float> buf = array.new_float(len, 0.0)
|
||||
var int count = 0
|
||||
var int head = 0
|
||||
float curr = src
|
||||
if na(curr) and not na(lastValid)
|
||||
curr := lastValid
|
||||
if not na(curr)
|
||||
lastValid := curr
|
||||
if not na(curr)
|
||||
array.set(buf, head, curr)
|
||||
if count < len
|
||||
count := count + 1
|
||||
head := (head + 1) % len
|
||||
float n = count
|
||||
if n < 2
|
||||
[na, na]
|
||||
else
|
||||
int start = count < len ? 0 : head
|
||||
float sumY = 0.0, sumXY = 0.0
|
||||
for i = 0 to int(n) - 1
|
||||
int idx = (start + i) % len
|
||||
float y_val = array.get(buf, idx)
|
||||
sumY += y_val
|
||||
sumXY += i * y_val
|
||||
float sumX = 0.5 * (n - 1) * n
|
||||
float sumX2 = (n - 1) * n * (2 * n - 1) / 6.0
|
||||
float D = n * sumX2 - sumX * sumX
|
||||
float s = D != 0 ? (n * sumXY - sumX * sumY) / D : na
|
||||
float intercept = (sumY / n) - s * ((n - 1) / 2)
|
||||
float lr = intercept + s * (n - 1)
|
||||
[lr, s]
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_period = input.int(14, "Period", minval=2)
|
||||
i_source = input.source(close, "Source")
|
||||
|
||||
// Calculation: Assign tuple elements.
|
||||
[lr, slope] = linreg(i_source, i_period)
|
||||
|
||||
// Plot
|
||||
plot(lr, "LinReg", color=color.yellow, linewidth=2)
|
||||
// plot(slope, "Slope", color=color.orange, linewidth=2, plot.style_histogram)
|
||||
@@ -0,0 +1,42 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Median", "MEDIAN", overlay=false, precision=8)
|
||||
|
||||
//@function Calculates the median of a series over a lookback period.
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/median.md
|
||||
//@param src series float Input data series.
|
||||
//@param len simple int Lookback period (must be > 0).
|
||||
//@returns series float The median of the series over the period, or na if insufficient valid data.
|
||||
median(series float src, simple int len) =>
|
||||
if len <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
var array<float> values_in_window = array.new_float(0)
|
||||
array.clear(values_in_window) // Clear from previous bar's calculation
|
||||
for i = 0 to len - 1
|
||||
val = src[i]
|
||||
if not na(val)
|
||||
array.push(values_in_window, val)
|
||||
int n = array.size(values_in_window)
|
||||
float result = na
|
||||
if n > 0
|
||||
array.sort(values_in_window) // Sort the array
|
||||
if n % 2 == 1 // Odd number of elements
|
||||
result := array.get(values_in_window, n / 2)
|
||||
else // Even number of elements
|
||||
float mid1 = array.get(values_in_window, n / 2 - 1)
|
||||
float mid2 = array.get(values_in_window, n / 2)
|
||||
result := (mid1 + mid2) / 2.0
|
||||
result
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_source = input.source(close, "Source")
|
||||
i_length = input.int(14, "Period", minval=1)
|
||||
|
||||
// Calculation
|
||||
median_value = median(i_source, i_length)
|
||||
|
||||
// Plot
|
||||
plot(median_value, "Median", color=color.new(color.orange, 0, color=color.yellow, linewidth=2), linewidth=2)
|
||||
@@ -0,0 +1,84 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Skewness (SKEW)", "SKEW", overlay=false, precision=6)
|
||||
|
||||
//@function Calculates the skewness of a source series over a specified period.
|
||||
// Skewness is a measure of the asymmetry of the probability distribution of a real-valued random variable about its mean.
|
||||
// This implementation calculates the population skewness (Fisher-Pearson coefficient g1).
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/skew.md
|
||||
//@param src The source series.
|
||||
//@param len The lookback period. Must be > 2.
|
||||
//@returns The skewness value.
|
||||
//@optimized Uses efficient rolling calculations for mean, variance, and the third central moment.
|
||||
skew(series float src, simple int len) =>
|
||||
if len <= 2
|
||||
runtime.error("Length must be greater than 2 for Skewness calculation.")
|
||||
var float sum_m = 0.0
|
||||
var array<float> buffer_m = array.new_float(len)
|
||||
var int head_m = 0
|
||||
if bar_index >= len
|
||||
sum_m -= array.get(buffer_m, head_m)
|
||||
float current_src_nz = nz(src)
|
||||
sum_m += current_src_nz
|
||||
array.set(buffer_m, head_m, current_src_nz)
|
||||
head_m := (head_m + 1) % len
|
||||
|
||||
float mean_val = na
|
||||
if bar_index >= len - 1
|
||||
mean_val := sum_m / len
|
||||
else
|
||||
mean_val := sum_m / (bar_index + 1)
|
||||
float dev = src - mean_val
|
||||
var float sum_v = 0.0
|
||||
var array<float> buffer_v = array.new_float(len)
|
||||
var int head_v = 0
|
||||
float dev_sq_nz = nz(math.pow(dev, 2))
|
||||
if bar_index >= len
|
||||
sum_v -= array.get(buffer_v, head_v)
|
||||
sum_v += dev_sq_nz
|
||||
array.set(buffer_v, head_v, dev_sq_nz)
|
||||
head_v := (head_v + 1) % len
|
||||
float variance_val = na
|
||||
if bar_index >= len - 1
|
||||
variance_val := sum_v / len
|
||||
else
|
||||
variance_val := sum_v / (bar_index + 1)
|
||||
float stddev_val = variance_val > 1e-9 ? math.sqrt(variance_val) : 0.0
|
||||
var float sum_s3 = 0.0
|
||||
var array<float> buffer_s3 = array.new_float(len)
|
||||
var int head_s3 = 0
|
||||
float dev_cubed_nz = nz(math.pow(dev, 3))
|
||||
if bar_index >= len
|
||||
sum_s3 -= array.get(buffer_s3, head_s3)
|
||||
sum_s3 += dev_cubed_nz
|
||||
array.set(buffer_s3, head_s3, dev_cubed_nz)
|
||||
head_s3 := (head_s3 + 1) % len
|
||||
float m3 = na
|
||||
if bar_index >= len - 1
|
||||
m3 := sum_s3 / len
|
||||
else
|
||||
m3 := sum_s3 / (bar_index + 1)
|
||||
float skew_val = na
|
||||
if not na(m3) and not na(stddev_val)
|
||||
if stddev_val > 1e-9
|
||||
float stddev_cubed = math.pow(stddev_val, 3)
|
||||
if stddev_cubed != 0
|
||||
skew_val := m3 / stddev_cubed
|
||||
else
|
||||
skew_val := 0.0
|
||||
else
|
||||
skew_val := 0.0
|
||||
skew_val
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_source = input.source(close, "Source")
|
||||
i_length = input.int(20, "Length", minval=3) // Minval 3 for skewness
|
||||
|
||||
// Calculation
|
||||
skewValue = skew(i_source, i_length)
|
||||
|
||||
// Plot
|
||||
plot(skewValue, "Skewness", color=color.yellow, linewidth=2)
|
||||
@@ -0,0 +1,42 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Standard Deviation (STDDEV)", "STDDEV", overlay=false)
|
||||
|
||||
//@function Calculates the standard deviation using a single pass with a circular buffer.
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/stddev.md
|
||||
//@param src {series float} Source series.
|
||||
//@param len {int} Lookback length. `len` > 0.
|
||||
//@returns {series float} Standard deviation of `src` for `len` bars back. Returns `na` if not enough data.
|
||||
stddev(series float src, int len) =>
|
||||
if len <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var int p = math.max(1, len)
|
||||
var array<float> buffer = array.new_float(p, na)
|
||||
var int head = 0, var int count = 0
|
||||
var float sum = 0.0, var float sumSq = 0.0
|
||||
float oldest = array.get(buffer, head)
|
||||
if not na(oldest)
|
||||
sum -= oldest
|
||||
sumSq -= oldest * oldest
|
||||
count -= 1
|
||||
float val = nz(src)
|
||||
sum += val
|
||||
sumSq += val * val
|
||||
count += 1
|
||||
array.set(buffer, head, val)
|
||||
head := (head + 1) % p
|
||||
count > 1 ? math.sqrt(math.max(0.0, (sumSq / count) - math.pow(sum / count, 2))) : 0.0
|
||||
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_period = input.int(14, "Period", minval=1) // Default period 14
|
||||
i_source = input.source(close, "Source")
|
||||
|
||||
// Calculation
|
||||
stddev_value = stddev(i_source, i_period)
|
||||
|
||||
// Plot
|
||||
plot(stddev_value, "StdDev", color=color.yellow, linewidth=2) // Changed color
|
||||
@@ -0,0 +1,59 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Rolling Sum", "SUM", overlay=false)
|
||||
|
||||
//@function Calculates Rolling Sum over a period using Kahan-Babuška algorithm
|
||||
//@doc Calculates the sum of the last n values with high numerical precision.
|
||||
//@doc Uses Kahan-Babuška summation for machine-epsilon accuracy.
|
||||
//@param source Series to calculate sum from
|
||||
//@param length Number of bars to sum
|
||||
//@returns Rolling sum of the last 'length' values
|
||||
rolling_sum(series float source, simple int length) =>
|
||||
// Persistent state
|
||||
var float sum = 0.0
|
||||
var float c = 0.0 // First-order compensation
|
||||
var float cc = 0.0 // Second-order compensation
|
||||
|
||||
float val = nz(source, 0.0)
|
||||
float oldVal = bar_index >= length ? nz(source[length], 0.0) : 0.0
|
||||
|
||||
// Kahan-Babuška subtract old value
|
||||
if bar_index >= length
|
||||
float yS = -oldVal - c
|
||||
float tS = sum + yS
|
||||
c := tS - sum - yS
|
||||
sum := tS
|
||||
|
||||
float zS = c - cc
|
||||
float ttS = sum + zS
|
||||
cc := ttS - sum - zS
|
||||
sum := ttS
|
||||
|
||||
// Kahan-Babuška add new value
|
||||
float yA = val - c
|
||||
float tA = sum + yA
|
||||
c := tA - sum - yA
|
||||
sum := tA
|
||||
|
||||
float zA = c - cc
|
||||
float ttA = sum + zA
|
||||
cc := ttA - sum - zA
|
||||
sum := ttA
|
||||
|
||||
sum
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_length = input.int(14, "Length", minval=1)
|
||||
i_source = input.source(close, "Source")
|
||||
|
||||
// Calculation
|
||||
sum_value = rolling_sum(i_source, i_length)
|
||||
|
||||
// Equivalent built-in for comparison (disabled by default)
|
||||
// sum_builtin = math.sum(i_source, i_length)
|
||||
|
||||
// Plot
|
||||
plot(sum_value, "Sum", color=color.yellow, linewidth=2)
|
||||
@@ -0,0 +1,41 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Variance, Dispersion or Spread (VARIANCE)", "VARIANCE", overlay=false)
|
||||
|
||||
//@function variance
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/statistics/variance.md
|
||||
//@param src {series float} Source series.
|
||||
//@param len {int} Lookback length. `len` > 0.
|
||||
//@returns {series float} Variance of `src` for `len` bars back. Returns 0 if not enough data.
|
||||
variance(series float src, int len) =>
|
||||
if len <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var int p = math.max(1, len)
|
||||
var array<float> buffer = array.new_float(p, na)
|
||||
var int head = 0, var int count = 0
|
||||
var float sum = 0.0, var float sumSq = 0.0
|
||||
float oldest = array.get(buffer, head)
|
||||
if not na(oldest)
|
||||
sum -= oldest
|
||||
sumSq -= oldest * oldest
|
||||
count -= 1
|
||||
float val = nz(src)
|
||||
sum += val
|
||||
sumSq += val * val
|
||||
count += 1
|
||||
array.set(buffer, head, val)
|
||||
head := (head + 1) % p
|
||||
count > 1 ? math.max(0.0, (sumSq / count) - math.pow(sum / count, 2)) : 0.0
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
// Inputs
|
||||
i_period = input.int(14, "Period", minval=1)
|
||||
i_source = input.source(close, "Source")
|
||||
|
||||
// Calculation
|
||||
variance_value = variance(i_source, i_period)
|
||||
|
||||
// Plot
|
||||
plot(variance_value, "Var", color=color.yellow, linewidth=2)
|
||||
Reference in New Issue
Block a user