Ошибка при поиске пиков\впадин кастом индикатора

Страницы: 1
RSS
Ошибка при поиске пиков\впадин кастом индикатора
 
Не пойму, в чем проблема..
Выдает ошибку 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
 
Цитата
torque написал:
attempt to compare number with nil
В тексте ошибки должен быть номер строки на которую она ссылается.
Кроме того, уточните на какой инструмент накладывается индикатор.
 
Строки с ошибкой
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,

Как минимум, уже ошибка в том что Вы берете значения kalman[i-1], kalman[i-2], kalman[i-3] тогда когда их может не быть.
раз i это номер свечки, следует добавить условие
if i>4 then
и только после этого продолжать код.
 
Цитата
Sergey Gorokhov написал:
if i>4 then
Имелось ввиду конечно же
if i>=4 then
 
Но ведь выше в начале цикла есть присвоение переменной i номера текущего бара. По поводу >=4 попробовал, ничего не изменилось

if _ARG_0_ >=4 then
   if _ARG_0_ > i then
     i = _ARG_0_
 
Странно именно то, что когда пик или впадина образуется, то сообщение выводится корректно и ошибки нет. Ошибка возникает только когда условие
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.
 
Цитата
Sergey Gorokhov написал:
Цитата
Sergey Gorokhov   написал:
if i>4 then
Имелось ввиду конечно же
if i>=4 then

и все-таки правильно if i>4 then
т.к. в первом условии if _ARG_0_ >1 then, а не if _ARG_0_ >=1 then
 
простите таже проблема можете помочь её исправить
вод код


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
 
Цитата
Roman Koledin написал:
if index < kijun_period - 1 then
Надо: if index < kijun_period - 1 then.   index начинается с 1.
 
Цитата
TGB написал:
Надо: if index < kijun_period - 1 then
Не убрал 1. Должно:  if index < kijun_period  then
 
Цитата
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 написал:
попробуйте так:
 Вы проверяли то, что предлагаете?
1. В строке
Цитата
nikolz написал:
if i%Settings.kijun_period==0 then  max_high = H(i); min_low = L(i) end
ошибка, так как Settings.kijun_period = nil.
2. Вместо скользящей вами предлагается "прыгающая" :smile: . Начальные значения каждого периода берутся в качестве экстремумов. Но может быть вы предлагаете свой прыгающий индикатор?
-----------
   Ниже выложен код реализации индикатора 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
 
Цитата
TGB написал:
Цитата
nikolz написал:
попробуйте так:
  Вы проверяли то, что предлагаете?
1. В строке
Цитата
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,

   }}
}
 
попробуйте так (проверил)
Код
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
Если нравится, можете сказать "спасибо".
Страницы: 1
Читают тему
Наверх