Помогите написать скрипт на актуальном языке Lua

Страницы: 1
RSS
Помогите написать скрипт на актуальном языке Lua
 
Надеюсь на помнимание, задачу ныжно делать прямо сейчас а скрипт на qpile перестал работать.
Помогите создать минимальный скрипт в стиле "Привет мир" на Lua

Нужно выгрузить из Квика 9.7.1.10 котировку например акции газпрома  с округлением до десятой доли после точки.в тектовый файл.

В полученном файлу будет одна строка.

GAZP 168.1

Нужно что бы обновлялось (перезаписывалось раз в 10-30 секунд)

Дальше я уже додумаю как дописать и другие интрументы.
 
Программисты, Ау,
Кто готов помочь?
Реально нужно начинать делать новый скрипт уже сегодня, размеры благадарности обсуждаются, пишите в личку.
 
Можно начать вот с этого примера, который сохраняет цену last для GAZP в файл в корне диска D:

Код
local classCode = "TQBR"
local secCode = "GAZP"
local param = "last"
local filename = "D:/" .. classCode .. "_" .. secCode .. ".txt"
local pauseDurationMillis = 10000
local sleepDurationMillis = 100
local isInterrupted = false

local function printValue(value)
    local file = io.open(filename, "w+")
    if file then
        file:write(tostring(value))
        file:close()
    end
end

local function exportParam()
    local paramEx = getParamEx(classCode, secCode, param)
    if paramEx.result == "1" then
        printValue(paramEx.param_value)
    end
end

local function pause(durationMillis)
    while durationMillis > 0 and not isInterrupted do
        sleep(math.min(durationMillis, sleepDurationMillis))
        durationMillis = durationMillis - sleepDurationMillis
    end
end

function OnStop()
    isInterrupted = true
end

function main()
    ParamRequest(classCode, secCode, param)
    while not isInterrupted do
        exportParam()
        pause(pauseDurationMillis)
    end
end
 
Спасибо _sk_, скрипт работает!

Сейчас начну подгонять под свои хотелки.

По ходу уточню, запускать лучше в 5.4.1 или 5.3.5?
 
Без разницы, я использую 5.4.1.
 
У меня будут  биржевые инструменты (котировки все в одном файле), это как снимок текущей обстановки на бирже по нескольким бумагам.
выходной файл я сделал статичным
Код
local filename = "!outs.txt"
И перед значением нужно добавить название бумаги.

На выходе  будет название бумаги (пробел) котировка с округлением до десятой доли.
Следующая строка другой инструмент.

GAZP 169.9
SBER 127.3

Пробовал сам так сделать, но пока не работает...
 
Цитата
Пробовал сам так сделать, но пока не работает...

Беда...

Код
local securities = {
  { classCode = "TQBR", secCode = "SBER", },
  { classCode = "TQBR", secCode = "GAZP", },
  { classCode = "SPBFUT", secCode = "LKZ2", }
}

local param = "last"
local filename = "D:/last_quotes.txt"
local pauseDurationMillis = 10000
local sleepDurationMillis = 100
local isInterrupted = false
local file

local function requestParams()
    for _, security in ipairs(securities) do
        ParamRequest(security.classCode, security.secCode, param)
    end
end

local function exportQuote(security)
    local paramEx = getParamEx(security.classCode, security.secCode, param)
    if paramEx.result == "1" then
        file:write(security.secCode, " ", tostring(paramEx.param_value), "\n")
    end
end

local function exportQuotes()
    file = io.open(filename, "w+")
    if file then
        for _, security in ipairs(securities) do
            exportQuote(security)
        end
        file:close()
    end
end

local function pause(durationMillis)
    while durationMillis > 0 and not isInterrupted do
        sleep(math.min(durationMillis, sleepDurationMillis))
        durationMillis = durationMillis - sleepDurationMillis
    end
end

function OnStop()
    isInterrupted = true
end

function main()
    requestParams()
    while not isInterrupted do
        exportQuotes()
        pause(pauseDurationMillis)
    end
end

 
Скрипт в второй редакции просто отличный, компактный. Работает очень быстро.

Не такой популярный язык LUA, обзвонил всех знакомых кто в IT, ни кто этот язык не знает... интуитивно  обычной логикой тоже наскоком его не понять.
Сейчас проблема в следующем.

Актуальный по экспирации фьючерс по нефти BRENT внутри квика имеет код  BRENT0123 в классе FEG но его выгрузке нужно показать как просто BRENT без месяца и года.
И следом указать как OIL с значением % изменения от закрытия "LASTCHANGE"

