1

Тема: Проблемы со знанием Lua

Пишу не с телефона, поэтому излагаю просто на пальцах, возможны ошибки в названии функций, не судите строго.
Есть функция получения таблицы стакана.
Туда надо подать класс инструмента и код инструмента в виде строк.
В коде пишу две глобальные переменные:
CLASS_CODE="EQOB"
SEC_CODE="RU000A1TB"
И соответственно подаю эти значения в OnQuote(CLASS_CODE,SEC_CODE)
Эти же переменные подаю в OnQuotelevel2, но у меня почему-то они подаются пустыми.
А вот если конкретно в функцию подать не переменные,а  класс и код инструмента, то все работает.
В чем я ошибаюсь?

2

Re: Проблемы со знанием Lua

Xantrax пишет:

В чем я ошибаюсь?

в OnQuote(CLASS_CODE,SEC_CODE) CLASS_CODE и SEC_CODE это не ваши глобальные переменные, а параметры того инструмента, по которому пришел снэпшот стакана, допустим Сбер.
Если у вас не открыт стакан с "RU000A1TB", то его нужно заказать:

CLASS_CODE="EQOB"
SEC_CODE="RU000A1TB"
if not IsSubscribed_Level_II_Quotes(CLASS_CODE, SEC_CODE) then
  Subscribe_Level_II_Quotes(CLASS_CODE, SEC_CODE)
end
function OnQuote(class_code, sec_code)
  if class_code == CLASS_CODE and sec_code == SEC_CODE then
    local ql2 = getQuoteLevel2(class_code, sec_code)
  end
end

3

Re: Проблемы со знанием Lua

kalikazandr пишет:

CLASS_CODE и SEC_CODE это не ваши глобальные переменные, а параметры того инструмента, по которому пришел снэпшот стакана, допустим Сбер.
Если у вас не открыт стакан с "RU000A1TB", то его нужно заказать

А что значит термин: "открыт стакан"? Программно открыт или в квике открыт (на какой вкладке, на любой)?

4

Re: Проблемы со знанием Lua

kalikazandr пишет:
if not IsSubscribed_Level_II_Quotes(CLASS_CODE, SEC_CODE) then
  Subscribe_Level_II_Quotes(CLASS_CODE, SEC_CODE)
end

И в какую функцию этот if лучше всего положить?

5 (2020-04-17 19:22:53 отредактировано Xantrax)

Re: Проблемы со знанием Lua

