Надеюсь на помнимание, задачу ныжно делать прямо сейчас а скрипт на 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
У меня будут биржевые инструменты (котировки все в одном файле), это как снимок текущей обстановки на бирже по нескольким бумагам. выходной файл я сделал статичным
Код
local filename = "!outs.txt"
И перед значением нужно добавить название бумаги.
На выходе будет название бумаги (пробел) котировка с округлением до десятой доли. Следующая строка другой инструмент.
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"
Скрипт в второй редакции просто отличный, компактный. Работает очень быстро.
С чего бы ему медленно работать, тут же все очень быстро происходит.
Цитата
Не такой популярный язык 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 написал: интуитивно обычной логикой тоже наскоком его не понять
насмешил )), наверное нет более простого и интуитивно понятного языка упрощающего жизнь любому программисту самоучке, абсолютно не знающему никакого языка программирования
nikolz - за ссылку спасибо за ссылку на книжку по программированию, изучаю.
_sk_ в 3-ю версию скрипта добавил все нужные мне инструменты, настроил округление (от 1 до 3 знаков после запятой) выгружается все моментально. получился большой вертикальный столбик. Как переформатировать вывод что бы бумаги с доп секцией lastchange оставить на отдельной строке, а "обычные" акции сделать по две на строку как в примере ниже:
Наблюдаем в прямом эфире рождение чёткого ТЗ от заказчика :)
Цитата
Как переформатировать вывод что бы бумаги с доп секцией 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
У меня на компе в итоговый файл русские буквы пишутся норм без проблем. А сообщения из скрипта типо "Скрипт экспорта котировок запущен." кракозябрами, но это мелочи, переписал сообщения на английском.
Загляните в вхоядище ЛК сообщения. Нужно уточнить одну деталь.
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) По-моему, этого кода должно быть достаточно для реализации всех пожеланий. Пробуйте.
и изменить код, начиная с 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
определить торговый или не торговый день, а также есть ли догружаемые записи (это для тех кого волнует все или не все в таблицах свечей и обезличенных сделок) можно по параметрам информационного окна.