1

Тема: Пользовательские таблицы

Всем доброго времени суток. Есть одна проблема с QUIK. Использую роботов на скриптах Lua. При этом каждый робот создает собственную рабочую таблицу.  Теперь если закрыть Квик, не останавливая роботов, то при следующем запуске самого QUIK он автоматически запустит роботов. Это очень удобно, НО! Роботы запускаю в специально созданной закладке Квик, там же создаются и рабочие таблицы роботов(таблицы создаются исключительно роботами/скриптами). И вот проблема, при каждом запуске Квика, именно эти таблицы создаются в специально выделенной закладке, именно так и должно быть... НО! эти же таблицы дублируются в других закладках, причем только в одной и выбирается она толи рандомно, толи на той, которая была открыта перед закрытием квика. Это очень мешает, ибо там другая важная информация. Как с этим бороться?

2 (2022-09-29 09:21:47 отредактировано swerg)

Re: Пользовательские таблицы

Если всё так, как вы описываете, то предполагаю, что при закрытии QUIK сохраняет "конфигурацию окон" и потом их восстанавливает. "На случайной вкладке" - это очень странно. Может это новые окна скриптом не на ой вкладке создаются?

А если остановить скрипт перед закрытием терминала, но не закрывать окно скрипта - после запуска терминала (без запуска скрипта) окно скрипта появится или нет? т.е проверить, что это именно сохраняется конфигурация окон.

Предлагаю попробовать удалять окно, созданное скриптом, при остановке скрипта в OnStop:

OnStop(NUMBER flag)
- flag передаётся равным 1 при остановке или удалении работающего скрипта Lua из диалога управления «Доступные скрипты»
- flag передаётся равным 2 при закрытии терминала QUIK

Значение 2 как раз нас интересует, в этом случае удалять окно скрипта.

3 (2022-09-29 09:52:43 отредактировано dark184)

Re: Пользовательские таблицы

У меня сделано так, если я закрываю таблицу скрипта, то и скрипт автоматом останавливается. Если скрипт останавливаю из из диалога управления «Доступные скрипты», то таблица автоматом закрывается...
Код, если закрываю таблицу крестиком

function main()
   while not stopped do 
        if IsWindowClosed(t_id) then                                            -- Если пользователь закрыл таблицу
            stopped = true                                                        -- Стопим скрипт
            message("Таблица закрыта пользователем, робот остановлен", 1)
        end
   end
end

Код, если торможу скрипт из диалога

function OnStop(s)
    stopped = true                            -- Скрипт остановлен закрытием таблицы или нажатием кнопки "Остановить"
    DestroyTable(t_id)                        -- Закрываем таблицу
    message("Скрипт остановлен пользователем, робот отключен")
end

Все это прекрасно работает, исключение только автоматический запуск скриптов.
Если запустить скрипт вручную, то таблица создается только в той вкладке, откуда был запуск из диалога управления, больше нигде не создается. При этом если скрипты не тормозить и закрыть квик, то при следующем запуске скрипты создают свои таблицы одновременно на двух вкладках(одна правильная, вторая рандомная или псевдорандомная) и судя по всему с одинаковыми ID, ибо при закрытии любой копии таблицы скрипт 100% останавливается.

4

Re: Пользовательские таблицы

Тогда это какой-то глюк квика, что он в таком случае так вот странно таблицы пересоздает при старте.

5

Re: Пользовательские таблицы

А у вас этого не наблюдается?

6

Re: Пользовательские таблицы

Выложите полный тестовый скрипт для пробы, смогу сказать.

7

Re: Пользовательские таблицы

