Kaavan (Все сообщения пользователя)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
Ошибка в индикаторе при увеличении таймфрейма
 
хорошее решение
Ошибка в индикаторе при увеличении таймфрейма
 
Проблема устранена.
Аналогичная проверка потребуется и в других индикаторах, где используется подобная конструкция.
Для PSAR даже дважды:
Код
it={ppp=it.pp, pp=it.p, p=I, l=it.l+1}

if it.p < it.pp then it.pp = it.p-1 end -- van
if it.pp < it.ppp then it.ppp = it.pp-1 end -- van
Ошибка в индикаторе при увеличении таймфрейма
 
А обойти можно дополнительной проверкой: if it.p < it.pp then it.pp = it.p-1 end
Спасибо за внимание)
Код
function CMO(I, Fsettings, ds) --Chande Momentum Oscillator ("CMO")
   local sum={}
   local sum2={}
   local it = {pp=0, p=0, l=0}
return function (I, Fsettings, ds)

local Fsettings=(Fsettings or {})
local P = (Fsettings.CMO_Period or 14)
local VT = (Fsettings.CMO_VType or CLOSE)
PrintDbgStr(P)
  
if (P>0) then
   if I == 1 then
      sum={}
      sum2={}
      it = {pp=0, p=0, l=0}
   end

   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
    if it.p < it.pp then it.pp = it.p-1 end   
    
Ошибка в индикаторе при увеличении таймфрейма
 
Ну если быть дотошным, то при увеличении таймфрейма ошибка выскакивает в строке
Код
GetValueEX(it.pp,VT,ds)
т.к. it.pp хранит номер предыдущего индекса, а при первом прогоне этого номер старшей свечи предыдущего графика.
При увеличении таймфрейма количество свечей уменьшается, отсюда идет обращение к несуществующему элементу массива.

Отсюда вопрос:
Есть ли способ обнулить переменные блока ниже?
Код
function CMO() --Chande Momentum Oscillator ("CMO")
   local sum={}
   local sum2={}
   local it = {pp=0, p=0, l=0}
return function (I, Fsettings, ds)
Ошибка в индикаторе при увеличении таймфрейма
 
Цитата
У Вас же абсолютно бессмысленное вложение во вложении во вложении.
услышал. Действительно еще недопонимаю нюансов - поэтому и пишу. Попробую упростить.

Цитата
local FCMO1 = CMO()
local FCMO2 = CMO()
local FCMO3 = CMO()
это для последовательного вызова? А трижды FCMO1 вызвать нельзя было?
Ошибка в индикаторе при увеличении таймфрейма
 
Цитата
Просто основной код индикатора использует служебную функцию, которая пользуется вашими индикаторам
в этом смысл

полный код:
Код
Settings = {
Name = "*CMO (TEST)", 
Period = 14, 
VType = "Close", --(Open, High, Low, Close, Volume, Median, Typical, Weighted, Difference)
line = {{
      Name = "Horizontal line (top)",
      Type = TYPE_LINE, 
      Color = RGB(140, 140, 140)
      },
      {
      Name = "Horizontal line (bottom)",
      Type = TYPE_LINE, 
      Color = RGB(140, 140, 140)
      },
      {
      Name = "CMO", 
      Type = TYPE_LINE, 
      Color = RGB(221, 44, 44)
      }
      },
Round = "off",
Multiply = 1,
Horizontal_line="50"
}
         
function Init()
   func = Test1()
   return #Settings.line
end

function OnCalculate(Index)
local Out = ConvertValue(Settings, func(Index, Settings))
local HL = tonumber(Settings.Horizontal_line)
   if HL then
      return HL,-HL,Out
   else
      return nil,nil,Out
   end
end

function Test1()
    local FTest = Test2()
    
    return function (I, Fsettings, ds)
      return FTest(I, Fsettings, ds)
    end  
end 

function Test2()
    local FCMO = CMO()
    local dsCMO = {Val = {}, Min = {}, Max = {}} 
    return function (I, Fsettings, ds)
      dsCMO.Val[I] = FCMO(I, Fsettings, ds)
      return dsCMO.Val[I]
    end  
end  

