Добрый день. В базе кодов есть индикатор RSI написанный разработчиками. У меня не получается вызвать его обычным способом. Спотыкается на строчке внутри индикатора:
Код
val_Up[I] = (val_Up[I-1] * (P-1) + Up[I]) / P
Вызываю так:
Код
DataSource("TQBR","RASP",INTERVAL_M5)
local num_candles=ds:Size()
func=RSI()
local a=func(num_candles, {Period=12, VType="Typical", round=7}, ds)
Вот сам индикатор. Спасибо за подсказки.
Код
Settings = {
Name = "*RSI (Relative Strength Index)",
round = "off",
Period = 14,
VType = "Close", --Open, High, Low, Close, Volume, Median, Typical, Weighted, Difference
line = {{
Name = "RSI",
Type = TYPE_LINE,
Color = RGB(255, 0, 0)
}
}
}
function Init()
func = RSI()
return #Settings.line
end
function OnCalculate(Index)
return func(Index, Settings)
end
function RSI() --Relative Strength I("RSI")
local Up = {}
local Down = {}
local val_Up = {}
local val_Down = {}
return function (I, Fsettings, ds)
local Out = nil
local Fsettings=(Fsettings or {})
local P = (Fsettings.Period or 14)
local VT = (Fsettings.VType or "Close")
local R = (Fsettings.round or "off")
if I == 1 then
Up[I] = 0
Down[I] = 0
end
if I>1 then
local Val = Value(I,VT,ds)
local ValPrev = Value(I-1,VT,ds)
if ValPrev < Val then
Up[I] = Val - ValPrev
else
Up[I] = 0
end
if ValPrev > Val then
Down[I] = ValPrev - Val
else
Down[I] = 0
end
if (I == P) or (I == P+1) then
local sumU = 0
local sumD = 0
for i = I-P+1, I do
sumU = sumU + Up[i]
sumD = sumD + Down[i]
end
val_Up[I] = sumU/P
val_Down[I] = sumD/P
end
if I > P+1 then
val_Up[I] = (val_Up[I-1] * (P-1) + Up[I]) / P
val_Down[I] = (val_Down[I-1] * (P-1) + Down[I]) / P
end
if I >= P then
Out = 100 / (1 + (val_Down[I] / val_Up[I]))
return rounding(Out, R)
end
end
end
end
function rounding(num, round)
if round and string.upper(round)== "ON" then round=0 end
if num and tonumber(round) then
local mult = 10^round
if num >= 0 then return math.floor(num * mult + 0.5) / mult
else return math.ceil(num * mult - 0.5) / mult end
else return num end
end
function Value(I,VType,ds)
local Out = nil
VType=(VType and string.upper(string.sub(VType,1,1))) or "A"
if VType == "O" then --Open
Out = (O and O(I)) or (ds and ds:O(I))
elseif VType == "H" then --High
Out = (H and H(I)) or (ds and ds:H(I))
elseif VType == "L" then --Low
Out = (L and L(I)) or (ds and ds:L(I))
elseif VType == "C" then --Close
Out = (C and C(I)) or (ds and ds:C(I))
elseif VType == "V" then --Volume
Out = (V and V(I)) or (ds and ds:V(I))
elseif VType == "M" then --Median
Out = ((Value(I,"H",ds) + Value(I,"L",ds)) / 2)
elseif VType == "T" then --Typical
Out = ((Value(I,"M",ds) * 2 + Value(I,"C",ds))/3)
elseif VType == "W" then --Weighted
Out = ((Value(I,"T",ds) * 3 + Value(I,"O",ds))/4)
elseif VType == "D" then --Difference
Out = (Value(I,"H",ds) - Value(I,"L",ds))
elseif VType == "A" then --Any
if ds then Out = ds[I] else Out = nil end
end
return Out
end
Индикатор RSI строится по EMA, которому нужен расчет по предыдущим значениям. Скорее всего проблема именно в этом. Прогоните цикл для корректного расчета for i=1,ds:Size() do a=func(i, {Period=12, VType="Typical", round=7}, ds) end
а как обратиться к конкретному бару? Скажем последнему или предпоследнему? из вашего кода получается что переменная a постоянно будет менять значение, так как идёт перебор i-элемента
На своём низком уровне понимания я разобрался. Получилось так:
Код
function main()
dofile ("C:\\Program Files (x86)\\Lua\\5.1\\lua\\RSI.lua")
while is_run do
stime=getSTime()
if stime==nil then stime=0 end
sleep (1)
if stime>100000 and stime<184000 then --не считаем вне сессии
func = RSI()
for sec in string.gmatch(ticker_list,"%a+") do
local rsi_count={}
ds = CreateDataSource(class, sec, INTERVAL_M5)
sleep (1000)
num_candles=ds:Size()
for i=1,num_candles do
rsi_count[i]=func(i, {Period=14, VType="Typical"}, ds)
end
indicator[sec].rsi_0 = rsi_count[num_candles]
indicator[sec].rsi_1 = rsi_count[num_candles-1]
indicator[sec].rsi_2 = rsi_count[num_candles-2]
и так далее
что самое противное (и не понятное), в нижеприведённом виде не работает! Ниже попытка считать не все бары, а только 50 последних.
Код
num_candles=ds:Size()
for i=num_candles-50,num_candles do
rsi_count[i]=func(i, {Period=14, VType="Typical"}, ds)
end
И ещё не понятно, рационально ли рассчитывать RSI в колбеке SetUpdateCallback? Я хочу запрашивать обновлённый RSI довольно редко - раз в секунду, скорость не нужна. С этой точки зрения, правильно ли помещать CreateDataSource внутри main в цикле перебора бумаг? Спасибо за советы.
Космонавт, Это Вы не уловили нить ответа. RSI требует согласно формуле, свои предыдущие значения. Это особенность данного индикатора. Даже если Вам надо только 50 последних свечей он в принципе не сможет Вам их дать не проведя расчет предыдущих. Просто такая формула.
Как по формуле узнать последние 50 значений X из 100 имеющихся? Никак. Просто потому что для расчета надо знать чему равно X1 и от него уже подсчитать все остальные.
Вот по этому, еще в четвертый раз повторяем.
Цитата
Sergey Gorokhov написал: Индикатор RSI строится по EMA, которому нужен расчет по предыдущим значениям.
Если Вам нужно получить последние 50 свечек, будьте добры предварительно подсчитать и первые свечки. Просто такая формула.