Циклы FOR, WHILE, REPEAT в QLua (lua)

Автор записи: Дмитрий (Admin)
1 звезда2 звезды3 звезды4 звезды5 звезд (Голосов 5, среднее: 5,00 из 5)
Загрузка...

Qlua-основы
В скриптовом языке QLua есть 3 вида циклов (for, while и repeat):

1. FOR - DO - END имеет 2 типа:

-- 1-й тип:
 
   -- Цикл сделает 10 итераций, увеличивая каждый раз переменную i на 1, т.е. i будет меняться от 0 до 9,
   -- переменная i является локальной для цикла, т.е. видна только внутри него
   for i = 0, 9, 1 do
      A = A*2;
   end;
   -- Данный цикл можно было записать и без 3-го аргумента, потому что по умолчанию он равен 1
   for i = 0, 9 do
      A = A*2;
   end;
   -- Но вместо 1 можно использовать любое другое число, или выражение, результат которого является числом
   -- Например так, цикл сделает только 5 итераций и остановится, потому что в 6-й итерации i будет равна 10 (0,2,4,6,8,10), а 10 > 9
   for i = 0, 9, 2 do
      A = A*2;
   end;
   -- Здесь используется выражение, т.е. каждая итерация увеличивает переменную i на 2
   for i = 0, 9, 1+1 do
      A = A*2;
   end;
   -- Можно сделать цикл на убывание
   for i = 9, 0, -1 do
      A = A*2;
   end;
 
-- 2-й тип:
 
-- Такой вариант при каждой итерации записывает в i индекс, а в value значение элемента из массива Array, 
-- перебирая, таким образом, все элементы в массиве типа {[1] = 10, [2] = "Текст", [3] = 50}
for i,value in ipairs(Array) do
   -- здесь какой-то блок кода
end;
 
-- Такой вариант при каждой итерации записывает в key ключ, а в value значение элемента из массива Array, 
-- перебирая, таким образом, все элементы в массиве типа {red = "Красный", green = "Зеленый", blue = "синий"}
for key,value in pairs(Array) do
   -- здесь какой-то блок кода
end;

2.WHILE - DO - END

while A < 10 do
   -- здесь какой-то блок кода 
end;
-- Читается так: ПОКА выполняется условие A меньше 10 ВЫПОЛНЯТЬ(делать) блок кода КОНЕЦ

3.REPEAT - UNTIL

repeat
   -- здесь какой-то блок код
until A < 10
-- Читается так: ПОВТОРЯТЬ блок кода ДО ТОГО, пока не выполняется условие A меньше 10

Для того, чтобы досрочно выйти из любого, вышеописанного, цикла служит оператор break.
Пример использования:

for i = 0, 9, 1 do
   if i >= 2 then break; end; -- цикл завершится на 3-й итерации (0,1,2)
end;

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Добавить комментарий