Вот по быстрому подчистил, оставил только рабочую базу. Честно говоря подозреваю что собака порылась в самом коде. У меня сейчас ситуация такая. Подключаю квик к бирже, запускаю робота(он создает единственную таблицу во вкладке из которой запущен, на остальных этой таблицы нет), закрываю квик с запущенным роботом, снова запускаю квик, подключаюсь, робот запущен, но одна и таже таблица создается сразу во всех вкладках квика. Причем судя по всему с одинаковым ID, т.к. останавливаю скрипт из диалога управления «Доступные скрипты», дестроятся таблицы сразу во всех вкладках. Снова запускаю скрипт, таблица в единственной вкладке из которой запущен скрипт.
Не разобрался как прикрепить файл, поэтому пришлось сделать так hmm Свои TRADE_ACC и CLIENT_CODE светить на форуме не стал, но и без них скрипт работает, ибо заявки убраны.

[+]Spoiler
-- Настроечные параметры скрипта

TRADE_ACC        = "123"                       -- торговый счет
CLIENT_CODE        = "321"                        -- код клиента
SEC                = "PIKK"                    -- Код инструмента
CLASS            = "TQBR"                    -- Код класса

percent            = 1                            -- Желаемый процент профита
portfolio        = 1                            -- Количество лотов для покупки
uniq_trans_id     = 0x18000                    -- Уникальный идентификатор транзакции.

Block_sell_Case    = 1                            -- Если в портфеле есть акции, то
                                            -- 1 - Запрещаем роботу их продавать при запуске
                                            -- 0 - Робот выставляет все, что еще не в продаже в заявки при старте. Цена расчитывается с учетом percent

-- Конец настроечных параметров скрипта
-- Переменные в скрипте
security_info = getSecurityInfo(CLASS, SEC)

NAME = security_info.short_name                -- Инструмент
PRICE_STEP    = security_info.min_price_step    -- шаг цены по инструменту
PRICE_SCALE    = security_info.scale            -- точность задания цены инструмента
LOT_SIZE    = security_info.lot_size        -- Размер лота
Open        = 0                                -- Цена окрытия свечи
High        = 0                                -- Максимум свечи
Low            = 0                                -- Минимум свечи
Close        = 0                                -- Цена закрытия свечи
Volume        = 0                                -- Объем свечи
Order        = 0                                -- Заявка
Case        = 0                                -- Текущее количество в портфеле
buy_price    = 0                                -- Цена покупки
sell_price    = 0                                -- Цена продажи
Total        = 0                                -- Итого, руб.
Date_Time    = 0
Total_perc    = 0                                -- Итого, %

average_price    = 0                            -- средняя цена покупки.
block_sell        = 0                            -- Стоят на продаже.

stopped = false                                -- Признак работы или остановки скрипта.
cur_state = ""                                -- Текущее состояние робота.
                                            -- ""                ничего не куплено, не продано, не ожидаем.
                                            -- "e_buy"            ждем подтверждения, заявка выставлена
                                            -- "e_sell"            ждем подтверждения, заявка выставлена
                                            -- "confirm_buy"    ждем покупки по подтвержденной заявке
                                            -- "confirm_sell"    ждем продажи по подтвержденной заявке
                                            -- "buy"            купили
                                            -- "sell"            продали
                                            -- "buy_kill"        отмена заявки на покупку
                                            -- "sell_kill"        отмена заявки на продажу
t_id        = 0
cur_order    = 1
-- Работаем с битовыми флагами.
order_stat    = 0                                -- Статус заявки.
mask_bits    = 7                                -- Выделяем нужные биты из всех
                                            -- 0 - Заявка исполнена
                                            -- 1 - Заявка активна, иначе - не активна.
                                            -- 2 - Заявка снята.
                                            -- 3 - 
                                            -- 4 -

function OnStop(s)
    stopped = true                            -- Скрипт остановлен закрытием таблицы или нажатием кнопки "Остановить"
    DestroyTable(t_id)                        -- Закрываем таблицу
    message("Скрипт остановлен пользователем, робот отключен")
end

