Не пойму, в чем проблема.. Выдает ошибку attempt to compare number with nil когда индикатор растет или падает и не обнаруживает пиков\впадин При успешном обнаружении пика\впадины выдает текстовое сообщение как положено Код:
require("w32") Settings = { Tiker = "\210\232\234\229\240", Name = "Kalman SndMsg", Mode = 6, KF = 50, line = { { Name = "Kalman", Color = RGB(0, 255, 0), Type = TYPE_LINE, Width = 2 } } } function Init() return 1 end i = 0 value = 0 count = 0 function OnCalculate(_ARG_0_) if _ARG_0_ == 1 then kalman ={} Distance = 0 Error = 0 value = dValue(1, Settings.Mode) Velocity = 0 i = 0 count = Size() end if _ARG_0_ > 1 then if _ARG_0_ > i then i = _ARG_0_ Distance = dValue(i, Settings.Mode) - value Error = value + Distance * math.sqrt(Settings.KF / 1000) Velocity = Velocity + Distance * (Settings.KF / 1000) value = Error + Velocity kalman[i] = value
if kalman[i-1] < kalman[i-2] and kalman[i-2] >= kalman[i-3] then if _ARG_0_ >= count then message(Settings.Tiker .. ": DOWN trend", 1) w32.MessageBeep(w32.MB_OK) count = _ARG_0_ end end
if kalman[i-1] > kalman[i-2] and kalman[i-2] <= kalman[i-3] then if _ARG_0_ >= count then message(Settings.Tiker .. ": UP trend", 1) w32.MessageBeep(w32.MB_OK) count = _ARG_0_ end end
end end return kalman[i] end
function dValue(_ARG_0_, _ARG_1_) if (_ARG_1_ or 0) == 1 then return O(_ARG_0_) elseif (_ARG_1_ or 0) == 2 then return H(_ARG_0_) elseif (_ARG_1_ or 0) == 3 then return L(_ARG_0_) elseif (_ARG_1_ or 0) == 0 then return C(_ARG_0_) elseif (_ARG_1_ or 0) == 4 then return (H(_ARG_0_) + L(_ARG_0_)) / 2 elseif (_ARG_1_ or 0) == 5 then return (H(_ARG_0_) + L(_ARG_0_) + C(_ARG_0_)) / 3 elseif (_ARG_1_ or 0) == 6 then return (H(_ARG_0_) + L(_ARG_0_) + 2 * C(_ARG_0_)) / 4 else return C(_ARG_0_) end end
Как минимум, уже ошибка в том что Вы берете значения kalman[i-1], kalman[i-2], kalman[i-3] тогда когда их может не быть. раз i это номер свечки, следует добавить условие if i>4 then и только после этого продолжать код.
Странно именно то, что когда пик или впадина образуется, то сообщение выводится корректно и ошибки нет. Ошибка возникает только когда условие if kalman[i-1] < kalman[i-2] and kalman[i-2] >= kalman[i-3] then или if kalman[i-1] > kalman[i-2] and kalman[i-2] <= kalman[i-3] then не выполняется.
torque написал: Но ведь выше в начале цикла есть присвоение переменной i номера текущего бара.
ну да, а если будет когда появится второй бар?
_ARG_0_ = 2 ...
if _ARG_0_ > 1 then if _ARG_0_ > i then i = _ARG_0_ kalman[i] = value if kalman[i-1] < kalman[i-2] and kalman[i-2] >= kalman[i-3] then
чему будет равно kalman[i-2]? а kalman[i-3]?
Цитата
torque написал: По поводу >=4 попробовал, ничего не изменилось
Надо не "пробовать", а исправлять и если не помогло смотреть дальше. Что попадает в kalman и что в i, перед возникновением ошибки. И действительно ли на предыдущих итерациях заполнялись нужные параметры kalman[i-1], kalman[i-2], kalman[i-3]
Добавьте логирование этих данных, например через message.
Roman Koledin написал: простите таже проблема можете помочь её исправить вод код
Settings = { Name = "*Kijun-sen", line = {{ Name = "Kijun-sen", Color = RGB(0, 0, 255), Type = TYPE_LINE, Width = 2 }} }
function Init() return 1 end
local kijun_period = 26 -- Период Kijun-sen (можно изменить)
function OnCalculate(index) -- Проверяем, достаточно ли данных для расчета if index < kijun_period - 1 then return nil end
-- Инициализация переменных для экстремумов local max_high = H(index - kijun_period + 1) local min_low = L(index - kijun_period + 1)
-- Поиск максимума и минимума за период for i = index - kijun_period + 2, index do local current_high = H(i) local current_low = L(i)
if current_high > max_high then max_high = current_high end
if current_low < min_low then min_low = current_low end end
-- Расчет Kijun-sen return (max_high + min_low) / 2 end
попробуйте так:
Код
Settings = {
Name = "*Kijun-sen",
line = {{
Name = "Kijun-sen",
Color = RGB(0, 0, 255),
Type = TYPE_LINE,
Width = 2,
kijun_period = 26 -- Период Kijun-sen (можно изменить)
}}
}
function Init() return 1 end
function OnCalculate(i)
if i==1 then
max_high = H(1)
min_low = L(1)
else
if i%Settings.kijun_period==0 then max_high = H(i); min_low = L(i) end
current_high = H(i)
current_low = L(i)
-- Поиск максимума и минимума за период
if current_high > max_high then max_high = current_high end
if current_low < min_low then min_low = current_low end
-- Расчет Kijun-sen
end
return (max_high + min_low) / 2
end
nikolz написал: if i%Settings.kijun_period==0 then max_high = H(i); min_low = L(i) end
ошибка, так как Settings.kijun_period = nil. 2. Вместо скользящей вами предлагается "прыгающая" . Начальные значения каждого периода берутся в качестве экстремумов. Но может быть вы предлагаете свой прыгающий индикатор? ----------- Ниже выложен код реализации индикатора Kijun-sen приблизительно в 3,5 раза более эффективный по времени выполнения, чем то, что выложил Roman Koledin:
Код
Settings = {
Name = "*Kijun-sen_opt",
kijun_period = 26, -- Период Kijun-sen (можно изменить)
line = {{
Name = "Kijun-sen_opt",
Color = RGB(0, 0, 200),
Type = TYPE_LINE,
Width = 2
}}
}
function Init() return 1 end
local kijun_period = Settings.kijun_period
function OnChangeSettings()
kijun_period = Settings.kijun_period
end
---
local TT
local N_C = 500
function OnCalculate(index)
-- -- Вычисление времени обработки свеч --
-- if index == kijun_period + 1 then
-- TT = os.clock()
-- end
-- if index == N_C + kijun_period then
-- message('Kijun-sen. Время обработки ' .. N_C .. ' свечей (млс.) = ' .. (os.clock() - TT) * 1000)
-- end
if index==1 then
max_high = H(1)
min_low = L(1)
else
current_high = H(index)
current_low = L(index)
--------
if current_high > max_high then -- Пришел максимальный
max_high = current_high
else
if index > kijun_period then
-- Ушел из скользящего периода максимальный --
if H(index - kijun_period) >= max_high then -- поиск максимального
max_high = current_high
for j = index - kijun_period + 1, index - 1 do
current_high = H(j)
if current_high > max_high then max_high = current_high end
end
end
end
end
---
if current_low < min_low then -- Пришел минимальный
min_low = current_low
else
if index > kijun_period then
-- Ушел из скользящего периода минимальный --
if L(index - kijun_period) <= min_low then -- поиск минимального
min_low = current_low
for j = index - kijun_period + 1, index - 1 do
current_low = L(j)
if current_low < min_low then min_low = current_low end
end
end
end
end
end
return (max_high + min_low) / 2
end
nikolz написал: if i%Settings.kijun_period==0 then max_high = H(i); min_low = L(i) end
ошибка, так как Settings.kijun_period = nil. 2. Вместо скользящей вами предлагается "прыгающая" :: . Начальные значения каждого периода берутся в качестве экстремумов. Но может быть вы предлагаете свой прыгающий индикатор? ----------- Ниже выложен код реализации индикатора Kijun-sen приблизительно в 3,5 раза более эффективный по времени выполнения, чем то, что выложил Roman Koledin:
Код
Settings = {
Name = "*Kijun-sen_opt" ,
kijun_period = 26 , -- Период Kijun-sen (можно изменить)
line = {{
Name = "Kijun-sen_opt" ,
Color = RGB ( 0 , 0 , 200 ),
Type = TYPE_LINE,
Width = 2
}}
}
function Init () return 1 end
local kijun_period = Settings.kijun_period
function OnChangeSettings ()
kijun_period = Settings.kijun_period
end
---
local TT
local N_C = 500
function OnCalculate (index)
-- -- Вычисление времени обработки свеч --
-- if index == kijun_period + 1 then
-- TT = os.clock()
-- end
-- if index == N_C + kijun_period then
-- message('Kijun-sen. Время обработки ' .. N_C .. ' свечей (млс.) = ' .. (os.clock() - TT) * 1000)
-- end
if index = = 1 then
max_high = H( 1 )
min_low = L( 1 )
else
current_high = H(index)
current_low = L(index)
--------
if current_high > max_high then -- Пришел максимальный
max_high = current_high
else
if index > kijun_period then
-- Ушел из скользящего периода максимальный --
if H(index - kijun_period) > = max_high then -- поиск максимального
max_high = current_high
for j = index - kijun_period + 1 , index - 1 do
current_high = H(j)
if current_high > max_high then max_high = current_high end
end
end
end
end
---
if current_low < min_low then -- Пришел минимальный
min_low = current_low
else
if index > kijun_period then
-- Ушел из скользящего периода минимальный --
if L(index - kijun_period) < = min_low then -- поиск минимального
min_low = current_low
for j = index - kijun_period + 1 , index - 1 do
current_low = L(j)
if current_low < min_low then min_low = current_low end
end
end
end
end
end
return (max_high + min_low) / 2
end
нет не проверял. Да именно прыгающий. Я же написал - попробуйте это. Как другой вариант, который работает быстрее.
Settings = {
Name = "*Kijun-sen",
kijun_period = 26, -- Период Kijun-sen (можно изменить)
line = {{
Name = "Kijun-sen",
Color = RGB(0, 0, 255),
Type = TYPE_LINE,
Width = 2,
}}
}
function Init() return 1 end
function OnCalculate(i)
high = H(i) low = L(i)
if high and low then
if i==1 then
max = H(1) min = L(1)
else
if i%Settings.kijun_period==0 then max = high; min =low end
if high > max then max = high end
if low < min then min = low end
return (max + min)/2;
end
end
end
Settings = {
Name = "*Kijun-sen",
kijun_period = 26, -- Период Kijun-sen (можно изменить)
line = {{
Name = "Kijun-sen",
Color = RGB(0,255,255),
Type = TYPE_LINE,
Width = 2,
}}
}
function Init() return 1 end
function OnCalculate(i)
if H(i) and L(i) then
local j=i-Settings.kijun_period; if j<1 then j=1; end
max=H(i); min=L(i);
while i>j do
local H,L=H(j),L(j)
if H and H>max then max = H end
if L and L<min then min =L end
j=j+1 end
return (max + min)/2;
end
end
Если уж уделяете столько времени этому вопросу, то, наверно, стоит сделать устойчивый вариант. Ошибка же была о сравнении nil с числом. А во всех предлагаемых реализациях нет проверок на наличие бара, полученных значений перед арифметикой, перехвата ошибок, чтобы Квик не умирал от потока сообщений об ошибках на графиках с 60 тыс барами и т.д. Даже если отбросить саму реализацию, то это все не рабочие решения.
Оптимизированный вариант обычный, считает тоже самое, но быстрее:
Код
Settings = {
Name = "*Kijun-sen",
kijun_period = 15,
line = {{
Name = "Kijun-sen",
Color = RGB(255,255,255),
Type = TYPE_LINE,
Width = 2,
}}
}
function Init() return 1 end
function OnCalculate(i)
local Hi,Li=H(i),L(i);
if Hi and Li then
if max==nil then max=Hi end
if min==nil then min=Li end
if Hi>max or min>Li then
local j=i-Settings.kijun_period; if j<1 then j=1; end
max=Hi; min=Li;
while i>j do
local Hj,Lj=H(j),L(j)
if Hj and Hj>max then max = Hj end
if Lj and Lj<min then min =Lj end
j=j+1 end
end
x=(max + min)/2;
end
return x;
end
пардон, последний вариант считает иначе, поэтому остается этот:
Код
Settings = {
Name = "*Kijun-sen",
kijun_period = 15,
line = {{
Name = "Kijun-sen",
Color = RGB(255,255,255),
Type = TYPE_LINE,
Width = 2,
}}
}
function Init() return 1 end
function OnCalculate(i)
local Hi,Li=H(i),L(i);
if Hi and Li then
local j=i-Settings.kijun_period; if j<1 then j=1; end
max=Hi; min=Li;
while i>j do
Hi,Li=H(j),L(j)
if Hi and Hi>max then max = Hi end
if Li and Li<min then min =Li end
j=j+1 end
x=(max + min)/2;
end
return x
end
Оптимизировал алгоритм вычислений, чтобы считал быстрее. Выкладываю для всех желающих:
Код
Settings = {Name = "*Kijun-sen",kijun_period = 6,}
function OnCalculate(i)
Hi=H(i) or H1; Li=L(i) or L1; x1=x;
if i1>i then
ma=Hi; mi=Li; jma=i; jmi=i;
end
if Hi and Li then
local j=i-Settings.kijun_period; if j<1 then j=1; end
if j>jma or j>jmi then
ma=Hi; mi=Li; jma=i; jmi=i;
while i>j do
Hi,Li=H(j),L(j)
if Hi and Hi>ma then ma = Hi jma=j; end
if Li and Li<mi then mi =Li jmi=j;end
j=j+1
end
else
if Hi>ma then ma=Hi; jma=i; end
if mi>Li then mi=Li; jmi=i; end
end
x=(ma + mi)/2; H1,L1,i1=Hi,Li,i;
end
return x1
end
function OnChangeSettings()
i1=0;jma=0; jmi=0; H1=0; L1=0;ma=0;mi=0;
end
function Init()
OnChangeSettings()
Settings.line = {{ Name=Settings.Name, Color=RGB(32,255,128), Type=TYPE_LINE, Width = 2,}}
return #Settings.line end