Циклы FOR, WHILE, REPEAT в QLua (lua): 61 комментарий

  1. Таблица имеет вид:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    
    [1]={[0]={
             ['low']=64745,
             ['doesExist']=1,
             ['close']=64749,
             ['datetime']={
                ['ms']=0,
                ['year']=2019,
                ['day']=11,
                ['week_day']=5,
                ['month']=10,
                ['sec']=0,
                ['hour']=10,
                ['min']=49
             },
             ['high']=64760,
             ['open']=64759,
             ['volume']=1082
          },
          [2]={
             ['low']=64744,
             ['doesExist']=1,
             ['close']=64752,
             ['datetime']={
                ['ms']=0,
                ['year']=2019,
                ['day']=11,
                ['week_day']=5,
                ['month']=10,
                ['sec']=0,
                ['hour']=10,
                ['min']=51
             },
             ['high']=64754,
             ['open']=64744,
             ['volume']=1743
          },
          [3]={
             ['low']=64749,
             ['doesExist']=1,
             ['close']=64752,
             ['datetime']={
                ['ms']=0,
                ['year']=2019,
                ['day']=11,
                ['week_day']=5,
                ['month']=10,
                ['sec']=0,
                ['hour']=10,
                ['min']=52
             },
             ['high']=64761,
             ['open']=64752,
             ['volume']=1122
          },

    Может выводить ее в файл а потом читать ?

    1. это вопрос? если да, то вот так:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      
      function table.val_to_str(v)
          if "string" == type(v) then
              v = string.gsub(v, "\n", "\\n")
              if string.match(string.gsub(v,"[^'\"]",""), '^"+$') then
                  return "'" .. v .. "'"
              end
              return '"' .. string.gsub(v,'"', '\\"') .. '"'
          end
          return "table" == type(v) and table.tostring(v) or tostring(v)
      end
      function table.key_to_str(k)
          if "string" == type(k) and string.match(k, "^[_%a][_%a%d]*$") then
              return k
          end
          return "[" .. table.val_to_str(k) .. "]"
      end
      function table.tostring(tbl)
          if type(tbl)~='table' then return table.val_to_str(tbl) end
          local result, done = {}, {}
          for k, v in ipairs(tbl) do
              table.insert(result, table.val_to_str(v))
              done[k] = true
          end
          for k, v in pairs(tbl) do
              if not done[k] then
                  table.insert(result, table.key_to_str(k) .. "=" .. table.val_to_str(v))
              end
          end
          return "{" .. table.concat(result, ",") .. "}"
      end
      function table.load(fname)
          local f, err = io.open(fname, "r")
          if f == nil then return {} end
          local fn, err = loadstring("return "..f:read("*a"))
          f:close()
          if type(fn) == "function" then
              local succ, res = pcall(fn)
              if succ and type(res) == "table" then return res end
          end
          return {}
      end
      function table.save(fname, tbl)
          local f, err = io.open(fname, "w")
          if f ~= nil then
              f:write(table.tostring(tbl))
              f:close()
          end
      end

      сохранить:
      table.save(yourtable, "table.dat")
      загрузить:
      res, yourtable = table.load("table.dat")

  2. Подскажите пожалуйста есть какой то способ посмотреть таблицу один раз за один проход расчета скрипта и сравнить значения всех нужных полей 100 свечей с одним значением?
    -- получаем таблицу параметров 100 свечей

    1
    2
    3
    4
    5
    6
    
    local tab = getCandles(ident, 100, offset)
    for i = #tab, 1, -1 do
    if last == tab[1][i].high or last == tab[1][i].low  then
    -- что то делаем
    end
    end

    Скрипт тормозит и расчитывает очень долго

    1. Не совсем понятно, что делает функция getCandles.
      Если используете не документированные функции, то нужно ее представить на обозрение. А то вопрос у вас ни о чем.
      Если подумать, что tab имеет ту структуру, которая в первом посте, (хотя она какая-то рваная) то цикл для обхода tab будет таким:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      
      local function calculate(tab, last)
        local result = 0
        local function calc_j(bar)
          if not bar or bar.high == 0 or bar.low == 0 then return 0 end
          if last ~= bar.high and last ~= bar.low  then return 0 end
          -- что то делаем
          return bar.volume
        end
       
        local function calc_i(t)
          local res = 0
          if not t then return res end
          for j = #t, 1, -1 do
            res = res + calc_j(t[j])
          end
          return res
        end
        for i = 1, #tab, 1, -1 do
          result = result + calc_i(tab[i])
        end
        return result
      end
       
      local tab = getCandles(ident, 100, offset) or {}
      local last = 64000
      local volume_summ = calculate(tab, last)
      1. А на счет медленно это сколько? час, минута?
        Все зависит от размера tab, которую возвращает getCandles, может там 1 мио вложенных свечных графиков по 100 баров?
        или "-- что то делаем" содержит ожидающие циклы?
        С вашими 3-мя строками кода, послать бы вас лесом по хорошему.

        1. Здравствуйте, спасибо за функцию, попробую прикрутить, Нет не час но в момент прохода примерно сек 20 и скрипт в это время зависает в этом месте, да эта функция получения данных по идентефикатору 100 последних свеч, ничего особенного, а если таких циклов будет несколько то все конец, таблица да кусок, нет смысла размещать остальные такие же

  3. Если поставить условие if (indx == Size()) then end , то ошибка attempt to compare number with nil пропадает, но расчёт тогда производится только в указанное время, а надо, чтобы при загрузке или смене инструмента в любое время

  4. Всем привет! Подскажите причину происхождения ошибки в теле цикла for "attempt to compare number with nil" при осуществлении индикатором расчётов .

    LUA
    if tt.hour == h and tt.min == m then
    t_table = tt
    HIGH = H(indx)
    LOW = L(indx)

    for i = 0, inter-1 do
    if H(indx-i) > HIGH then
    HIGH = H(indx-i);
    end
    if L(indx-i) < LOW then
    LOW = L(indx-i);
    end
    end

    /LUA

    1. В данном куске кода многие переменные не описаны, так что буду догадываться.
      Когда indx = 1 Запускается цикл for
      В первой итерации переменная i = 0, значит indx-i ( где 1-0 ) Дает в условии H(1) то есть high первого бара.
      Во второй итерации переменная i уже равна 1, а значит indx-i ( где 1-1 ) дает в условии H(0), то есть high нулевого бара, такого бара на графике нет, вот тут то и появляется nil
      Далее во всех итерациях запрашивается high не существующих баров -1 -2 -3 ... Сколько итераций в цикле не известно, потому что в этом коде не указано значение переменной inter

      1. Добрый день, Павел! Тогда скажите, как же тогда индикатор работает, если баров не существует, ведь рассчитывается значение правильно Если же добавить условие if (indx == Size()) then end , то ошибка пропадает. Период для М5 для нахождение экстремумов вчерашнего дня и созерцания их в дне сегодняшнем от начала времён.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        
        Settings= {
        Name = "*HIGH-LOW_YESTERDAY",
        period = 162,
        line =
         
        {
        	{
        		Name = "HIGH",
        		Color = RGB(255, 255, 255),
        		Type = TYPE_LINE,
        		Width = 3,
         
        	},
        	{
        		Name = "LOW",
        		Color = RGB(255, 255, 255),
        		Type = TYPE_LINE,
        		Width = 3,
         
        	},
        }
         
        }
         
        function Init()
        return #Settings.line
        end
         
        		local inter = Settings.period
        		local t_table = {}
        		local HIGH
        		local LOW
         
         
        function OnCalculate(indx)
         
        	local tt = T(indx)
         
          if (indx == Size()) then
         
        	if tt.hour == 23
        	and	tt.min == 45
        	then
        		t_table = tt
         
        		HIGH = H(indx)
        		LOW = L(indx)
         
        					for i = 0, inter-1 do
        						if H(indx-i) > HIGH then
        						HIGH = H(indx-i);
        						end
        						if L(indx-i) < LOW then
        						LOW = L(indx-i);
        						end
        					end
        						for i = 1, indx do
        						SetValue(i, 1, HIGH);
        						SetValue(i, 2, LOW);
        						end
         
        	end
         
           end
         
        	return HIGH, LOW
        end
      2. Предыдущий не работает всё время,а только в указанное, а вот этот работает всегда, но выдаёт ошибку

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        
        Settings= {
        Name = "*HIGH-LOW_RGB",
        period = 162,
        line =
         
        {
        	{
        		Name = "HIGH",
        		Color = RGB(255, 255, 255),
        		Type = TYPE_LINE,
        		Width = 3,
         
        	},
        	{
        		Name = "LOW",
        		Color = RGB(255, 255, 255),
        		Type = TYPE_LINE,
        		Width = 3,
         
        	},
        }
         
        }
         
        function Init()
        return #Settings.line
        end
         
        		local inter = Settings.period
        		local t_table = {}
        		local HIGH
        		local LOW
         
         
        function OnCalculate(indx)
         
         
         
        	local tt = T(indx)
         
         
         
        		if tt.hour == 23 and tt.min == 45 then
        			t_table = tt
        			HIGH = H(indx)
        			LOW = L(indx)
         
         
        					for i = 0, inter-1 do
        						if H(indx-i) > HIGH then
        						HIGH = H(indx-i);
        						end
        						if L(indx-i) < LOW then
        						LOW = L(indx-i);
        						end
        					end
        						for i = 1, indx do
        						SetValue(i, 1, HIGH);
        						SetValue(i, 2, LOW);
        						end
        		end
         
        	return HIGH, LOW
        end
        1. Вот Вы и отвечаете на свой вопрос. Потому что он работает не все время.
          В варианте где есть if (indx == Size()) then вычисления идут только тогда, когда indx = Size(), а это значит что indx равен количеству баров на графике. У Вас график содержит 1 бар или тысячи? скорее всего тысячи.
          Предположим что на графике 3000 баров, значит когда indx равен 3000, только в этом случае выполняется вычисления, а дальше...
          Запускается цикл for
          первая итерация, переменная i = 0 переменная indx = 3000 Вы запрашиваете H(3000-0)
          вторая итерация, переменная i = 1 переменная indx = 3000 Вы запрашиваете H(3000-1)
          третья итерация, переменная i = 2 переменная indx = 3000 Вы запрашиваете H(3000-2)
          Вот и работает Ваш код нормально, потому что бары с индексами 3000, 2999, 2998 реально существуют на графике, по этому и ошибки нет.
          Но у Вас еще условие стоит что вычисления нужно выполнять только тогда, когда последний бар имеет время 23:45, в остальное время вычисления не выполняются.