function OnInit()

    local NO = getNumberOf("orders")
    
    Column_Table =    {                                        -- Создаем список колонок таблицы.function() return  end
                    {"Инструмент",QTABLE_STRING_TYPE,15,function() return NAME end},
                    {"Шаг цены",QTABLE_DOUBLE_TYPE, 12,function() return tostring(PRICE_STEP) end},
                    {"Точность",QTABLE_INT_TYPE, 12,function() return tostring (PRICE_SCALE) end},
                    {"Заявка", QTABLE_STRING_TYPE, 10,function() return tostring(Order) end},
                    {"Портфель", QTABLE_INT_TYPE, 10,function() return tostring(Case) end},
                    {"Цена покупки", QTABLE_DOUBLE_TYPE, 15,function() return tostring(buy_price * LOT_SIZE) end},
                    {"Цена продажи", QTABLE_DOUBLE_TYPE, 15,function() return tostring(sell_price * LOT_SIZE) end},
                    {"Итого", QTABLE_DOUBLE_TYPE, 15,function() return tostring(Total) end},
                    {"Дата время", QTABLE_DOUBLE_TYPE, 15,function() return tostring(Date_Time) end},
                    {"Статус", QTABLE_STRING_TYPE, 10,function() return tostring(cur_state) end},
    }
    t_id = Table_init(Column_Table)                            -- Создаем таблицу и добавляем колонки.
        
--    File_Write()
end;

function main()
        
    while not stopped do 
        
        if IsWindowClosed(t_id) then                                            -- Если пользователь закрыл таблицу
            stopped = true                                                        -- Стопим скрипт
            message("Таблица закрыта пользователем, робот остановлен", 1)
        end
        
        
        Table_row(cur_order)
        sleep(500)
    end
    
end

function File_Write()

    f = io.open(getScriptPath().."\\Robot\\log\\" .. SEC .. ".lua","r+");        -- Пытается открыть файл в режиме "чтения/записи"
    message("Пытаюсь открыть файл \\Robot\\log\\" .. SEC .. ".lua")
    if f == nil then                                                            -- Если файл не существует
        message("Файл не существует!")
        f = io.open(getScriptPath().."\\Robot\\log\\" .. SEC .. ".lua","w");    -- Создает файл в режиме "записи"
        f:close();                                                                -- Закрывает файл
        f = io.open(getScriptPath().."\\Robot\\log\\" .. SEC .. ".lua","r+");    -- Открывает уже существующий файл в режиме "чтения/записи"
        message("Файл создан!")
        local i = 0
        for i=1,#Column_Table,1 do                                                -- Если файл не существует, то заполняем заголовок таблицы.
            f:write(Column_Table[i][1])
            f:write(string.rep(" ", Column_Table[i][3] - string.len(Column_Table[i][1]) - 2) .. "|" .. " ")
            --f:write("\t")
        end
        f:write("\n")
    end;
                                                                                -- Встает в начало файла 
                                                                                -- 1-ым параметром задается относительно чего будет смещение: 
                                                                                -- "set" - начало, "cur" - текущая позиция, "end" - конец файла
                                                                                -- 2-ым параметром задается смещение
    f:seek("end",0);
    for i=1,#Column_Table,1 do                                                    -- Если файл не существует, то заполняем заголовок таблицы.
        f:write(Column_Table[i][4]())
        f:write(string.rep(" ", Column_Table[i][3] - string.len(Column_Table[i][4]()) - 2) .. "|" .. " ")
    end
    f:write("\n")
    f:flush()                                                                    -- Сохраняет изменения в файле
    f:close()                                                                    -- Закрывает файл
--    f:write("Line1\nLine2");                                                    -- Записывает в файл 2 строки, "\n" признак конца строки
--    for line in f:lines() do message(tostring(line));end                        -- Перебирает строки файла, выводит их содержимое в сообщениях
    
end

-- Инициализация таблицы
function Table_init(t)

