Получение в QLua(Lua) данных из графиков и индикаторов

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

QUIK-Qlua-poluchenie-dannyhЧтобы получить доступ к графику(не индикатору) какого-либо инструмента нужно создать источник данных при помощи функции CreateDataSource().
ВАЖНО!!! Для получения новых данных, кроме тех, что уже есть в открытом графике на текущий момент (тем более, если он не открыт), требуется использовать одну из следующих функций: SetUpdateCallback(), или SetEmptyCallback(), о которых будет написано ниже.

Описание функции CreateDataSource()

Функция CreateDataSource возвращает таблицу QLua с параметрами, получать значения которых можно следующим образом:

local O = ds:O(i); -- Получить значение Open для указанной свечи (цена открытия свечи)
local H = ds:H(i); -- Получить значение High для указанной свечи (наибольшая цена свечи)
local L = ds:L(i); -- Получить значение Low для указанной свечи (наименьшая цена свечи)
local C = ds:C(i); -- Получить значение Close для указанной свечи (цена закрытия свечи)
local V = ds:V(i); -- Получить значение Volume для указанной свечи (объем сделок в свече)
local T = ds:T(i); -- Получить значение Time для указанной свечи (время открытия свечи (таблица datetime))
   -- Где i - индекс свечи (от 1 до ds:Size())
 
local Size = ds:Size(); -- Возвращает текущий размер (количество свечей в источнике данных) 
ds:Close(); -- Удаляет источник данных, отписывается от получения данных
 
ds:SetUpdateCallback(MyFuncName); -- Позволяет задать пользователю функцию обратного вызова для обработки изменившихся свечей, т.е. когда по выбранному в CreateDataSource параметру в терминал поступит новое значение (возможно такое же), автоматически будет вызвана данная функция, в которую будут передан индекс последней свечи графика, а так же добавятся новые данные в таблицу ds
-- Пример функции:
function MyFuncName(index)
   message('На '..index..'-й свече объем вырос до '..ds:V(index));
end;
 
-- Чтобы получать новые данные без использования функции обратного вызова, а просто получать новые данные в ds и брать их оттуда по необходимости существует функция:
ds:SetEmptyCallback(); -- Которая подписывается на получение новых данных

Списки возможных параметров, используемых в функции CreateDataSource():

Список для АКЦИЙ
Список для ВАЛЮТЫ
Список для ОПЦИОНОВ
Список для ФЬЮЧЕРСОВ

Так же, в QLua есть функции для получения данных как графиков, так и индикаторов по их уникальным идентификаторам(тэгам), для этого необходимо нужному графику(индикатору) назначить уникальный идентификатор, о том как это делается можете ознакомиться в самом начале "Инструкции по использованию" Индикатора "Мои Сделки". Идентификатор для индикатора добавляется аналогичным способом.

После этого, можно использовать следующие функции для доступа к данным:

-- Функция предназначена для получения КОЛИЧЕСТВА ЛИНИЙ в графике (индикаторе) по выбранному идентификатору
getLinesCount(tag); -- Возвращает число
   -- tag - (STRING) идентификатор графика (индикатора), о котором писалось выше
 
-- Функция предназначена для получения информации о КОЛИЧЕСТВЕ СВЕЧЕЙ по выбранному идентификатору
getNumCandles(tag); -- Возвращает число
   -- tag - (STRING) идентификатор графика (индикатора), о котором писалось выше
 
-- Функция предназначена для получения информации о свечах по идентификатору (заказ данных для построения графика функция не осуществляет, поэтому для успешного доступа нужный график должен быть открыт)
t, n, l = getCandlesByIndex (tag, line, first_candle, count);
   -- Параметры:
      -- tag          – (STRING) строковый идентификатор графика или индикатора 
      -- line         – (NUMBER) номер линии графика или индикатора. Первая линия имеет номер 0 
      -- first_candle – (NUMBER) индекс первой свечи. !!! ПЕРВАЯ (САМАЯ ЛЕВАЯ) СВЕЧКА ИМЕЕТ ИНДЕКС 0 !!!
      -- count        – (NUMBER) количество запрашиваемых свечей
   -- Возвращаемые значения:
      -- t – таблица, содержащая запрашиваемые свечи, пример работы: 
         local O = t[i].open; -- Получить значение Open для указанной свечи (цена открытия свечи)
         local H = t[i].high; -- Получить значение High для указанной свечи (наибольшая цена свечи)
         local L = t[i].low; -- Получить значение Low для указанной свечи (наименьшая цена свечи)
         local C = t[i].close; -- Получить значение Close для указанной свечи (цена закрытия свечи)
         local V = t[i].volume; -- Получить значение Volume для указанной свечи (объем сделок в свече)
         local T = t[i].datetime; -- Получить значение datetime для указанной свечи
            -- Где i - индекс свечи от 0 до n-1
      -- n – количество свечей в таблице t
      -- l – легенда (подпись) графика

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

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