В выгрузке вот в таком виде с округлением:

BRENT 92.58 OIL -0.3
 
Цитата
Скрипт в второй редакции просто отличный, компактный. Работает очень быстро.

С чего бы ему медленно работать, тут же все очень быстро происходит.

Цитата
Не такой популярный язык LUA, обзвонил всех знакомых кто в IT, ни кто  этот язык не знает... интуитивно  обычной логикой тоже наскоком его не  понять.

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

Код
local securities = {
    { 
        classCode = "TQBR",
        secCode = "SBER",
        params = {
            { name = "SBER", param = "last", format = "%.2f", }, 
            { name = "Сбер", param = "lastChange", format = "%.1f", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GAZP",
        params = { 
            { name = "GAZP", param = "last", format = "%.2f", }, 
        },
    },
    {
        classCode = "SPBFUT",
        secCode = "BRF3",
        params = {
            { name = "BR", param = "last", format = "%.2f", },
            { name = "OIL", param = "lastChange", format = "%.2f", }, 
        },
    },
}

local filename = "D:/last_quotes.txt"
local pauseDurationMillis = 10000
local sleepDurationMillis = 100
local isInterrupted = false
local file

local function requestParams()
    for _, security in ipairs(securities) do
        for _, securityParams in ipairs(security.params) do
            ParamRequest(security.classCode, security.secCode, securityParams.param)
        end
    end
end

local function exportQuotesForSecurity(security)
    for i, securityParams in ipairs(security.params) do
        local paramEx = getParamEx(security.classCode, security.secCode, securityParams.param)
        if paramEx.result == "1" then
            if i > 1 then
                file:write(" ")
            end
            file:write(securityParams.name, " ", string.format(securityParams.format, paramEx.param_value))
        end
    end
    file:write("\n")
end

local function exportQuotes()
    file = io.open(filename, "w+")
    if file then
        for _, security in ipairs(securities) do
            exportQuotesForSecurity(security)
        end
        file:close()
    end
end

local function pause(durationMillis)
    while durationMillis > 0 and not isInterrupted do
        sleep(math.min(durationMillis, sleepDurationMillis))
        durationMillis = durationMillis - sleepDurationMillis
    end
end

function OnStop()
    isInterrupted = true
end

function main()
    requestParams()
    while not isInterrupted do
        exportQuotes()
        pause(pauseDurationMillis)
    end
end

 
Цитата
Forbius написал:

Не такой популярный язык LUA, обзвонил всех знакомых кто в IT, ни кто этот язык не знает... интуитивно  обычной логикой тоже наскоком его не понять.
https://eligovision.ru/media/upload/lua.pdf
 
Уважаемый _SK_

Третья версия отлично работает!  

Сейчас добавлю все свои интрументы, посмотрю что получается в итоге.
 
Цитата
Forbius написал:
интуитивно  обычной логикой тоже наскоком его не понять
насмешил )), наверное нет более простого и интуитивно понятного языка упрощающего жизнь любому программисту самоучке, абсолютно не знающему никакого языка программирования
                       
 
nikolz - за ссылку спасибо за ссылку на книжку по программированию, изучаю.

_sk_  в 3-ю версию скрипта добавил все нужные мне инструменты, настроил округление (от 1 до 3 знаков после запятой) выгружается все моментально.
получился большой вертикальный столбик.
Как переформатировать вывод что бы бумаги с доп секцией lastchange оставить на отдельной строке, а "обычные" акции сделать по две на строку как в примере ниже:

BRENT 92.60 -0.3
GAZP 169.2 SBER 139.2
AFLT 25.1 GMKN 15072
 
Наблюдаем в прямом эфире рождение чёткого ТЗ от заказчика :)

Цитата
Как переформатировать вывод что бы бумаги с доп секцией lastchange  оставить на отдельной строке, а "обычные" акции сделать по две на строку  как в примере ниже:

Примерно так:

Код
local securities = {
    {
        classCode = "SPBFUT",
        secCode = "BRF3",
        params = {
            { prefix = "", name = "BRENT", delimiter = " ", param = "last", format = "%.2f", suffix = " ", },
            { prefix = "", name = "OIL", delimiter = " ", param = "lastChange", format = "%.1f", suffix = "\n", }, 
        },
    },
    {
        classCode = "SPBFUT",
        secCode = "GDZ2",
        params = {
            { prefix = "на всякий случай :) ", name = "GOLD", delimiter = " ", param = "last", format = "%.1f", suffix = " ", },
            { prefix = "", name = "золото", delimiter = " ", param = "lastChange", format = "%.2f", suffix = "\n", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GAZP",
        params = { 
            { prefix = "", name = "GAZP", delimiter = " ", param = "last", format = "%.2f", suffix = " ", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "SBER",
        params = {
            { prefix = "", name = "SBER", delimiter = " ", param = "last", format = "%.2f", suffix = "\n", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "AFLT",
        params = { 
            { prefix = "", name = "AFLT", delimiter = " ", param = "last", format = "%.2f", suffix = " ", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GMKN",
        params = {
            { prefix = "", name = "GMKN", delimiter = " ", param = "last", format = "%.0f", suffix = "\n", }, 
        },
    },
}

local filename = "D:/last_quotes.txt"
local pauseDurationMillis = 10000
local sleepDurationMillis = 250
local isInterrupted = false
local file

local function requestParams()
    for _, security in ipairs(securities) do
        for _, securityParams in ipairs(security.params) do
            if not ParamRequest(security.classCode, security.secCode, securityParams.param) then
                message("Не удалось заказать: "
                    .. tostring(security.classCode) .. ", "
                    .. tostring(security.secCode) .. ", "
                    .. tostring(securityParams.param), 2)
            end
        end
    end
end

local function exportQuotesForSecurity(security)
    for i, securityParams in ipairs(security.params) do
        local paramEx = getParamEx(security.classCode, security.secCode, securityParams.param)
        if paramEx.result == "1" then
            file:write(
                securityParams.prefix or "",
                securityParams.name or "",
                securityParams.delimiter or " ",
                string.format(securityParams.format, paramEx.param_value), 
                securityParams.suffix or "")
        else
            message("Не удалось экспортировать: "
                .. tostring(security.classCode) .. ", "
                .. tostring(security.secCode) .. ", "
                .. tostring(securityParams.param), 2)
        end
    end
end

local function exportQuotes()
    file = io.open(filename, "w+")
    if file then
        for _, security in ipairs(securities) do
            exportQuotesForSecurity(security)
        end
        file:close()
    end
end

local function pause(durationMillis)
    while durationMillis > 0 and not isInterrupted do
        sleep(math.min(durationMillis, sleepDurationMillis))
        durationMillis = durationMillis - sleepDurationMillis
    end
end

function OnStop()
    isInterrupted = true
end

function main()
    message("Скрипт экспорта котировок запущен.", 1)
    requestParams()
    while not isInterrupted do
        exportQuotes()
        pause(pauseDurationMillis)
    end
    message("Скрипт экспорта котировок остановлен.", 1)
end

 
При использовании скрипта надо обращать внимание, что в файле с кодом используется кодировка CP1251, иначе вместо русских букв будут кракозябры. Либо всё по-английски писать:
Cannot request parameter:
Cannot export:
Script started.
Script stopped.
 
В предыдущем скрипте можно упростить описание массива инструментов: префиксы, суффиксы, разделители, переводы строки и название инструмента поместить в строку format. Так получается компактнее. Функционал не должен пострадать. Неудобство может возникнуть только если придётся экранировать какие-либо символы в названии инструмента (скажем, если в названии присутствует знак процента или ещё что-то в этом рода).

Код
local securities = {
    {
        classCode = "SPBFUT",
        secCode = "BRF3",
        params = {
            { param = "last", format = "BRENT %.2f ", }, -- название пишем прямо в строке format, в конце добавляем пробел
            { param = "lastChange", format = "OIL %.1f\n", }, -- тут в конце строки format добавляем перевод строки
        },
    },
    {
        classCode = "SPBFUT",
        secCode = "GDZ2",
        params = {
            { param = "last", format = "GOLD %.1f ", },
            { param = "lastChange", format = "%.2f\n", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GAZP",
        params = { 
            { param = "last", format = "GAZP %.2f ", }, -- в конце пробел, чтобы отделить от следующего инструмента 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "SBER",
        params = {
            { param = "last", format = "SBER %.2f\n", }, -- в конце перевод строки
        },
    },
    { 
        classCode = "TQBR",
        secCode = "AFLT",
        params = { 
            { param = "last", format = "AFLT %.2f ", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GMKN",
        params = {
            { param = "last", format = "GMKN %.0f\n", }, 
        },
    },
}

local filename = "D:/last_quotes.txt"
local pauseDurationMillis = 10000
local sleepDurationMillis = 250
local isInterrupted = false
local file

local function requestParams()
    for _, security in ipairs(securities) do
        for _, securityParams in ipairs(security.params) do
            if not ParamRequest(security.classCode, security.secCode, securityParams.param) then
                message("Не удалось заказать: "
                    .. tostring(security.classCode) .. ", "
                    .. tostring(security.secCode) .. ", "
                    .. tostring(securityParams.param), 2)
            end
        end
    end
end

local function exportQuotesForSecurity(security)
    for i, securityParams in ipairs(security.params) do
        local paramEx = getParamEx(security.classCode, security.secCode, securityParams.param)
        if paramEx.result == "1" then
            file:write(string.format(securityParams.format, paramEx.param_value))
        else
            message("Не удалось экспортировать: "
                .. tostring(security.classCode) .. ", "
                .. tostring(security.secCode) .. ", "
                .. tostring(securityParams.param), 2)
        end
    end
end

local function exportQuotes()
    file = io.open(filename, "w+")
    if file then
        for _, security in ipairs(securities) do
            exportQuotesForSecurity(security)
        end
        file:close()
    end
end

local function pause(durationMillis)
    while durationMillis > 0 and not isInterrupted do
        sleep(math.min(durationMillis, sleepDurationMillis))
        durationMillis = durationMillis - sleepDurationMillis
    end
end

function OnStop()
    isInterrupted = true
end

function main()
    message("Скрипт экспорта котировок запущен.", 1)
    requestParams()
    while not isInterrupted do
        exportQuotes()
        pause(pauseDurationMillis)
    end
    message("Скрипт экспорта котировок остановлен.", 1)
end

 
Я бы вообще бы вынес описание инструментов в текстовый файл,
чтобы можно было менять набор не зная луа и не редактируя скрипт.
 
У меня на компе в итоговый файл русские буквы пишутся норм без проблем.
А сообщения из скрипта типо "Скрипт экспорта котировок запущен."  кракозябрами, но это мелочи, переписал сообщения на английском.

Загляните в вхоядище ЛК сообщения. Нужно уточнить одну деталь.
 
Цитата
nikolz написал:
Я бы вообще бы вынес описание инструментов в текстовый файл,
чтобы можно было менять набор не зная луа и не редактируя скрипт.
К этому уже всё идёт. :)
 
С учётом высказанных пожеланий.

1) Создаём два файла. В одном описываются настройки и вызывается второй файл, содержащий код. Оба файла должны лежать в одной папке. Запускать надо ParamExportConfig.lua.

Файл ParamExportConfig.lua:
Код
--- Функция для условного форматирования: до момента hhmm используется format1, после -- format2
local function formatHHMM(hhmm, format1, format2)
    return function()
        local dt = os.sysdate()
        if dt.hour * 100 + dt.min < hhmm then          
            return format1
        else
            return format2
        end
    end
end

-- Настройки для вывода котировок
securities = {
    {
        line = "GAZ ----\n", -- в конце перевод строки
    },
    {
        classCode = "SPBFUT",
        secCode = "BRF3",
        params = {
            { param = "last", format = "BRENT %.2f ", }, -- в конце пробел-разделитель
            { param = "lastChange", format = "OIL %.1f\n", }, -- в конце перевод строки
        },
    },
    {
        classCode = "SPBFUT",
        secCode = "GDZ2",
        params = {
            { param = "last", format = "GOLD %.1f ", },
            { param = "lastChange", format = "%.2f\n", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GAZP",
        params = { 
            { param = "last", format = "GAZP %.2f ", },
        },
    },
    { 
        classCode = "TQBR",
        secCode = "SBER",
        params = {
            { param = "last", format = "SBER %.2f\n", },
        },
    },
    { 
        classCode = "TQBR",
        secCode = "AFLT",
        params = { 
            { param = "last", format = "AFLT %.2f ", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "GMKN",
        params = {
            { param = "last", format = "GMKN %.0f\n", }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "MGNT",
        params = { 
            { param = "last", format = formatHHMM(1837, "MGNT --\n", "MGNT %.1f\n"), }, 
        },
    },
    { 
        classCode = "TQBR",
        secCode = "MOEX",
        params = { 
            { param = "last", format = formatHHMM(1837, "", "MOEX %.2f\n"), }, 
        },
    },
}

filename = "D:/last_quotes.txt"
pauseDurationMillis = 10000
sleepDurationMillis = 250

dofile(getScriptPath() .. "/ParamExportCode.lua")


Файл ParamExportCode.lua:
Код
local isInterrupted = false
local file

local function valueOf(x)
    return type(x) == "function" and x() or x
end

local function requestParams()
    for _, security in ipairs(securities) do
        if type(security.params) == "table" then
            for _, securityParams in ipairs(security.params) do
                if not ParamRequest(security.classCode, security.secCode, securityParams.param) then
                    message("Cannot request: "
                            .. tostring(security.classCode) .. ", "
                            .. tostring(security.secCode) .. ", "
                            .. tostring(securityParams.param), 2)
                end
            end
        end
    end
end

local function exportQuotesForSecurity(security)
    if type(security.line) == "string" then
        file:write(tostring(security.line))
    elseif type(security.params) == "table" then
        for i, securityParams in ipairs(security.params) do
            local paramEx = getParamEx(security.classCode, security.secCode, securityParams.param)
            if paramEx.result == "1" then
                file:write(string.format(valueOf(securityParams.format), paramEx.param_value))
            else
                message("Cannot export: "
                        .. tostring(security.classCode) .. ", "
                        .. tostring(security.secCode) .. ", "
                        .. tostring(securityParams.param), 2)
            end
        end
    end
end

local function exportQuotes()
    file = io.open(filename, "w+")
    if file then
        for _, security in ipairs(securities) do
            exportQuotesForSecurity(security)
        end
        file:close()
    end
end

local function pause(durationMillis)
    while durationMillis > 0 and not isInterrupted do
        sleep(math.min(durationMillis, sleepDurationMillis))
        durationMillis = durationMillis - sleepDurationMillis
    end
end

function OnStop()
    isInterrupted = true
end

function main()
    message("Export started.", 1)
    requestParams()
    while not isInterrupted do
        exportQuotes()
        pause(pauseDurationMillis)
    end
    message("Export stopped.", 1)
end


2) Добавлена функция для реализации форматирования в зависимости от времени formatHHMM. В примере конфига для MGNT выводим прочерк до указанного момента времени и цену в остальное время, для MOEX не выводим ничего (пустая строка) до указанного момента и цену в остальное время. Возможно, придётся доработать эту функцию, чтобы указать время перехода с format2 на format1 (сейчас это полночь). В os.sysdate() используется локальное время компа.

3) По-моему, этого кода должно быть достаточно для реализации всех пожеланий. Пробуйте.
 
Наконец, можно ещё учесть, что скрипт должен работать только по будням в какой-то промежуток времени. Для этого написать в конце конфига:
Код
filename = "D:/last_quotes.txt"
pauseDurationMillis = 10000
sleepDurationMillis = 250
startExportHHMM = 0900
stopExportHHMM = 2300

dofile(getScriptPath() .. "/ParamExportCode.lua")

и изменить код, начиная с OnStop(), в файле с кодом:
Код
local function isExportTime()
    local dt = os.sysdate()
    local hhmm = dt.hour * 100 + dt.min
    return startExportHHMM <= hhmm and hhmm < stopExportHHMM and 1 <= dt.week_day and dt.week_day <= 5
end

function OnStop()
    isInterrupted = true
end

function main()
    message("Export started.", 1)
    requestParams()
    while not isInterrupted do
        if isExportTime() then
            exportQuotes()
        end
        pause(pauseDurationMillis)
    end
    message("Export stopped.", 1)
end
 
На сколько помню, в течении года бывает исключение когда биржа работает в субботу. Могу ошибаться но черная суббота вроде как бывает. Как бы не получить сюрприз от скрипла в такой день когда ожидаешь не напряжный рабочий график и бац скрипт пишет "выходной". А если совпало с отпуском когда за терминалом кто то из младших помощников тогда совмес беда....
 
Цитата
Forbius написал:
На сколько помню, в течении года бывает исключение когда биржа работает в субботу. Могу ошибаться но черная суббота вроде как бывает. Как бы не получить сюрприз от скрипла в такой день когда ожидаешь не напряжный рабочий график и бац скрипт пишет "выходной". А если совпало с отпуском когда за терминалом кто то из младших помощников тогда совмес беда....
Нужно тогда как у сервера quik в конфиге предусмотреть параметр
типо WorkDay= 29022023
 
определить торговый или не торговый день,
а также есть ли догружаемые записи (это для тех кого волнует все или не все в таблицах свечей и обезличенных сделок)
можно по параметрам информационного окна.
Страницы: 1
Читают тему
Наверх