Я не понимаю работу функции OnQuote(). Я задаю параметры одного инструмента. А OnQuote откуда-то хватает параметры Алросы. Откуда она берет код и класс Алросы? Хотя в окне у меня стакан совершенно другого инструмента.
Посмотрел в "Менеджере окон" ни одного стакана Алросы не открыто!(( А функция все равно откуда-то хватает Алросу.
Перезапустил Quik, теперь в переменной sec-code, оказывается облигация Камаза БО5.((

6

Re: Проблемы со знанием Lua

Да, если событие изменения стакана можно обработать, то куда включить заявку на стакан? В main()? Нет. Может в onInit()?

7 (2020-04-18 02:02:08 отредактировано toxa)

Re: Проблемы со знанием Lua

Подписываться лучше всего в main.

К сожалению, не видя код сложно сказать, в чем проблема. Подозреваю, что ошибка где-то в 17-ой строки.

8 (2020-04-18 14:28:09 отредактировано kalikazandr)

Re: Проблемы со знанием Lua

А вы читали файл справки QLUA.chm, который лежит в корневом каталоге quik? Почитайте, там много полезной информации.
Гадать, что у вас в коде не работает никто не будет, это не форум эзотериков и ясновидящих тут нет.

9 (2020-04-18 14:35:45 отредактировано Xantrax)

Re: Проблемы со знанием Lua

toxa пишет:

Подписываться лучше всего в main.

[+]Spoiler
function main()
    if not IsSubscribed_Level_II_Quotes(CLASS_CODE, SEC_CODE) then
        Subscribe_Level_II_Quotes(CLASS_CODE, SEC_CODE)
    end
    while is_run do
        sleep(50)
    end;
end

Так, я думаю.

10 (2020-04-18 14:47:47 отредактировано Xantrax)

Re: Проблемы со знанием Lua

kalikazandr пишет:

Гадать, что у вас в коде не работает никто не будет, это не форум эзотериков и ясновидящих тут нет.

Там все просто, в функции main() цикл для постоянной работы скрипта.
В функции onQuote(class_code,sec_code) сравнение переменных класса инструмента и кода инструмента нужного мне и из сравнение. В этой же функции, функция getQuoteLevel2(class_code,sec_code) выдает мне стакан, в котором я нахожу лучшую цену покупки и лучшую цену продажи.
Я не понимаю, куда воткнуть функцию запроса стакана Subscribe_Level_II_Quotes и нужна ли она вообще. Так как я не понимаю, куда ее воткнуть, я ее воткнул просто в скрипт без всякой фунции, в самом начале.

Да, в этом файле много всего интересного, изучаю потихоньку. Не все сразу.

11

Re: Проблемы со знанием Lua

Xantrax пишет:

Я не понимаю, куда воткнуть функцию запроса стакана Subscribe_Level_II_Quotes и нужна ли она вообще. Так как я не понимаю, куда ее воткнуть, я ее воткнул просто в скрипт без всякой фунции, в самом начале.

1. вызов Subscribe_Level_II_Quotes() нужен. без нее в ваш колбэк будут приходить нотификации только о тех изменившихся стаканах, которые физически открыты в квике.
2. то, как вы сделали это в main - правильно.
3. в ваш колбэк могут приходить нотификации не только о тех стаканах, которые вы запросили. это нормально. в колбэке нужно проверять.

12

Re: Проблемы со знанием Lua

toxa пишет:
Xantrax пишет:

Я не понимаю, куда воткнуть функцию запроса стакана Subscribe_Level_II_Quotes и нужна ли она вообще. Так как я не понимаю, куда ее воткнуть, я ее воткнул просто в скрипт без всякой фунции, в самом начале.

1. вызов Subscribe_Level_II_Quotes() нужен. без нее в ваш колбэк будут приходить нотификации только о тех изменившихся стаканах, которые физически открыты в квике.
2. то, как вы сделали это в main - правильно.
3. в ваш колбэк могут приходить нотификации не только о тех стаканах, которые вы запросили. это нормально. в колбэке нужно проверять.

Спасибо большое.

13

Re: Проблемы со знанием Lua

toxa пишет:

Подписываться лучше всего в main.
К сожалению, не видя код сложно сказать, в чем проблема. Подозреваю, что ошибка где-то в 17-ой строки.

Да, моя проблема была в том, что onQuotes() возвращает изменение всех открытых стаканов в терминале. Мне, правда, до сих пор не понятно откуда эта функция дергала изменения цены Алросы, если ее стакана не было нигде открыто. На, да ладно.
Вопрос по другой функции, по Subscribe_Level_II_Quotes(). Есть у меня пара исходников, так вот там я ни одной такой функции не нашел.
Вопрос: а нужная ли она вообще? Если стакан по инструменту открыт, остальные инструменты мы не пропускаем по коду и классу инструмента зачем она? Или все же нужна?

14

Re: Проблемы со знанием Lua

Если стакан открыт - то не нужна. Это поведение происходит от древних версий квика, когда функции subscribe еще не было. Хорошим тоном является подписка, чтобы скрипт не перестал работать, если пользователь случайно закроет стакан.

15

Re: Проблемы со знанием Lua

toxa пишет:

... если пользователь случайно закроет стакан.

если случайно закроет стакан, подписка не отменится, но если был дисконект, та-да.

16

Re: Проблемы со знанием Lua

И опять про плохое знание Lua.
Товарищи, вот создаю я таблицу вложенную в таблицу, как мне обратиться в первому значению вложенной таблицы?

    local sot = {
    ["nam"] = {}
    };

Соответственно заполняю эту подтаблицу в коде.
И, к примеру, пытаюсь вывести значение:

message(sot["nam"]);

Выводится последний элемент массива.
А как обратиться к первому?
Так:

message(sot["nam"].[1]);

не работает.

17

Re: Проблемы со знанием Lua

Xantrax пишет:

как мне обратиться в первому значению вложенной таблицы?

Все товарищи, походу разобрался.
Заполнять надо:

sot["nam"][key];

а обращаться:

message(sot["nam"][1])

Может быть выскажете еще какие-нибудь рекомендации по работе с вложенными таблицами, ключами в них и т.п. Спасибо.

18

Re: Проблемы со знанием Lua

Xantrax, "расскажите чего-нибудь" - так не работает. smile задайте вопрос. нет никакого особого секрета в обращении с вложенными и не вложенными таблицами. просто помните о том, что таблицы - это на самом деле не массивы, а словари "ключ-значение". старайтесь писать программы так, чтобы не приходилось ничего сортировать и вставлять в середину, доступ по ключу всегда быстрее.

и что таблицы - это объекты, которые везде передаются по ссылке:

a = {"a"}
b = a
message(a[1]..' '..b[1])
a[1] = "b"
message(a[1]..' '..b[1])

потому что и a и b - это ссылки. чтобы получить копию - нужно постараться.

19 (2020-04-30 14:58:48 отредактировано Xantrax)

Re: Проблемы со знанием Lua

toxa пишет:

таблицы - это на самом деле не массивы

Чем в Lua таблицы отличаются от массивов?
Как работает функция OnParam(class, sec) ? В документации написано, что "Функция вызывается терминалом QUIK при изменении текущих параметров." Каких параметров? Любых по всем инструментам? С какой же частотой тогда она срабатывает. Т.е. можно отследить изменение цены продажи инструмента?
Как быстро организовать поиск по таблице? Есть у меня таблица с Sec_code, как быстро найти есть ли там значение совпадающее с искомым? Есть что-то наподобии string.find()? Или через цикл for искать?

20

Re: Проблемы со знанием Lua

Получается что функции поиска по Lua-таблице нет. Есть все что угодно (concat, insert, remove), а вот поиска нет.

21 (2020-05-01 01:01:31 отредактировано Xantrax)

Re: Проблемы со знанием Lua

Товарищи, что я получаю в этом коде

sec_list = getClassSecurities("EQOB")

Массив, таблицу, что? И как обращаться к этому?
если

message(sec_list )

то выводится все
если

message(sec_list[1] )

то ничего не выводится.
Как с этим зверем обращаться?

UPD: точнее у меня куда-то этот message теряется.

22

Re: Проблемы со знанием Lua

Xantrax, прежде чем задать вопрос, попробуйте использовать Поиск по форуму по ключевым словам и найдете кучу примеров с getClassSecurities.
Поиск работает и в справке QLUA.chm (в корневом каталоге квик)
функция getClassSecurities возвращает список инструментов класса, строку, а не таблицу.
Если вы не будете пользоваться поиском, то совсем скоро вам никто не будет ничего отвечать, без обид.

23

Re: Проблемы со знанием Lua

kalikazandr пишет:

функция getClassSecurities возвращает список инструментов класса, строку, а не таблицу.

Понял, не внимателен, строку, которую нужно потом парсить.

24 (2020-05-02 12:02:01 отредактировано Xantrax)

Re: Проблемы со знанием Lua

А может быть такое, что

for i = 0,getNumberOf("securities")-1 do 

выдает облигации, которые уже погашены, а потом при поиске (переборе) параметров через функцию

message(getSecurityInfo(CLASS_CODE,"RU000A0ZZXN3").name);

она не находит параметр name этой облигации и выдает сообщение attempt to index a nil value.
Зачем getNumberOf выдает абсолютно все бумаги (даже погашенные)?))
Получается надо при первоначальном поиске сравнивать их дату погашения с текущей датой, чтобы иметь список актуальных?
А еще вопрос, как динамически менять значения в пользовательской таблице при изменении цены предложения по инструменту, к примеру? Какова концепция? Полностью ее стирать и заново заносить туда все значения или запоминать строку в которой находилась данная бумага и менять только параметр в строке?

25 (2020-05-05 16:54:06 отредактировано kalikazandr)

Re: Проблемы со знанием Lua

Xantrax пишет:

Получается надо при первоначальном поиске сравнивать их дату погашения с текущей датой, чтобы иметь список актуальных?

такие проверки нужны

Xantrax пишет:

А еще вопрос, как динамически менять значения в пользовательской таблице при изменении цены предложения по инструменту, к примеру? Какова концепция? Полностью ее стирать и заново заносить туда все значения или запоминать строку в которой находилась данная бумага и менять только параметр в строке?

динамически будет заполняться в OnParam, и заново заполняться при закрытии

local caption = getScriptPath()
local is_run = true
local id = nil
local gui_param =
{
    [1]= {"Инструмент", true, QTABLE_CACHED_STRING_TYPE, 12, 0},
    [2]= {"До эксп.", true, QTABLE_DOUBLE_TYPE, 8, 1},
    [3]= {"bid", true, QTABLE_DOUBLE_TYPE, 8, 1},
    [4]= {"ask", true, QTABLE_DOUBLE_TYPE, 8, 1},
    colls = 
    {
        ticker = 1,
        dtmd = 2,
        bid = 3,
        ask = 4,
    },
    rows = {},
    coord = {y= 50, x= 600, dy= 500, dx= 293},
}

local function gui_insert()
    Clear(id)
    for ticker in string.gmatch(getClassSecurities("SPBFUT"), "(%w+)") do
        local dtmd = tonumber(getParamEx("SPBFUT", ticker, "days_to_mat_date").param_value)
        if dtmd > -1 then
            local r = InsertRow(id, -1)
            gui_param.rows[ticker] = {row = r, dtmd = dtmd}
            SetCell(id, r, gui_param.colls.ticker, ticker)
            SetCell(id, r, gui_param.colls.dtmd, tostring(dtmd), dtmd)
            local bid = tonumber(getParamEx("SPBFUT", ticker, "bid").param_value) or 0
            local ask = tonumber(getParamEx("SPBFUT", ticker, "offer").param_value) or 0
            SetCell(id, r, gui_param.colls.bid, tostring(bid), bid)
            SetCell(id, r, gui_param.colls.ask, tostring(ask), ask)
        end
    end
end
local function CallbackGui(t_id, msg, row, col)
    if row ~= 0 and msg == QTABLE_LBUTTONUP then
        if col < 0 then return end
        local col_name = gui_param[col][1]
        local val = GetCell(t_id, row, col).image
        if col == 1 then
            message("row= "..row.."\ncol= "..col.."\n"..col_name..": "..tostring(val),2)
        else
            local ticker = GetCell(t_id, row, gui_param.colls.ticker).image
            message("row= "..row.."\ncol= "..col.."\nИнструмент: "..ticker.."\n"..col_name.."= "..tostring(val),2)
        end
    end
    if (row == 0 and col < 0) or (msg == QTABLE_CLOSE) then
        local top, left, bottom, right = GetWindowRect(t_id)
        local height = bottom - top
        local width = right - left
        gui_param.coord =
        {
            y = top,
            x = left,
            dy = height,
            dx = width,
        }
        message("\n y = "..top.."\n x = "..left.."\n dy= "..height.."\n dx= "..width,2)
    end
end
function main()
    id = AllocTable()
    for i=1, #gui_param do
        local p = gui_param[i]
        AddColumn(id, i, p[1], p[2], p[3], p[4])
    end

    SetTableNotificationCallback(id, CallbackGui)

    while is_run do
        if IsWindowClosed(id) then
            CreateWindow(id)
            SetWindowCaption(id, caption)
            local coord = gui_param.coord
            SetWindowPos(id, coord.x, coord.y, coord.dx, coord.dy)
            gui_insert()
        end
        sleep(1)
    end
end
function OnParam(class, sec)
    local rows = gui_param.rows[sec]
    if rows then
        local bid = tonumber(getParamEx(class, sec, "bid").param_value) or 0
        local ask = tonumber(getParamEx(class, sec, "offer").param_value) or 0
        SetCell(id, rows.row, gui_param.colls.bid, tostring(bid), bid)
        SetCell(id, rows.row, gui_param.colls.ask, tostring(ask), ask)
    end
end
function OnStop()
    is_run = nil
    DestroyTable(id)
    return 1000
end