@blackphoenixslo/trading-bot-framework
Version:
A comprehensive framework for building trading bots with support for TradingView, various market data providers, MongoDB, Google Sheets, and Discord alerts.
441 lines (309 loc) • 14.9 kB
Plain Text
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Celje_2300
import TradingView/ta/5
//@version=5
// @description It's a library of the aproximations of a price and noice redusction.
library("math")
// @function DFT3: Discrete Fourier Transform with 3 points
// @param x: Array of input values
// @param y: Array of imaginary values
// @param _dir: Direction parameter
// @returns DFT1 value
DFT3(x, y, _dir) =>
x_0 = array.get(x, 0) + array.get(x, 1) + array.get(x, 2)
x_1 = array.get(x, 0) + array.get(x, 1) * math.cos( -2 * math.pi * _dir / 3 ) - array.get(y, 1) * math.sin( -2 * math.pi * _dir / 3 ) + array.get(x, 2) * math.cos( -4 * math.pi * _dir / 3 ) - array.get(y, 2) * math.sin( -4 * math.pi * _dir / 3 )
x_2 = array.get(x, 0) + array.get(x, 1) * math.cos( -4 * math.pi * _dir / 3 ) - array.get(y, 1) * math.sin( -4 * math.pi * _dir / 3 ) + array.get(x, 2) * math.cos( -8 * math.pi * _dir / 3 ) - array.get(y, 2) * math.sin( -8 * math.pi * _dir / 3 )
y_0 = array.get(x, 0) + array.get(x, 1) + array.get(x, 2)
y_1 = array.get(x, 0) + array.get(x, 1) * math.sin( -2 * math.pi * _dir / 3 ) + array.get(y, 1) * math.cos( -2 * math.pi * _dir / 3 ) + array.get(x, 2) * math.sin( -4 * math.pi * _dir / 3 ) + array.get(y, 2) * math.cos( -4 * math.pi * _dir / 3 )
y_2 = array.get(x, 0) + array.get(x, 1) * math.sin( -4 * math.pi * _dir / 3 ) + array.get(y, 1) * math.cos( -4 * math.pi * _dir / 3 ) + array.get(x, 2) * math.sin( -8 * math.pi * _dir / 3 ) + array.get(y, 2) * math.cos( -8 * math.pi * _dir / 3 )
div = _dir == 1 ? 3 : _dir
array.set(x, 0, x_0 / div)
array.set(x, 1, x_1 / div)
array.set(x, 2, x_2 / div)
array.set(y, 0, y_0 / div)
array.set(y, 1, y_1 / div)
array.set(y, 2, y_2 / div)
export DFT3(int _dir, series float xval = close) =>
x = array.new_float(3, 0.0)
y = array.new_float(3, 0.0)
for i = 0 to 2
array.set(x, i, xval[i])
array.set(y, i, 0.0)
x_0 = array.get(x, 0) + array.get(x, 1) + array.get(x, 2)
x_1 = array.get(x, 0) + array.get(x, 1) * math.cos( -2 * math.pi * _dir / 3 ) - array.get(y, 1) * math.sin( -2 * math.pi * _dir / 3 ) + array.get(x, 2) * math.cos( -4 * math.pi * _dir / 3 ) - array.get(y, 2) * math.sin( -4 * math.pi * _dir / 3 )
x_2 = array.get(x, 0) + array.get(x, 1) * math.cos( -4 * math.pi * _dir / 3 ) - array.get(y, 1) * math.sin( -4 * math.pi * _dir / 3 ) + array.get(x, 2) * math.cos( -8 * math.pi * _dir / 3 ) - array.get(y, 2) * math.sin( -8 * math.pi * _dir / 3 )
y_0 = array.get(x, 0) + array.get(x, 1) + array.get(x, 2)
y_1 = array.get(x, 0) + array.get(x, 1) * math.sin( -2 * math.pi * _dir / 3 ) + array.get(y, 1) * math.cos( -2 * math.pi * _dir / 3 ) + array.get(x, 2) * math.sin( -4 * math.pi * _dir / 3 ) + array.get(y, 2) * math.cos( -4 * math.pi * _dir / 3 )
y_2 = array.get(x, 0) + array.get(x, 1) * math.sin( -4 * math.pi * _dir / 3 ) + array.get(y, 1) * math.cos( -4 * math.pi * _dir / 3 ) + array.get(x, 2) * math.sin( -8 * math.pi * _dir / 3 ) + array.get(y, 2) * math.cos( -8 * math.pi * _dir / 3 )
div = _dir == 1 ? 3 : _dir
array.set(x, 0, x_0 / div)
array.set(x, 1, x_1 / div)
array.set(x, 2, x_2 / div)
array.set(y, 0, y_0 / div)
array.set(y, 1, y_1 / div)
array.set(y, 2, y_2 / div)
dft1 = math.sqrt(math.pow(array.get(x, 0), 2) + math.pow(array.get(y, 0), 2))
dft1
// @function DFT2: Discrete Fourier Transform with 2 points
// @param x: Array of input values
// @param y: Array of imaginary values
// @param _dir: Direction parameter
// @returns DFT1 value
DFT2(x, y, _dir) =>
x_0 = array.get(x, 0) + array.get(x, 1)
x_1 = array.get(x, 0) + array.get(x, 1) * math.cos( -2 * math.pi * _dir / 2 ) - array.get(y, 1) * math.sin( -2 * math.pi * _dir / 2 )
y_0 = array.get(x, 0) + array.get(x, 1)
y_1 = array.get(x, 0) + array.get(x, 1) * math.sin( -2 * math.pi * _dir / 2 ) + array.get(y, 1) * math.cos( -2 * math.pi * _dir / 2 )
div = _dir == 1 ? 3 : _dir
array.set(x, 0, x_0 / div)
array.set(x, 1, x_1 / div)
array.set(y, 0, y_0 / div)
array.set(y, 1, y_1 / div)
export DFT2(int _dir , series float xval = close) =>
x = array.new_float(2, 0.0)
y = array.new_float(2, 0.0)
for i = 0 to 1
array.set(x, i, xval[i])
array.set(y, i, 0.0)
x_0 = array.get(x, 0) + array.get(x, 1)
x_1 = array.get(x, 0) + array.get(x, 1) * math.cos( -2 * math.pi * _dir / 2 ) - array.get(y, 1) * math.sin( -2 * math.pi * _dir / 2 )
y_0 = array.get(x, 0) + array.get(x, 1)
y_1 = array.get(x, 0) + array.get(x, 1) * math.sin( -2 * math.pi * _dir / 2 ) + array.get(y, 1) * math.cos( -2 * math.pi * _dir / 2 )
div = _dir == 1 ? 3 : _dir
array.set(x, 0, x_0 / div)
array.set(x, 1, x_1 / div)
array.set(y, 0, y_0 / div)
array.set(y, 1, y_1 / div)
dft1 = math.sqrt(math.pow(array.get(x, 0), 2) + math.pow(array.get(y, 0), 2))
dft1
// @function FFT: Fast Fourier Transform
// @param xval: Array of input values
// @returns DFT1 value
export FFT(series float xval = close) =>
N = 3
x = array.new_float(N, 0.0)
y = array.new_float(N, 0.0)
for i = 0 to N - 1
array.set(x, i, xval[i])
array.set(y, i, 0.0)
DFT3(x, y, 1)
dft1 = math.sqrt(math.pow(array.get(x, 0), 2) + math.pow(array.get(y, 0), 2))
dft1
// @function DTF32: Combined Discrete Fourier Transforms
// @param xval: Array of input values
// @returns DFT1 value
export DTF32(series float xval = close) =>
N = 3
x = array.new_float(N, 0.0)
y = array.new_float(N, 0.0)
for i = 0 to N - 1
array.set(x, i, xval[i])
array.set(y, i, 0.0)
DFT3(x, y, 2)
DFT2(x, y, 1)
dft1 = math.sqrt(math.pow(array.get(x, 0), 2) + math.pow(array.get(y, 0), 2))
dft1
// @function whitenoise: Ehler's Universal Oscillator with White Noise
// @param indic_: Input series for the oscillator
// @param _devided: Divisor for oscillator calculations
// @param minEmaLength: Minimum EMA length
// @param maxEmaLength: Maximum EMA length
// @param src: Source series
// @returns Smoothed indicator value
export whitenoise(series float indic_ , int _devided = 10, int minEmaLength = 1, int maxEmaLength = 8 , series float src = close ) =>
var filt = float(na)
indic = indic_
w = (src - src[2]) / 2
a = math.sqrt(2) * math.pi / _devided
b = math.cos(math.sqrt(2) * 180 / _devided)
c2 = 2 * math.pow(a, 2) * b
c3 = math.pow(a, 4)
c1 = 1 - 2 * math.pow(a, 2) * math.cos(b) + math.pow(a, 4)
filt := na(filt[1]) ? 0 : c1 * (w + nz(w[1])) / 2.0 + c2 * nz(filt[1]) - c3 * nz(filt[2])
// Smoothness (Reduce noise)
var emaLength = 1 //input(1, "EMA Length", group = "VZO")
uniL = filt > 0
vzoL = indic_ > indic_[1]
// Dynamically adjust EMA length based on conditions
emaLength := emaLength -1
if (uniL and vzoL) or (not uniL and not vzoL)
emaLength := emaLength + 2
// Reset EMA length to default if it exceeds the limits
if emaLength > maxEmaLength or emaLength < minEmaLength
emaLength := maxEmaLength - 1
indic := ta.ema2(indic_, emaLength)
indic
// @function whitenoise: Ehler's Universal Oscillator with White Noise and DFT1
// @param indic_: Input series for the oscillator
// @param dft1: DFT1 value
// @param _devided: Divisor for oscillator calculations
// @param minEmaLength: Minimum EMA length
// @param maxEmaLength: Maximum EMA length
// @param src: Source series
// @returns Smoothed indicator value
export whitenoise(series float indic_ , series float dft1 , int _devided = 10, int minEmaLength = 1, int maxEmaLength = 8 , series float src = close) =>
w = (dft1*src - dft1[2]*src[2]) / math.sqrt(math.pow(math.abs(src- src[2]),2) + math.pow(math.abs(dft1[0]- dft1[2]),2))
//w = (close - close[2]) / 2
indic = indic_
var filt = float(na)
a = math.sqrt(2) * math.pi / _devided
b = math.cos(math.sqrt(2) * 180 / _devided)
c2 = 2 * math.pow(a, 2) * b
c3 = math.pow(a, 4)
c1 = 1 - 2 * math.pow(a, 2) * math.cos(b) + math.pow(a, 4)
filt := na(filt[1]) ? 0 : c1 * (w*dft1 + nz(w[1]*dft1[1])) / 2.0 /math.abs(dft1[1]-dft1[0]) + c2 * nz(filt[1]) - c3 * nz(filt[2])
//filt := na(filt[1]) ? 0 : c1 * (w*dft1 + nz(w[1]*dft1[1])) /math.sqrt(
// math.pow(math.abs(w- w[1]),2) + math.pow(math.abs(dft1[0]- dft1[1]),2)
// ) + c2 * nz(filt[1]) + c3 * nz(filt[2])
//filt := na(filt[1]) ? 0 : c1 * (w + nz(w[1])) / 2.0 + c2 * nz(filt[1]) + c3 * nz(filt[2])
// Smoothness (Reduce noise)
var emaLength = 1 //input(1, "EMA Length", group = "VZO")
uniL = filt > 0
vzoL = indic_ > indic_[1]
// Dynamically adjust EMA length based on conditions
emaLength := emaLength -1
if (uniL and vzoL) or (not uniL and not vzoL)
emaLength := emaLength + 2
// Reset EMA length to default if it exceeds the limits
if emaLength > maxEmaLength or emaLength < minEmaLength
emaLength := maxEmaLength - 1
indic := ta.ema2(indic_, emaLength)
indic
// @function smooth: Smoothing function with DFT1
// @param dft1: DFT1 value
// @param indic__: Optional input for indicator (default is close)
// @param _devided: Divisor for smoothing calculations
// @param minEmaLength: Minimum EMA length
// @param maxEmaLength: Maximum EMA length
// @param src: Source series
// @returns Smoothed series
export smooth( series float dft1 , series float indic__ = na , int _devided = 10, int minEmaLength = 1, int maxEmaLength = 8 , series float src = close) =>
w = (dft1*src - dft1[2]*src[2]) / math.sqrt(math.pow(math.abs(src- src[2]),2) + math.pow(math.abs(dft1[0]- dft1[2]),2))
//w = (close - close[2]) / 2
indic = src
var filt = float(na)
aprox = FFT()
indic_ = na(indic__) ? aprox : indic__
a = math.sqrt(2) * math.pi / _devided
b = math.cos(math.sqrt(2) * 180 / _devided)
c2 = 2 * math.pow(a, 2) * b
c3 = math.pow(a, 4)
c1 = 1 - 2 * math.pow(a, 2) * math.cos(b) + math.pow(a, 4)
filt := na(filt[1]) ? 0 : c1 * (w*dft1 + nz(w[1]*dft1[1])) / 2.0 /math.abs(dft1[1]-dft1[0]) + c2 * nz(filt[1]) - c3 * nz(filt[2])
//filt := na(filt[1]) ? 0 : c1 * (w*dft1 + nz(w[1]*dft1[1])) /math.sqrt(
// math.pow(math.abs(w- w[1]),2) + math.pow(math.abs(dft1[0]- dft1[1]),2)
// ) + c2 * nz(filt[1]) + c3 * nz(filt[2])
//filt := na(filt[1]) ? 0 : c1 * (w + nz(w[1])) / 2.0 + c2 * nz(filt[1]) + c3 * nz(filt[2])
// Smoothness (Reduce noise)
var emaLength = 1 //input(1, "EMA Length", group = "VZO")
uniL = filt > 0
vzoL = indic_ > indic_[1]
// Dynamically adjust EMA length based on conditions
emaLength := emaLength -1
if (uniL and vzoL) or (not uniL and not vzoL)
emaLength := emaLength + 2
// Reset EMA length to default if it exceeds the limits
if emaLength > maxEmaLength or emaLength < minEmaLength
emaLength := maxEmaLength - 1
indic := ta.ema2(src, emaLength)
indic
// @function vzo_ema: Volume Zone Oscillator with EMA smoothing
// @param src: Source series
// @param len: Length parameter for EMA
// @returns VZO value
export vzo_ema(series float src, int len) =>
dvol = math.sign(src - src[2]) * volume //chicken dinner
dvma = ta.ema(dvol, len) //ema
vma = ta.ema(volume, len)
VZO_1 = vma != 0 ? 100 * dvma / vma : 0
// @function vzo_sma: Volume Zone Oscillator with SMA smoothing
// @param src: Source series
// @param len: Length parameter for SMA
// @returns VZO value
export vzo_sma(series float src, int len) =>
dvol = math.sign(src - src[2]) * volume //chicken dinner
dvma = ta.sma(dvol, len) //ema
vma = ta.sma(volume, len)
VZO_1 = vma != 0 ? 100 * dvma / vma : 0
// @function vzo_wma: Volume Zone Oscillator with WMA smoothing
// @param src: Source series
// @param len: Length parameter for WMA
// @returns VZO value
export vzo_wma(series float src, int len) =>
dvol = math.sign(src - src[2]) * volume //chicken dinner
dvma = ta.wma(dvol, len) //ema
vma = ta.sma(volume, len)
VZO_1 = vma != 0 ? 100 * dvma / vma : 0
// @function alma2: Arnaud Legoux Moving Average 2
// @param series: Input series
// @param windowsize: Size of the moving average window
// @param offset: Offset parameter
// @param sigma: Sigma parameter
// @returns ALMA value
alma2(series, windowsize, offset, sigma) =>
m = offset * (windowsize - 1)
//m = math.floor(offset * (windowsize - 1)) // Used as m when math.floor=true
s = windowsize / sigma
norm = 0.0
sum = 0.0
for i = 0 to windowsize - 1
weight = math.exp(-1 * math.pow(i - m, 2) / (2 * math.pow(s, 2)))
norm := norm + weight
sum := sum + series[windowsize - i - 1] * weight
sum / norm
//Wavelet
// @function Wavelet: Wavelet Transform
// @param len: Length parameter for ALMA
// @param src: Source series
// @returns Wavelet-transformed series
export Wavelet(int len = 16, series float src = close )=>
r = src * (1 + ta.alma(ta.change(src)/ src, len, 0.77, 6))
// @function Wavelet_std: Wavelet Transform with Standard Deviation
// @param len: Length parameter for ALMA
// @param offset: Offset parameter for ALMA
// @param mag: Magnitude parameter for standard deviation
// @param src: Source series
// @returns Wavelet-transformed series
export Wavelet_std(int len = 20, float offset = 0.5, int mag = 2, series float src = close )=>
std_dev = ta.stdev(src, len ,true)
sigma_for_alma = std_dev * float(mag)
alm = alma2(ta.change(src)/ src, len, offset, sigma_for_alma)
close * (alm + 1)
// @function Fisher_WMA: Fisher Transform with WMA smoothing
// @param src: Source series
// @_n1: Parameter for Fisher Transform
// @_n2: Parameter for Fisher Transform
// @returns Transformed series
export Fisher_WMA(series float src = close, int _n1 = 3 , int _n2 = 2)=>
_lambda = _n1 / _n2
_alpha = _lambda * (_n1 - 1) / (_n1 - _lambda)
_ma1 = ta.wma(src, _n1)
_ma2 = ta.wma(_ma1, _n2)
_src = (1 + _alpha) * _ma1 - _alpha * _ma2
// @function Fisher_EMA: Fisher Transform with EMA smoothing
// @param src: Source series
// @_n1: Parameter for Fisher Transform
// @_n2: Parameter for Fisher Transform
// @returns Transformed series
export Fisher_EMA(series float src = close, int _n1 = 3 , int _n2 = 2)=>
_alpha = _n1 / _n2 * (_n1 - 1) / (_n1 - _n1 / _n2)
_ma1 = ta.ema(src, _n1)
_ma2 = ta.ema(_ma1, _n2)
_src = (1 + _alpha) * _ma1 - _alpha * _ma2
// @function InverseFisher_Z_Score_aprox: Inverse Fisher Transform with Z-Score approximation
// @param len: Length parameter for Z-Score
// @param src: Source series
// @returns Transformed series
export InverseFisher_Z_Score_aprox(int len = 3 , series float src = close ) =>
z = (src - ta.sma(src,len))/ta.stdev(src,len)
f = (((math.exp(2*z) - 1)/(math.exp(2*z) + 1) + 1)*50 - 50)/100
r = src * (1+f)
// @function InverseFisher_Z_Score_aprox_Smoothed: Inverse Fisher Transform with Z-Score approximation and smoothing
// @param len: Length parameter for Z-Score
// @param src1: Source series for smoothing
// @returns Transformed and smoothed series
export InverseFisher_Z_Score_aprox_Smoothed(int len = 3 , series float src1 = close ) =>
src = smooth(src1)
z = (src - ta.sma(src,len))/ta.stdev(src,len)
f = (((math.exp(2*z) - 1)/(math.exp(2*z) + 1) + 1)*50 - 50)/100
r = src * (1+f)