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

Страницы: 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
Если нравится, можете сказать "спасибо".
 
Цитата
nikolz написал:
Если нравится, можете сказать "спасибо".
 Этот индикатор не Kijun-sen.
Вы сравнивали его с исправленным, долго работающим индикатором пользователя Roman Koledin?
Это же делается просто.
 
Цитата
nikolz написал:
чтобы считал быстрее
  Можете попробовать использовать ранее выложенный мной, но слегка модифицированный код индикатора Kijun-sen, который работает в ~20 раз быстрее, чем  чем то, что выложил Roman Koledin:
Код
Settings = {
   Name = "*Kijun-sen",
   kijun_period = 26,  -- Период Kijun-sen (можно изменить)
   line = {{
       Name = "Kijun-sen",
       Color = RGB(0, 0, 200),
       Type = TYPE_LINE,
       Width = 2
   }}
}

local kijun_period = Settings.kijun_period

local QueueH, QueueL = {}, {}
local const_L = 999999999

function Init()
   QueueH, QueueL = {}, {}
   for i = 0, kijun_period - 1 do
      QueueH[i] = 0; QueueL[i] = const_L
   end
   return 1 
end

function OnChangeSettings()
   kijun_period = Settings.kijun_period 
   QueueH, QueueL = {}, {}
   for i = 0, kijun_period - 1 do
      QueueH[i] = 0; QueueL[i] = const_L
   end
end
---
local TT
local N_C = 500
local max_high, min_low
function OnCalculate(index)
-- -- Вычисление времени обработки свеч  (500 свечкй за ~4 млс. в 5 раз быстрее моего же *Kijun-sen_opt)--
-- 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) or 0
      min_low = L(1) or const_L
      QueueH[1], QueueL[1] = max_high, min_low
   else
      current_high = H(index) or 0
      current_low = L(index) or const_L
      local ind = index % kijun_period  -- место в векторе --
      local QueueH_end 
      local QueueL_end
      if index > kijun_period then  -- сохранение уходящих значений --
         QueueH_end = QueueH[ind]   
         QueueL_end = QueueL[ind]
      end
      
      QueueH[ind], QueueL[ind] = current_high, current_low -- сохранение текущих в векторе --
      -- --------
      if current_high >= max_high then  -- Пришел максимальный --
         max_high = current_high
      else
         if index > kijun_period then  -- начальный период завершен --
            --  Максимум "ушел" из скользящего периода --
            if QueueH_end >= max_high then -- поиск максимального в векторе 
               max_high = current_high
               for j = 0, kijun_period - 1 do
                  current_high = QueueH[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 QueueL_end <= min_low then -- поиск минимального
               min_low = current_low
               for j = 0, kijun_period - 1 do
                  current_low = QueueL[j]
                  if current_low < min_low then min_low = current_low end
               end
            end
         end
      end
   end
   return (max_high + min_low) / 2
end
 
«При 300% прибыли нет такого преступления, на которое не рискнул бы капитал» К. Маркс.

И опять двойственность, или почему побитные операции 2^n предпочтительнее!

В Lua оператор % — это остаток от деления (modulus). Он возвращает остаток от деления одного числа на другое. И остаток от деления на степень двойки можно сделать с помощью побитовой маски.
Если нам нужен остаток x % 2^n, то это равносильно тому, что мы обнуляем все биты выше n-го. Для этого используем побитовое И (bit.band):
bit.band — чистая побитовая операция на целых, выполняется через С-библиотеку, работает на порядок быстрее, особенно если много итераций.

Этот метод работает только для делителей, являющихся степенью двойки 2^n (2, 4, 8, 16, …).

* Если делитель — степень двойки, используем bit.band(x, 2^n - 1). Это и быстрее, и чище в контексте масок.
* Если делитель любой, лучше оставить обычный % или написать функцию на математику.

В своей практике, вспомнив высказывание К. Маркса, тоже не удержался, и перевел кольцевой буфер на bit.band.
Кольцевой буфер как раз классический случай, где % заменяется на bit.band. И именно здесь ускорение становится реально заметным, потому что операция повторяется на каждом обращении к буферу. Простая замена оператора % (modulus) на bit.band приводит к приросту в скорости от 2 - 10 раз! Как здесь не вспомнить К. Маркса.
 
Цитата
VPM написал:
bit.band — чистая побитовая операция на целых, выполняется через С-библиотеку, работает на порядок быстрее, особенно если много итераций.
   Вы это проверяли?
   bit.band   это вызов функции, в теле которой выполняется битовая операция "И". Сам вызов до начала выполнения тела функции это довольно тяжелая операция, выполняющаяся дольше любой арифметической операции.
  В Lua 5.4 соотношение длительности выполнения приблизительно следующее:
  1)  %   =  1
  2)  bit.band  = 4,49
  3)  & (битовая операция "И" вместо bit.band , начиная c Lua  5.3) =  0,63
 
TGB,  Да вы целиком правы, спасибо за уточнение! Производительность в Lua 5.4.1 реально зависит от использования встроенных операторов, и побитовая операция & становится явным лидером, когда дело  операций с числами, являющимися степенями двойки.
 
TGB,  Можете взглянуть на код?
Код
--- Функциональный стиль: кольцевой буфер
-- @param size_power_of_two степень двойки (например, 3 → буфер на 8 элементов)
function CreateRingBuffer(size_power_of_two)
    local size = 1 << size_power_of_two -- 2^n
    local mask = size - 1
    local data = {}
    for i = 1, size do
        data[i] = 0
    end

    local head = -1
    local count = 0

    local buffer = {}

    --- Добавление элемента
    function buffer:add(value)
        head = (head + 1) & mask
        data[head + 1] = value
        count = math.min(count + 1, size)
    end

    --- Получение элемента (1 - последний)
    function buffer:get(index)
        if index < 1 or index > count then return nil end
        local pos = (head - index + 1 + size) & mask
        return data[pos + 1]
    end

    --- Последний элемент
    function buffer:last()
        if count == 0 then return nil end
        return data[head + 1]
    end

    --- Первый элемент (самый старый)
    function buffer:first()
        if count == 0 then return nil end
        local pos = (head - count + 1 + size) & mask
        return data[pos + 1]
    end

    --- Количество элементов
    function buffer:length()
        return count
    end

    --- Очистка буфера
    function buffer:clear()
        head = -1
        count = 0
    end

    --- Итератор для цикла for (новые → старые)
    function buffer:iter()
        local i = 0
        return function()
            i = i + 1
            return buffer:get(i)
        end
    end

    --- Преобразование в таблицу (новые сначала)
    function buffer:toTable()
        local t = {}
        for i = 1, count do
            t[i] = buffer:get(i)
        end
        return t
    end

    --- Проверка на заполненность
    function buffer:isFull()
        return count == size
    end

    return buffer
end
 
Вроде все правильно работает.  :!:  Вот результаты теста в SciTe:
Код
RingBufferClassOPP.lua"  1  
Функциональный стиль:
Последнее значение:   100
Предпоследнее:   90
Первое в буфере:   30

Все элементы (новые сначала):
100
90
80
70
60
50
40
30

ООП стиль:
RSI   1   период назад:   45
RSI   2   период назад:   36
RSI   3   период назад:   50
RSI   4   период назад:   46
RSI   5   период назад:   54
Среднее RSI:   46.2

Анализ ADX:   Слабый тренд или флэт
Функциональный стиль:   0.43   сек
ООП стиль:   0.631   сек
>Exit code: 0    Time: 1.483
Страницы: 1
Читают тему
Наверх