function CMO() --Chande Momentum Oscillator ("CMO")
   local sum={}
   local sum2={}
   local it = {pp=0, p=0, l=0}
return function (I, Fsettings, ds)
local Fsettings=(Fsettings or {})
local P = (Fsettings.Period or 14)
local VT = (Fsettings.VType or CLOSE)
if (P>0) then
   if I == 1 then
      sum={}
      sum2={}
      it = {pp=0, p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      if it.l > 1 then
         local diff = GetValueEX(it.p,VT,ds) - GetValueEX(it.pp,VT,ds)
         if diff > 0 then
            sum[Ip] = (sum[Ipp] or 0) + diff
            sum2[Ip] = (sum2[Ipp] or 0)
         elseif diff < 0 then
            sum[Ip] = (sum[Ipp] or 0)
            sum2[Ip] = (sum2[Ipp] or 0) - diff
         elseif diff == 0 then 
            sum[Ip] = (sum[Ipp] or 0)
            sum2[Ip] = (sum2[Ipp] or 0)
         end
      end
      if it.l > P then
         local CMO1 = sum[Ip]-(sum[Ippp] or 0)
         local CMO2 = sum2[Ip]-(sum2[Ippp] or 0)
         return (CMO1 - CMO2) / (CMO1 + CMO2) * 100
      end
   end
end
return nil
end
end


SMA,MMA,EMA,WMA,SMMA,VMA = "SMA","MMA","EMA","WMA","SMMA","VMA"
OPEN,HIGH,LOW,CLOSE,VOLUME,MEDIAN,TYPICAL,WEIGHTED,DIFFERENCE,ANY = "O","H","L","C","V","M","T","W","D","A"

function CandleExist(I,ds)
return (type(C)=="function" and C(I)~=nil) or
   (type(ds)=="table" and (ds[I]~=nil or (type(ds.Size)=="function" and (I>0) and (I<=ds:Size()))))
end

function Squeeze(I,P)
   return math.fmod(I-1,P+1)
end

function ConvertValue(T,...)
local function r(V, R) 
   if R and string.upper(R)== "ON" then R=0 end
   if V and tonumber(R) then
      if V >= 0 then return math.floor(V * 10^R + 0.5) / 10^R
      else return math.ceil(V * 10^R - 0.5) / 10^R end
   else return V end
end
local arg = {...}
arg.n = select('#', ...)
   if arg.n > 0 then
      for i = 1, arg.n do
         arg[i]=arg[i] and r(arg[i] * ((T and T.Multiply) or 1), (T and T.Round) or "off")
      end
      return unpack(arg)
   else return nil end
end


function GetValueEX(I,VT,ds) 
VT=(VT and string.upper(string.sub(VT,1,1))) or ANY
   if VT == OPEN then         --Open
      return (O and O(I)) or (ds and ds:O(I))
   elseif VT == HIGH then       --High
      return (H and H(I)) or (ds and ds:H(I))
   elseif VT == LOW then      --Low
      return (L and L(I)) or (ds and ds:L(I))
   elseif VT == CLOSE then      --Close
      return (C and C(I)) or (ds and ds:C(I))
   elseif VT == VOLUME then      --Volume
      return (V and V(I)) or (ds and ds:V(I)) 
   elseif VT == MEDIAN then      --Median
      return ((GetValueEX(I,HIGH,ds) + GetValueEX(I,LOW,ds)) / 2)
   elseif VT == TYPICAL then   --Typical
      return ((GetValueEX(I,MEDIAN,ds) * 2 + GetValueEX(I,CLOSE,ds))/3)
   elseif VT == WEIGHTED then   --Weighted
      return ((GetValueEX(I,TYPICAL,ds) * 3 + GetValueEX(I,OPEN,ds))/4) 
   elseif VT == DIFFERENCE then   --Difference
      return (GetValueEX(I,HIGH,ds) - GetValueEX(I,LOW,ds))
   else                     --Any
      return (ds and ds[I])
   end
return nil
end
Ошибка в индикаторе при увеличении таймфрейма
 
При этом построение индикатора выполняется корректно
Ошибка в индикаторе при увеличении таймфрейма
 
Получилось.
Двойной вызов.

Вот такая надстройка над вашим индикатором
Код
Settings = {
Name = "*CMO (TEST)", 
Period = 14, 
VType = "Close", --(Open, High, Low, Close, Volume, Median, Typical, Weighted, Difference)
line = {{
      Name = "Horizontal line (top)",
      Type = TYPE_LINE, 
      Color = RGB(140, 140, 140)
      },
      {
      Name = "Horizontal line (bottom)",
      Type = TYPE_LINE, 
      Color = RGB(140, 140, 140)
      },
      {
      Name = "CMO", 
      Type = TYPE_LINE, 
      Color = RGB(221, 44, 44)
      }
      },
Round = "off",
Multiply = 1,
Horizontal_line="50"
}
         
function Init()
   func = Test1()
   return #Settings.line
end

function OnCalculate(Index)
local Out = ConvertValue(Settings, func(Index, Settings))
local HL = tonumber(Settings.Horizontal_line)
   if HL then
      return HL,-HL,Out
   else
      return nil,nil,Out
   end
end

function Test1()
    local FTest = Test2()
    
    return function (I, Fsettings, ds)
      return FTest(I, Fsettings, ds)
    end  
end 

function Test2()
    local FCMO = CMO()
    local dsCMO = {Val = {}, Min = {}, Max = {}} 
    return function (I, Fsettings, ds)
      dsCMO.Val[I] = FCMO(I, Fsettings, ds)
      return dsCMO.Val[I]
    end  
end  

дает подобную ошибку ТОЛЬКО ПРИ УВЕЛИЧЕНИИ ТАЙМФРЕЙМА.
для строки  return dsCMO.Val[I] пишет CMO_TEST.lua:54: attempt to perform arithmetic on a nil value

Дело не в том, что мне заняться нечем. Просто основной код индикатора использует служебную функцию, которая пользуется вашими индикаторами.
Отсюда такая вложенность.
Ошибка в индикаторе при увеличении таймфрейма
 
К вашему индикатору претензий нет.
Проблема в том, что вызывая его из промежуточной функции что-то происходит такое, что ошибка появляется. Словно утечка какая-то или некорректная инициализация глобальных переменных.
Попробую воспроизвести ситуацию снова на чистом индикаторе.
Ошибка в индикаторе при увеличении таймфрейма
 
При уменьшении таймфрейма такой ошибки не возникает
Ошибка в индикаторе при увеличении таймфрейма
 
Добрый день!
Столкнулся с такой проблемой, которую не могу обойти никакими условиями.
Скорее всего каких-то нюансов не учитываю.

Имеется индикатор, используемый поставляемый вами CMO()
Код
Settings = {
  Name = "*Kaavan Signals TEST", 
  CMO_Period = 14, 
  line = {
      {
        Name = "CMO",
        Color = RGB(0, 255, 0),
        Type = TYPE_POINT,
        Width = 3      
      }
    }
}

function Init()
   func = GetSignals()
   return #Settings.line
end

function OnCalculate(Index) 
   return func(Index, Settings)
end

function GetSignals()
  local FCMO = CMO()                                --Chande Momentum Oscillator ("CMO")
  local dsCMO = {Val = {}, Min = {}, Max = {}}      
  
  return function (I, Fsettings, ds)
    if I < Fsettings.CMO_Period then
      return nil
    else  
      dsCMO.Val[I] = FCMO(I, Fsettings, ds)                                       -- считаем CMO
    end
  end  
end

------------------------------
function CMO() --Chande Momentum Oscillator ("CMO")
   local sum={}
   local sum2={}
   local it = {pp=0, p=0, l=0}
return function (I, Fsettings, ds)
local Fsettings=(Fsettings or {})
local P = (Fsettings.CMO_Period or 14)
local VT = (Fsettings.CMO_VType or CLOSE)
if (P>0) then
   if I == 1 then
      sum={}
      sum2={}
      it = {pp=0, p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      if it.l > 1 then
         local diff = GetValueEX(it.p,VT,ds) - GetValueEX(it.pp,VT,ds)
         if diff > 0 then
            sum[Ip] = (sum[Ipp] or 0) + diff
            sum2[Ip] = (sum2[Ipp] or 0)
         elseif diff < 0 then
            sum[Ip] = (sum[Ipp] or 0)
            sum2[Ip] = (sum2[Ipp] or 0) - diff
         elseif diff == 0 then 
            sum[Ip] = (sum[Ipp] or 0)
            sum2[Ip] = (sum2[Ipp] or 0)
         end
      end
      if it.l > P then
         local CMO1 = sum[Ip]-(sum[Ippp] or 0)
         local CMO2 = sum2[Ip]-(sum2[Ippp] or 0)
         return (CMO1 - CMO2) / (CMO1 + CMO2) * 100
      end
   end
end
return nil
end
end

Отрабатывает без ошибок, но при увеличении таймфрейма выдает следующую ошибку:attempt to perform arithmetic on a nil value
на строке 55:
Код
local diff = GetValueEX(it.p,VT,ds) - GetValueEX(it.pp,VT,ds)
Аналогично и с другими используемыми индиктаорами.
В чем может быть проблема и как от неё уйти?
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
Извините, в коде выше опечатки.
Вот работающий:
Код
function CMO_trends()
  local FCMO = CMO()
  local dsCMO = {Val = {}, Min = {}, Max = {}}
  
  return function (I, Fsettings, ds)
    local CMO_upTrend, CMO_downTrend
    
    local mn = #dsCMO.Min
    local mx = #dsCMO.Max
    
    dsCMO.Val[I] = FCMO(I, Fsettings, ds)                                       -- считаем CMO
    
    if I > Settings.CMO_Period and dsCMO.Val[I] ~= nil and dsCMO.Val[I-1] ~= nil and dsCMO.Val[I-2] ~= nil then
      if dsCMO.Val[I-1] > dsCMO.Val[I] and dsCMO.Val[I-1] > dsCMO.Val[I-2] then
        dsCMO.Max[mx+1] = dsCMO.Val[I-1]                                        -- определяем очередной максимум CMO
        CMO_downTrend =  mx>0 and dsCMO.Max[mx+1] < dsCMO.Max[mx]               -- если максимум ниже предыдущего - нисходящий тренд
      end  
      
      if dsCMO.Val[I-1] < dsCMO.Val[I] and dsCMO.Val[I-1] < dsCMO.Val[I-2] then
        dsCMO.Min[mn+1] = dsCMO.Val[I-1]                                        -- определяем очередной минимум CMO
        CMO_upTrend =  mn>0 and dsCMO.Min[mn+1] > dsCMO.Min[mn]                 -- если минимум выше предыдущего - восходящий тренд
        end 
    end 
    
    return CMO_upTrend and 10 or nil, CMO_downTrend and -10 or nil
  end
end
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
Код
function CMO_trends()
  local FCMO = CMO()
  local dsCMO = {Val = {}, Min = {}, Max = {}}
  
  return function (I, Fsettings, ds)
    local CMO_upTrend, CMO_downTrend
    
    local mn = #dsCMO.Min
    local mx = #dsCMO.Max
    
    dsCMO.Val[I] = FCMO(I, Fsettings, ds)                                       -- считаем CMO
    
    if I > Settings.CMO_Period and dsCMO.Val[I] ~= nil and dsCMO.Val[I-1] ~= nil and dsCMO.Val[I-2] ~= nil then
      if dsCMO.Val[I-1] > dsCMO.Val[I] and dsCMO.Val[I-1] > dsCMO.Val[I-2] then
        dsCMO.Max[mx+1] = dsCMO.Val[I-1]                                        -- определяем очередной максимум CMO
        CMO_downTrend =  mx>0 and dsCMO.Max[mx+1] < dsCMO.Max[mx]               -- если максимум ниже предыдущего - нисходящий тренд
      end  
      
      if dsCMO.Val[I-1] < dsCMO.Val[I] and dsCMO.Val[I-1] < dsCMO.Val[I-2] then
        dsCMO.Min[mn+1] = dsCMO.Val[I-1]                                        -- определяем очередной минимум CMO
        CMO_upTrend =  mn>0 and dsCMO.Max[mn+1] < dsCMO.Max[mn]                 -- если минимум ниже предыдущего - восходящий тренд
        end 
    end 
    
    return CMO_upTrend and 10 or nil, CMO_downTrend and -10 or nil
  end
end
может этот фрагмент кому-то поможет
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
Всё получилось красиво. Спасибо!
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
в этом смысле никак не могу осознать расчет SMA.
Получается таблица sum накапливает данные с каждым вызовом?
Код
--[[Simple Moving Average (SMA)
SMA = sum(Pi) / n]]
function F_SMA()
   local sum = {}
   local it = {p=0, l=0}
return function (I, P, VT, ds)
   if I == 1 then
      sum = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
      if it.l >= P then
         return (sum[Ip] - (sum[Ippp] or 0)) / P
      end
   end
return nil
end
end
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
Читал, но не в полной мере осознал.
Спасибо за ответ.
Т.е. в моем случае нужно будет циклом от 1 до I просчитать CMO, поместить результаты в массив и работать далее с ним как с источником данных?  
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
Код
function CMOExtremum ()
local CMOlenght = 20 
local FCMO = CMO()

return function (I, Fsettings, ds)

local CMOValues = {}

CMOValues[ 1 ] = FCMO(I, Fsettings, ds)
CMOValues[ 2 ] = FCMO(I + 1 , Fsettings, ds)

return CMOValues[ 2 ]
end 
end 
 
Добрый день!
Для расчета индикатора мне нужны пара десятков последних значений индикатора CMO, который я рассчитываю в этом же файле.

Я предположил, что для этого мне нужно создать массив, в который вызвать функцию СМО для значений индекса от I до I-20
Но получается какая-то ерунда.
Т.е. если смотреть код выше: если возвращать CMOValues[1], то выход индикатора совпадает с СМО
Ожидается, что возврат CMOValues[2] даст ту же картину, но смещенную на один бар назад.
Но нет. Получается совсем другая кривая.

Предположу, что нужно задействовать Squeeze и GetValueEX, не предположу как.
Подскажите, пожалуйста, как решить задачу эффективно?

Для понимания опишу постановку. При возникновении экстремума на CMO
Код
if CMOValues[ 2 ] > CMOValues[ 1 ] and CMOValues[ 2 ] > CMOValues[ 3 ] then 
maxCMO1 = CMOValues[ 2 ]
end 
if CMOValues[ 2 ] < CMOValues[ 1 ] and CMOValues[ 2 ] < CMOValues[ 3 ] then 
minCMO1 = CMOValues[ 2 ]
end 
 найти ближайший того же типа (мин, макс) и сравнить их значения.
В зависимости от их соотношения выдать сигнал
Использование части данных другого индикатора в коде, Работа с типовым шаблоном индикатора
 
Код
function CMOExtremum()
  local CMOlenght = 20
  local FCMO = CMO()
  
  return function (I, Fsettings, ds)

    local CMOValues = {}
    
    CMOValues[1] = FCMO(I, Fsettings, ds)
    CMOValues[2] = FCMO(I+1, Fsettings, ds)
    
    return CMOValues[2]
  end
end

Добрый день!
Для расчета индикатора мне нужны пара десятков последних значений индикатора CMO, который я рассчитываю в этом же файле.

Я предположил, что для этого мне нужно создать массив, в который вызвать функцию СМО для значений индекса от I до I-20
Но получается какая-то ерунда.
Т.е. если смотреть код выше: если возвращать CMOValues[1], то выход индикатора совпадает с СМО
Ожидается, что возврат CMOValues[2] даст ту же картину, но смещенную на один бар назад.
Но нет. Получается совсем другая кривая.

Предположу, что нужно задействовать Squeeze и GetValueEX, не предположу как.
Подскажите, пожалуйста, как решить задачу эффективно?

Для понимания опишу постановку. При возникновении экстремума на CMO
Код
    if CMOValues[2] > CMOValues[1] and CMOValues[2] > CMOValues[3] then
      maxCMO1 = CMOValues[2]
    end  
    if CMOValues[2] < CMOValues[1] and CMOValues[2] < CMOValues[3] then
      minCMO1 = CMOValues[2]
    end  
найти ближайший того же типа (мин, макс) и сравнить их значения.
В зависимости от их соотношения выдать сигнал
Страницы: 1
Наверх