-- Создаем таблицу и присваиваем имена столбцов из переданного массива t.
    local i = 0
    local Table = AllocTable()
        for i=1,#t,1 do            -- Перебираем массив по строкам от первой до последней. Количество строк массива получаем #t
            AddColumn(Table, i, t[i][1], true, t[i][2], t[i][3])
        end

    CreateWindow(Table)
    SetWindowCaption(Table, "Рабочая таблица робота " .. NAME)
--    SetWindowPos(Table, 0, 10, 2500, 200)
    InsertRow(Table, -1)
    
return Table
end

-- Заполнение строки таблицы
function Table_row(row, color)

    local i = 0
    for i=1,#Column_Table,1 do
        SetCell(t_id,row,i,Column_Table[i][4]())
    end
    
end

function Add_row()

    InsertRow(t_id, cur_order)

end

8

Re: Пользовательские таблицы

Дошли руки проверить ваш пример.
Да, проблема проявляется такая же как у вас: после перезапуска QUIK с не остановленным скриптом таблица скрипта создается на всех вкладках.
Причем это именно вновь созданная таблица, а не "сохраненная в конфигурации QUIK", как я ошибочно предположил. Проверил так: перед повторным запуском QUIK я поправил указанный  заголовок окна в скрипте - и после запуска QUIK создалось окно (на всех вкладках) уже с новым заголовком.

Проверял на версиях 8.7 и 9.1 - проблема одинаковая.

Причем это на самом деле создается всего одно окно из скрипта, просто ошибочно отображается на всех вкладках. Проверил так: изменил ширину колонок - и видно, что на всех вкладках ширина тоже измененная, а значит это точно всего одно окно, просто отображаемое на любой вкладке.

Обнаружил, что если перенести строку

    t_id = Table_init(Column_Table)                            -- Создаем таблицу и добавляем колонки.

из OnInit() в самое начало main(), то проблема исчезает.

Т.е. беда в том, что таблица создается прямо в OnInit(), с этим какая-то проблема у терминала в случае, если скрипт автостартует при запуске терминала. Если же скрипт просто стартануть из диалога, то проблем с созданием пользовательской таблицы в OnInit() не возникает.

Надо зарепортить проблему разработчикам, может когда и поправят.

9

Re: Пользовательские таблицы

Спасибо. Век бы не докумекал перенести smile
Сейчас поэкспериментировал немного и выяснил следующее:
1. У меня работают 7 роботов, у 5 из них код абсолютно одинаковый, у 2 код похожий, но другая стратегия. Если присутствует хоть один робот с созданием таблицы в OnInit(), таблицы создаются вообще в рандомных вкладках, причем не во всех. Раскидываются по 3-4 вкладкам, всего их у меня 11. Причем закономерность не уловил, кроме того, что те, у которых таблица создается в OnInit() всегда отдельно от тех, у которых в main().
2. Если все роботы создают таблицу в main(), то все таблицы создаются именно в той вкладке, которая была активна перед закрытием квика.

Что то подозреваю, что дело все таки в самом терминале. Хотя с другой стороны, откуда ему знать в какой вкладке создавать таблицу smile

10 (2022-09-30 12:03:20 отредактировано swerg)

Re: Пользовательские таблицы

dark184 пишет:

Что то подозреваю, что дело все таки в самом терминале. Хотя с другой стороны, откуда ему знать в какой вкладке создавать таблицу

Разумеется.
И основная проблема - в том, что окно, созданное скриптом, отображается в нескольких вкладках (в описанном здесь вами сценарии). Это прям совсем проблема.
А то, что при создании таблиц нельзя штатно указать определенную вкладку - это отдельная история еще.

11

Re: Пользовательские таблицы

swerg пишет:

А то, что при создании таблиц нельзя штатно указать определенную вкладку - это отдельная история еще.

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

12

Re: Пользовательские таблицы

Для создания окна скрипта на нужной вкладке QUIK можно воспользоваться описанным в этой теме приёмом
[url]https://quik2dde.ru/viewtopic.php?id=329[/url]