Получение в QLua(Lua) данных из графиков и индикаторов: 305 комментариев

  1. Здравствуйте, пытаюсь получить данные из таблицы и ничего не получается. Вроде бы все должно работать, а не работает.
    сама таблица DS,Error = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_M1) не равна nil, а вот число свечей в ней DS.Size() - равно nil, причем не 0, а именно nil.
    Делаю в цикле DS.SetEmptyCallback(); sleep(5000) жду по нескольку минут
    и все равно DS.Size() равно nil
    при этом график этого инструмента открыт в Quik и все отображается нормально.
    ничего не понимаю.

    1. Здравствуйте, сделайте как в примере в статье:

      1
      2
      3
      4
      5
      6
      
      main = function()
         ds, Error = CreateDataSource (CLASS_CODE, SEC_CODE, INTERVAL_M1)
         while (Error == "" or Error == nil) and ds:Size() == 0 do sleep(1) end
         if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) end
         message('Кол-во свечей: '..tostring(ds:Size()))
      end
  2. Подправил, насколько мог, пока ничего не рисуется, ругается на 22 строчку, что пытаюсь сравнивать с нулем

    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
    
     Settings =
    {
    Name = "Call AMA",
     
      line =
      {
        -- цвет и толщина дубля АМА
    	{Name = "AMAresult", Color = RGB (255, 50, 40), Type = TYPE_LINE, Width = 2},
      }
    }
    function Init()
      return 1
     end
     
    function OnCalculate (index)
    --исходное назначение АМАresult
    AMAresult=0
    Last=1
    -- получение значения линии индикатора АМА
     Last=getNumCandles(a01);
      t,n,a01=getCandlesByIndex(a01,1,index-1,1);
     if index<Last then
     AMAresult=t[0].close
     end
     
    	return AMAresult
     
    end
  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    Settings =
    {
    Name = "Call AMA",
     
      line =
      {
        -- цвет и толщина дубля АМА
    	{Name = "AMAresult", Color = RGB (255, 0, 0), Type = TYPE_LINE, Width = 2},
      }
    }
    function Init()
      -- получение значения линии индикатора АМА
     AMAresult = getCandlesByIndex(a01,1,0,1)
      --t[i].close,20,a01=getCandlesByIndex(a01,1,0,1)
     
    end
     
    function OnCalculate (index)
    	return AMAresult
    end
    1. Здравствуйте, функция getCandlesByIndex не может использоваться внутри индикатора. Вам нужно установить нужный Вам индикатор на график, потом зайти в его настройки, указать в них, во вкладке "Дополнительно" идентификатор. Потом создать скрипт, который будет запускаться как робот, через окно "Доступные скрипты" и уже в нем получать значения индикатора при помощи getCandlesByIndex

      1. Дмитрий спасибо за оперативный ответ!
        Скажите, чтобы мне зря не мучиться, возможно ли после этого визуализировать полученное или это будет некая таблица без линии в окне?
        И ещё, что проще, ловить через скрипт значения индикатора, чтобы потом с ними возиться, или взять и выстроить подобный индикатор в ЛУА ( АМУ на ЛУА я у кого-то срисовал, она строится)?

          1. Спасибо, ответ понятен, придется для начала - так как я визуал )) - в луа строить. Видел примеры с кэшированием построения тех же мувингов, у вас кэширование, случаем, нигде не рассматривалось?

              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
                
                 --dofile(getWorkingFolder() .. \\Include\\ma.lua)
                Settings =
                {
                Name = "Three EMA",
                period1 = 50,
                value_type1 = "C",
                period2 = 50,
                value_type2 = "C",
                line=
                {
                {
                Name = "EMA 1",
                Color = RGB(255, 0, 0),
                Type = TYPE_LINE,
                Width = 2
                },
                {
                Name = "EMA 2",
                Type = TYPE_LINE,
                Width = 2
                }
                }
                }
                function Init()
                myEMA1 = cached_EMA()
                myEMA2 = cached_EMA()
                return 2
                end
                function OnCalculate(index)
                ema1 = myEMA1(index, Settings.period1, Settings.value_type1)
                ema2 = myEMA2(index, Settings.period2, Settings.value_type2)
                return round(ema1,2), round(ema2,2)
                end
                1. Понял что Вы имели в виду. Ваша задача ведь не индикаторы писать научиться, а использовать их для начала. Их уже на все случаи жизни написано, практически, нет смысла Вам сейчас думать о тонкостях их написания.

                  1. Дадада, совершенно верно!
                    Дело в том, что я их хочу несколько использовать одновременно, до 10, может, 20-ти штук. И упрятать их в другое место, чтобы в коде не мешались, если это возможно, ес-сно

  4. Здравствуйте, я из начинающих, прошу извинить за дилетантизм, буду благодарен если дадите ссылку, где можно подробнее посмотреть пример использования функции t, n, l = getCandlesByIndex (tag, line, first_candle, count)
    мне нужно поработать с данными линии индикатора АМА. Присвоил ему идентификатор, но похоже слишком просто сочинил код. Нужно бы узнать побольше о его применении.
    Спасибо за очень информативный и полезный сайт!
    Settings =
    {
    Name = "Call AMA",

    line =
    {
    -- цвет и толщина дубля АМА
    {Name = "AMAresult", Color = RGB (255, 0, 0), Type = TYPE_LINE, Width = 2},
    }
    }
    function Init()
    -- получение значения линии индикатора АМА
    AMAresult = getCandlesByIndex(a01,1,0,1)
    --t[i].close,20,a01=getCandlesByIndex(a01,1,0,1)

    end

    function OnCalculate (index)
    return AMAresult
    end

  5. Добрый день. Подскажите пожалуйста, каким образом можно вывести на график текущую минимально возможную и максимально возможную цену фьючерса в виде полосок? У меня имеется индикатор LUA, отображающий минимум/максимум предыдущего дня в виде полосок (его код приложу ниже), и я хотел его как-то переделать под эту задачу, но не обладаю достаточными знаниями((. Я уже понял, что мне нужны данные "PRICEMAX" и "PRICEMIN", но как их "запихнуть" в код индикатора к сожалению не понимаю. Или возможно вы поделитесь ссылкой на подобный готовый индикатор, я искал, но ничего похожего не нашел.

    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
    68
    69
    
    Settings =
    {
      Name = "MinMaxPrevDay",
      line =
      {
        {
          Name = "MaxPD",
          Color = RGB (255, 128, 64),
          Type = TYPE_LINE,
          Width = 4
        },
        {
          Name = "MidPD",
          Color = RGB (128, 128, 255),
          Type = TYPE_LINE,
          Width = 4
        },
        {
          Name = "MinPD",
          Color = RGB (0, 128, 128),
          Type = TYPE_LINE,
          Width = 4
        }
      }
    }
     
    function Init ()
      DoInit ()
      return 3 -- кол-во линий
    end
     
    function DoInit ()
      t = getTradeDate()
      TYear  = t.year
      TMonth = t.month
      TDay   = t.day
      Day  = 0
      High = 0
      Low  = 1e10
    end
     
    function OnCalculate (index)
      if index == 1 then
        DoInit ()
        return nil, nil, nil
      end
      if T(index).year == nil or T(index).month == nil or T(index).day == nil or
         H(index-1) == nil or L(index-1) == nil  then
        return nil, nil, nil
      end
      if High  L(index-1) then
        Low = L(index-1)
      end
      if T(index).day ~= Day then
        Day = T(index).day
        sHigh = High
        sLow  = Low
        High = 0
        Low  = 1e10
      end
      if sHigh == 0 or sLow == 0 or
         T(index).year ~= TYear or
         T(index).month ~= TMonth or
         T(index).day  ~= TDay then
        return nil, nil, nil
      else
        return sHigh, sLow+(sHigh-sLow)/2, sLow
      end
    end
      1. Благодарю за помощь. Сейчас мой код выглядит вот так (приложил ниже), и он даже работает)). Теперь меня мучает вопрос, возможно ли сделать, чтобы код инструмента "подхватывался" с текущего графика? Прочитав информацию здесь (), я пытался использовать конструкции такого вида:
        sec_code = getSecurityInfo("","").name
        sec_code = getSecurityInfo("","").code
        sec_code = getSecurityInfo("","").short_name
        но они не работают.

        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
        
        Settings =
        {
          Name = "MinMaxOrderPrice",
          line =
          {
            -- цвет и толщина максимально возможной цены
        	{Name = "Max order price", Color = RGB (255, 128, 64), Type = TYPE_LINE, Width = 2},
        	-- цвет и толщина минимально возможной цены
            {Name = "Min order price", Color = RGB (0, 128, 128), Type = TYPE_LINE, Width = 2}
          }
        }
         
        function Init()
          -- код инструмента
        sec_code = "RIH9"
         
          -- код класса инструмента
          class_code = getSecurityInfo("",sec_code).class_code
         
          -- получение значения максимально возможной цены
          MaxOrderPrice = getParamEx (class_code, sec_code, "PRICEMAX").param_value
         
          -- получение значения минимально возможной цены
          MinOrderPrice = getParamEx (class_code, sec_code, "PRICEMIN").param_value
         
          return 2 -- кол-во линий
        end
         
        function OnCalculate (index)
        	return MaxOrderPrice, MinOrderPrice
        end
  6. Здравствуйте!
    Есть ли способ получить данные свечи по времени?
    Например запускаю робот и хочу чтобы он мне выдал цену открытия свечи по инструменту в 10:01:00 текущего дня.

      1. Решил задачу может кому пригодится код:
        t, q, n = getCandlesByIndex("OIL", 0, getNumCandles("OIL")-1440, getNumCandles("OIL"))
        for i = q - 1439, q - 1, 1 do
        if t[q-i].datetime.hour == 10 and t[q-i].datetime.min == 00 then
        oilPrice = t[q-i].open
        break
        end
        end

  7. Скажите, пожалуйста, если у индикатора несколько кривых, как узнать, какой номер у каждой соответствующей кривой? Например, индикатор уровней Боллинджера, какой номер у нижней, и какой у верхней? Только методом "тыка"?

  8. Дмитрий, здравствуйте!
    1) При запуске скрипта Квик зависает (максимум минут 15 ждал, но он так и не отвис). Наверное не может подтянуть данные по фьючу поскольку график фьюча не открыт, а если открыть график, то тогда скрипт не зависает. Подскажите, пожалуйста, как его скорректировать, чтобы можно было данные по фьючу подтягивать без графика и чтобы скрипт не зависал.

    2) И второй вопрос как обратиться к DS:T(i), чтобы в файл записались данные формате "ДД.ММ.ГГГГ чч:мм:сс"

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    class="SPBFUT";
    sec="RIM8";
    interval=INTERVAL_M1;
    DSf=nil;                  -- Источник данных графика (DataSource)
    is_run=true;
    QuoteStr="";
    count=0;
    file_count=-1;
     
    function OnInit()
    	-- Получает доступ к свечам графика
    	local Error = '';
    	DSf,Error = CreateDataSource(class, sec, interval);
    	-- Если график, к которому нужно подключиться не открыт в терминале, то данные заказываются с сервера, на их получение нужно время,
    	-- по этому, рекомендуется добавлять вот такое ожидание, прежде, чем обращаться к DSf:
    	-- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт)
    	while (Error == "" or Error == nil) and DSf:Size() == 0 do sleep(1000) message('додж') end
    	if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) return end
    	-- Чтобы получать новые данные без использования функции обратного вызова, а просто получать новые данные в ds и брать их оттуда по необходимости существует функция:
    	DSf:SetEmptyCallback();
    end;
      1. Но если я перенесу это блок в main , то получается он будет каждый раз заново прогоняться в месте с main, вместо одно раза как в функции init. Не будет ли это негативно сказываться на быстродейстивии робота?

          1. Всё понял, этот кусок кода надо перед while поставить. Спасибо за ответ, Дмитрий!
            Можете, пожалуйста, по второму вопросу подсказать: как обратиться к DS:T(i), чтобы в файл записались данные формате "ДД.ММ.ГГГГ чч:мм:сс"?