I'm trying to convert pine script stdev to Python code but it seems I'm doing it wrong.
Pine script:
//the same on pine
isZero(val, eps) => abs(val) <= eps
SUM(fst, snd) =>
EPS = 1e-10
res = fst + snd
if isZero(res, EPS)
res := 0
else
if not isZero(res, 1e-4)
res := res
else
15
pine_stdev(src, length) =>
avg = sma(src, length)
sumOfSquareDeviations = 0.0
for i = 0 to length - 1
sum = SUM(src[i], -avg)
sumOfSquareDeviations := sumOfSquareDeviations + sum * sum
stdev = sqrt(sumOfSquareDeviations / length)
Python code:
import talib as ta
def isZero(val, eps):
if abs(val) <= eps:
return True
else:
return False
def SUM(fst, snd):
EPS = 1e-10
res = fst + snd
if isZero(res, EPS):
res += 0
else:
if not isZero(res, 1e-4):
res = res
else:
res = 15
return res
def pine_stdev(src, length):
avg = ta.SMA(src, length)
sumOfSquareDeviations = 0.0
for i in range(length - 1):
s = SUM(src.iloc[i], -avg.iloc[i])
sumOfSquareDeviations = sumOfSquareDeviations + s * s
stdev = (sumOfSquareDeviations / length)*(sumOfSquareDeviations / length)
What am I doing wrong? And why does the SUM function return 15?
2 Answers 2
Trading View has made a mistake in the code on the site. The number "15" should be written as "1e-5". You can use this code:
def SUM(fst, snd):
EPS = 1e-10
res = fst + snd
if isZero(res, EPS):
res = 0
else:
if not isZero(res, 1e-4):
res = res
else:
res = 1e-5
return res
Comments
I was able to figure it out using numpy and using vectorization which is faster than doing a for loop for every bar
I start at length - 1 because before length is just nan values so you don't need to work with those
on tradingview stdev website they say na values in the source series are ignored; the function calculates on the length quantity of non-na values.
https://www.tradingview.com/pine-script-reference/v5/#fun_ta.stdev
import numpy as np
import plotly.graph_objects as go
def sma_calc(source: np.array, length: int):
arr = np.cumsum(source, dtype=np.float_)
arr[length:] = arr[length:] - arr[:-length]
sma = np.full_like(source, np.nan)
sma[length - 1 :] = arr[length - 1 :] / length
return sma
def stdev(source, length):
avg = sma_calc(source=source, length=length)
sum_square_dev = np.full_like(avg, np.nan)
looper = length - 1
for i in range(looper, avg.size):
res = source[i - looper : i + 1] + -avg[i]
res_2 = np.where(np.absolute(res) <= 1e-10, 0, res)
sum = np.where((np.absolute(res_2) < 1e-4) & (np.absolute(res_2) > 1e-10), 1e-5, res_2)
sum_square_dev[i] = (sum * sum).sum()
final = np.sqrt(sum_square_dev / length)
return final
multi = 2
length = 20
basis = sma_calc(source=close, length=length)
dev = multi * stdev(source=close, length=length)
upper = basis + dev
lower = basis - dev
multi = 2
length = 20
basis = sma_calc(source=close, length=length)
dev = multi * stdev(source=close, length=length)
upper = basis + dev
lower = basis - dev
datetimes = pd.to_datetime(candles[:, 0], unit="ms")
fig = go.Figure(
data=[
go.Candlestick(
x=datetimes,
open=candles[:, 1],
high=candles[:, 2],
low=candles[:, 3],
close=candles[:, 4],
name="Candles",
),
go.Scatter(
x=datetimes,
y=upper,
name="upper",
),
go.Scatter(
x=datetimes,
y=basis,
name="bases",
),
go.Scatter(
x=datetimes,
y=lower,
name="lower",
),
]
)
fig.update_layout(height=600, xaxis_rangeslider_visible=False)
fig.show()