Блог им. morefinances
Иногда бывает необходимым проанализировать не отдельную бумагу, а рынок в целом.
Кто-то смотрит для этого индексы, кто-то различные сантименты, а мне удобнее проводить анализ по динамике всех бумаг (сколько на дату эмитентов в совокупности растет, сколько бумаг выше своих месячных, квартальных или годовых значений и пр.). Каждый по своему может это использовать далее (как общий фильтр принятия решения для входа в сделку, для составления своих индексов, для анализа динамики своего портфеля – особенно если счетов несколько у разных брокеров и пр.).
Получить котировки на конкретную дату можно через сайт Московской Биржи (https://www.moex.com/ru/marketdata/#/mode=groups&group=4&collection=3&boardgroup=57&data_type=history&date=2023-06-27&category=main), но это не очень удобно т.к. требуется либо парсить (для чего нужен уже нетривиальный уровень в программировании), либо вручную выдергивать эту страницу, например в excel (тем, кто попробует выгрузить всё по кнопкам скачать Excel / CSV биржа предложит воспользоваться платной подпиской для получения данных).
В качестве альтернативы можно воспользоваться iss запросами (подробно расписано в руководстве разработчика в разделе «Программный интерфейс к ИСС» https://www.moex.com/a2193, все варианты запросов и параметров здесь: https://iss.moex.com/iss/reference/).
Акции можно выгрузить постранично по 100 эмитентов. Для примера на 27 июня 2023 года:
Уже в Excel я объединяю эти XML выгрузки и макросом отсекаю лишнюю информацию.
Эта возможность бесплатная (пока), но ничто не вечно: биржа может перестать поддерживать этот сервис (как ранее случилось с запросами ISSRPC) или сделает его платным.
Поэтому в какой-то момент я задумался о том, как это всё можно выгружать из торгового терминала. И здесь либо нужно работать с массивом тикеров, который самому необходимо ежедневного мониторить и обновлять на предмет новых бумаг или делистинга, либо делать это в автоматическом режиме. Я выбрал второй путь.
Небольшой скрипт на qlua проходит по всем возможным вариантам тикеров (от AAAA до ZZZZ) на предмет их торгуемости (=getParamEx(«TQBR», TIKER, 'STATUS').param_value), префы проверяются добавлением к тикеру «P». Отдельно приходится проверять торгуемость VEON-RX, т.к. она единственная выбивается из общего списка.
Результат записывается в файл tickers.csv на C:\files\ (папку files необходимо создать на C:\ до запуска скрипта, либо заменить в коде на свою).
function main()
message('[ = = = = = = = = = = start = = = = = = = = = = ]')
datetime = os.date("!*t",os.time())
message('Определение тикеров торгуемых бумаг на фондовой секции')
message(os.date("%d.%m.%Y"))
message('Начало работы скрипта '..os.date("%X",os.time()))
DirectionSaveFile=tostring("C:\\files\\tickers.csv")
my_csv=io.open(DirectionSaveFile,"w")
t = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
ind = 1
ind_two = 0
sprint = ""
for i=1, #t do
for j=1, #t do
for n=1, #t do
for m=1, #t do
TIKER = tostring(t[i])..tostring(t[j])..tostring(t[n])..tostring(t[m])
TIKERP = tostring(t[i])..tostring(t[j])..tostring(t[n])..tostring(t[m]).."P"
find_status=tonumber(getParamEx("TQBR",TIKER,'STATUS').param_value)
find_status2=tonumber(getParamEx("TQBR",TIKERP,'STATUS').param_value)
if find_status == 1 then
my_csv:write(TIKER)
my_csv:write("\n")
sprint = sprint..tostring(ind).."/ "..TIKER.." "
ind_two = ind_two + 1
ind = ind + 1
sleep(5)
end
if find_status2 == 1 then
my_csv:write(TIKERP)
my_csv:write("\n")
sprint = sprint..tostring(ind).."/ "..TIKERP.." "
ind_two = ind_two + 1
ind = ind + 1
sleep(5)
end
if ind_two >= 6 or (i==#t and i==j and n==m and i==n) then
message(sprint)
sprint=""
ind_two = 0
end
end
end
end
end
if tonumber(getParamEx("TQBR","VEON-RX",'STATUS').param_value) == 1 then
message(tostring(ind).." / ".."VEON-RX")
my_csv:write("VEON-RX")
sleep(5)
end
message('Завершение работы скрипта '.. os.date("%X",os.time()))
my_csv:flush()
my_csv:close()
message('Общее количество торгуемых бумаг : '..tostring(ind))
message("[ = = = = = = = = = = end = = = = = = = = = = ]")
endМинус этого скрипта – если появится тикер с цифрами, с большим количеством букв или c тире (как это случилось с VEON-RX), то такую бумагу скрипт не увидит, нужно будет добавить как исключение (как и сделано с VEONом) и далее скрипт будет точечно проверять эту бумагу на торгуемость.
Дополнительно результаты выводятся в терминале в таблице системных сообщениях (в настройках лучше отключить показ сообщений в отдельном окне).
Следующий скрипт запускается и уже по таймеру (HTimeOut – час выгрузки по МСК, MTimeOut — минуты) делает выгрузку всей необходимой для меня информации из таблицы текущих торгов. Тикеры берутся из только что полученного файла C:\files\tickers.csv (поэтому если меняли папку выше, то и в следующем скрипте нужно подправить). Я запускаю параллельно 2 подобных скрипта, один делает выгрузку в 18:55 под закрытие основной сессии, после чего сам выключается, второй в 23:55 и также выключается.
Статусы текущих состояний работы скриптов выводятся в отдельные таблички.
function OnInit()
--параметры таймера:
HTimeOut=18
MTimeOut=55
NameTableColumns = {'старт', 'таргет', 'текущий статус', 'время начала выгрузки'}
QCTanbles = { 9, 7, 55, 33 }
YPosConsts = {447, 526}
if HTimeOut <= 19 then
YPosTables = YPosConsts[1]
else
YPosTables = YPosConsts[2]
end
indTimer = 1680 -- таймер отключит скрипт через 7 часов (4*60*7=1680)
if HTimeOut < 10 then
otxt = "0"
else
otxt = ""
end
if MTimeOut < 10 then
ttxt = "0"
else
ttxt = ""
end
ProgramSmallName="dwnlds "..otxt..HTimeOut..":"..ttxt..MTimeOut
ProgramName="выгрузка цен закрытия и объемов торгов"
ProgramVersion="1.0.5. от 23.06.2023"
end
function OnStop()
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_csv=io.open(DirectionSaveFile,"a+")
if ind == 1 then
message("Скрипт "..ProgramSmallName.." остановлен по завершению работы", 2)
my_csv:write("Скрипт "..ProgramSmallName.." остановлен по завершению работы\n")
SetCell(m_t, 1, 3, "Скрипт остановлен по завершению работы")
Highlight(m_t, 1, 3, RGB(149, 200, 216), RGB(0,0,0), 600)
SetColor(m_t, 1, QTABLE_NO_INDEX, RGB(166, 220, 243), RGB(0,0,0), RGB(149,200,216), RGB(0,0,0))
end
if ind == 0 then
message("Скрипт "..ProgramSmallName.." остановлен пользователем")
my_csv:write("Скрипт "..ProgramSmallName.." остановлен пользователем\n")
SetCell(m_t, 1, 3, "Скрипт остановлен пользователем")
Highlight(m_t, 1, 3, RGB(149, 200, 216), RGB(0,0,0), 600)
SetColor(m_t, 1, QTABLE_NO_INDEX, RGB(197, 220, 243), RGB(0,0,0), RGB(149,200,216), RGB(0,0,0))
end
if ind == -1 then
message("Скрипт "..ProgramSmallName.." остановлен в период разрыва соединения", 3)
my_csv:write("Скрипт "..ProgramSmallName.." остановлен в период разрыва соединения\n")
SetCell(m_t, 1, 3, "Скрипт остановлен в период разрыва соединения")
Highlight(m_t, 1, 3, RGB(160, 160, 160), RGB(0,0,0), 600)
SetColor(m_t, 1, QTABLE_NO_INDEX, RGB(224, 224, 224), RGB(0,0,0), RGB(149,200,216), RGB(0,0,0))
end
if ind == 2 then
message("Скрипт "..ProgramSmallName.." остановлен по таймеру [ n >= "..indtre.." ] ", 3)
my_csv:write("Скрипт "..ProgramSmallName.." остановлен по таймеру [ n >= "..indtre.." ] \n")
SetCell(m_t, 1, 3, "Скрипт остановлен по таймеру [ n >= "..indtre.." ]")
Highlight(m_t, 1, 3, RGB(160, 160, 160), RGB(0,0,0), 600)
SetColor(m_t, 1, QTABLE_NO_INDEX, RGB(224, 224, 224), RGB(0,0,0), RGB(149,200,216), RGB(0,0,0))
end
myRun=false
message("<--- завершение "..ProgramSmallName..": "..ProgramName.." --->")
message("===========================================")
my_csv:write("<--- завершение "..ProgramSmallName..": "..ProgramName.." --->\n")
my_csv:write("===========================================\n")
my_csv:flush()
my_csv:close()
sleep(10)
end
function downloadsdata()
message("<-- "..ProgramSmallName.." -->")
message("<-- выгрузка данных -->")
message("подгрузка тикеров с С:/files/tickers.csv")
-- выгрузка тикеров С:\files\tickers.csv
t = {}
DirectionOpenFile=tostring("C:\\files\\tickers.csv")
f = io.open(DirectionOpenFile, "r");
for i=1, 300 do
t[i] = f:read("*l")
if t[i]==nil then break end
end
f:close()
message(ProgramSmallName.." Выгружено "..tostring(#t).." тикеров")
-- создание файла
datetime = os.date("!*t",os.time())
Hou_one = datetime.hour
Min_one = datetime.min
Sec_one = datetime.sec
Total_one = Hou_one * 60 * 60 + Min_one * 60 + Sec_one
mdate=getTradeDate()
if mdate.day<10 then
clockdate = " 0"..mdate.day
else
clockdate = mdate.day
end
if mdate.month < 10 then
clockdate = clockdate.." 0"..mdate.month.." "..mdate.year
else
clockdate = clockdate.." "..mdate.month.." "..mdate.year
end
if (Hou_one + 3) < 10 then
clocknamefile = "0"..tostring(Hou_one + 3)
else
clocknamefile = tostring(Hou_one + 3)
end
if Min_one < 10 then
clocknamefile = clocknamefile.." ".."0"..Min_one
else
clocknamefile = clocknamefile.." "..Min_one
end
if Sec_one < 10 then
clocknamefile = clocknamefile.." ".."0"..Sec_one
else
clocknamefile = clocknamefile.." "..Sec_one
end
DirectionSaveFile=tostring("C:\\files\\downloads "..clockdate.." "..clocknamefile..".csv")
my_csv=io.open(DirectionSaveFile,"a+")
--LEGALCLOSEPRICE 18:45 / Цена закрытия основной сессии
--CLOSE 23:50 / Цена закрытия дневной свечи (+ вечерняя сессия, если есть)
if (Hou_one + 3) < 23 then
my_csv:write("Тикер; OPEN; HIGH; LOW; LASTPRICE; Оборот (на 18:50); LCP; preLCP; preCP; LCP = LegalClosePrice (18:50); CP = ClosePrice (23:50) \n")
else
my_csv:write("Тикер; Open; High; Low; LastPrice; Оборот (на 23:50); LCP; CP ; preCP; LCP = LegalClosePrice (18:50); CP = ClosePrice (23:50)\n")
end
openprice = {}
highprice={}
lowprice = {}
lastprice = {}
closeprice = {}
legalcloseprice = {}
prevlegalcloseprice = {}
value = {}
for i = 1, #t do
-- проверка на торгуемость
if getParamEx("TQBR",t[i],'STATUS').param_value == 0 then
message(ProgramSmallName..' Тикер '..t[i]..' не торгуется')
my_csv:write(t[i].."; Не торгуется;\n")
sleep(5)
else
openprice[i] = tonumber(getParamEx("TQBR",t[i],'OPEN').param_value)
if openprice[i] == 0 then
for u=1, 10 do
sleep(100)
openprice[i] = tonumber(getParamEx("TQBR",t[i],'OPEN').param_value)
message(ProgramSmallName.." "..t[i]..": openprice_"..u)
if openprice[i]~=0 then break end
end
end
highprice[i] = tonumber(getParamEx("TQBR",t[i],'HIGH').param_value)
if highprice[i] == 0 then
for u=1, 10 do
sleep(100)
highprice[i] = tonumber(getParamEx("TQBR",t[i],'HIGH').param_value)
message(ProgramSmallName.." "..t[i]..": highprice_"..u)
if highprice[i]~=0 then break end
end
end
lowprice[i] = tonumber(getParamEx("TQBR",t[i],'LOW').param_value)
if lowprice[i] == 0 then
for u=1, 10 do
sleep(100)
lowprice[i] = tonumber(getParamEx("TQBR",t[i],'LOW').param_value)
message(ProgramSmallName.." "..t[i]..": lowprice_"..u)
if lowprice[i]~=0 then break end
end
end
lastprice[i] = tonumber(getParamEx("TQBR",t[i],'LAST').param_value)
if lastprice[i] == 0 then
for u=1, 10 do
sleep(100)
lastprice[i] = tonumber(getParamEx("TQBR",t[i],'LAST').param_value)
message(ProgramSmallName.." "..t[i]..": lastprice_"..u)
if lastprice[i]~=0 then break end
end
end
legalcloseprice[i] = tonumber(getParamEx("TQBR",t[i],'LCLOSEPRICE').param_value)
if legalcloseprice[i] == 0 and (Hou_one + 3) >= 18 then
for u=1, 10 do
sleep(1000)
legalcloseprice[i] = tonumber(getParamEx("TQBR",t[i],'LCLOSEPRICE').param_value)
message(ProgramSmallName.." "..t[i]..": legalcloseprice_"..u)
if tonumber(legalcloseprice[i]~=0) then break end
end
end
closeprice[i] = tonumber(getParamEx("TQBR",t[i],'PREVPRICE').param_value)
if closeprice[i] == 0 then
for u=1, 10 do
sleep(1000)
closeprice[i] = tonumber(getParamEx("TQBR",t[i],'PREVPRICE').param_value)
message(ProgramSmallName.." "..t[i]..": prevprice~close"..u)
if closeprice[i]~=0 then break end
end
end
prevlegalcloseprice[i] = tonumber(getParamEx("TQBR",t[i],'PREVLEGALCLOSEPR').param_value)
-- and ((Hou_one + 3) < 10 or (Hou_one + 3) >= 23)
if prevlegalcloseprice[i] == 0 then
for u=1, 10 do
sleep(1000)
prevlegalcloseprice[i] = tonumber(getParamEx("TQBR",t[i],'PREVLEGALCLOSEPR').param_value)
message(ProgramSmallName.." "..t[i]..": prevlegalcloseprice"..u)
if closeprice[i]~=0 then break end
end
end
value[i] = tonumber(getParamEx("TQBR",t[i],'VALTODAY').param_value)
if value[i] == 0 then
for u=1, 10 do
sleep(250)
value[i] = tonumber(getParamEx("TQBR",t[i],'VALTODAY').param_value)
message(ProgramSmallName.." "..t[i]..": value_"..u)
if tonumber(value[i]~=0) then break end
end
end
message(ProgramSmallName.." "..t[i].." : OPEN="..tostring(myint(openprice[i],2)).." / HIGH="..tostring(myint(highprice[i],2)).." / LOW="..tostring(lowprice[i]).."/ LAST= "..tostring(myint(lastprice[i],0)))
message(ProgramSmallName.." "..t[i].." : legalCP="..tostring(myint(legalcloseprice[i],2)).." / CP="..tostring(myint(closeprice[i],2)).." / PLCP="..tostring(prevlegalcloseprice[i]).."/ V= "..tostring(myint(value[i],0)))
my_csv:write(t[i]..";"..openprice[i]..";"..highprice[i]..";"..lowprice[i]..";"..lastprice[i]..";"..value[i]..";"..legalcloseprice[i]..";"..prevlegalcloseprice[i]..";"..closeprice[i]..";\n")
sleep(10)
end
sleep(10)
end
my_csv:flush()
my_csv:close()
datetime = os.date("!*t",os.time())
Hou_two = datetime.hour
Min_two = datetime.min
Sec_two = datetime.sec
Total_two = Hou_two * 60 * 60 + Min_two * 60 + Sec_two
message(ProgramSmallName.." Время выгрузки: "..tostring(Total_two-Total_one).." сек.")
message(ProgramSmallName.." <-- завершение процедуры выгрузки -->")
end
-- вывод чисел: отсекаем хвосты 000
function myint(numb, qual)
if qual == 0 then
return(tostring(math.floor(numb)))
end
if qual == 1 then
b = math.floor(numb)
c = math.ceil((numb - b)*10)
--message(b.."."..c)
return (b.."."..c)
end
if qual == 2 then
b = math.floor(numb)
c = math.ceil((numb - b)*100)
if c == 0 then
return(b.."."..c.."0")
else
return(b.."."..c)
end
end
end
function main()
-- создаём таблицу
if m_t==nil then
m_t=AllocTable()
for m=1, 4 do
AddColumn(m_t, m, NameTableColumns[m], true, QTABLE_STRING_TYPE, QCTanbles[m])
end
CreateWindow(m_t)
SetWindowPos(m_t, 0, YPosTables, 706, 80)
SetWindowCaption(m_t, ProgramSmallName..": "..ProgramName.." "..ProgramVersion)
InsertRow(m_t,-1)
end
myRun=true
message("===========================================", 2)
message("<--- cтарт "..ProgramSmallName..": "..ProgramName.." --->", 2)
message("<--- версия: "..ProgramVersion.." --->", 2)
message('Дата запуска: '..os.date("%d.%m.%Y"), 2)
message('Время старта: '..os.date("%X",os.time()), 2)
SetCell(m_t, 1, 1, tostring(os.date("%X",os.time())))
SetCell(m_t, 1, 2, otxt..HTimeOut..":"..ttxt..MTimeOut)
SetCell(m_t, 1, 3, "старт программы")
Highlight(m_t, 1, QTABLE_NO_INDEX, RGB(149,200,216), RGB(0,0,0), 600)
sleep(10)
--дублируем в логи
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_csv=io.open(DirectionSaveFile,"a+")
my_csv:write("===========================================\n")
my_csv:write("<--- cтарт "..ProgramSmallName..": "..ProgramName.." --->\n")
my_csv:write("<--- версия: "..ProgramVersion.." --->\n")
my_csv:write('Дата запуска: '..os.date("%d.%m.%Y").."\n")
my_csv:write('Время старта: '..os.date("%X",os.time()).."\n")
my_csv:flush()
my_csv:close()
sleep(10)
ind = 0 -- счетчик выключения программы
indtwo = 0 -- индикатор первой итерации
MM = 0 -- запись минут
indtre = 0 -- счетчик для отключения по таймеру
while myRun do
-- обработка таймера старта
datetime = os.date("!*t",os.time())
mHou = datetime.hour + 3
mMin = datetime.min
mSec = datetime.sec
TimerVar = mHou * 3600 + mMin * 60 + mSec
cnct = isConnected()
if indtwo == 0 then
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_csv=io.open(DirectionSaveFile,"a+")
if cnct == 1 then
if ind >= 0 then
message(ProgramSmallName.." <-- Связь с сервером на старте установлена -->", 2)
my_csv:write(ProgramSmallName.." <-- Связь с сервером на старте установлена -->\n")
SetCell(m_t, 1, 3, "Связь с сервером на старте установлена")
Highlight(m_t, 1, 3, RGB(149, 200, 216), RGB(0,0,0), 600)
sleep(10)
end
else
message(ProgramSmallName.." <-- Связь с сервером на старте разорвана -->", 3)
my_csv:write(ProgramSmallName.." <-- Связь с сервером на старте разорвана -->\n")
SetCell(m_t, 1, 3, "Связь с сервером на старте разорвана")
Highlight(m_t, 1, 3, RGB(160, 160, 160), RGB(0,0,0), 600)
ind = -1
OnStop()
myRun = false
end
my_csv:flush()
my_csv:close()
sleep(10)
end
if ind == -1 and cnct == 1 then
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_csv=io.open(DirectionSaveFile,"a+")
if mMin<10 then
stxtone="0"
else
stxtone=""
end
if mSec<10 then
stxttwo="0"
else
stxttwo=""
end
message(ProgramSmallName..": Связь восстановлена в "..mHou..":"..stxtone..mMin..":"..stxttwo..mSec, 2)
my_csv:write(ProgramSmallName..": Связь восстановлена в "..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."\n")
SetCell(m_t, 1, 3, "Связь восстановлена в "..mHou..":"..stxtone..mMin..":"..stxttwo..mSec)
Highlight(m_t, 1, 3, RGB(149, 200, 216), RGB(0,0,0), 600)
my_csv:flush()
my_csv:close()
sleep(10)
ind = 0
indtwo = 0
MM = 0
end
if cnct == 0 and indtwo == 1 then
if mMin<10 then
stxtone="0"
else
stxtone=""
end
if mSec<10 then
stxttwo="0"
else
stxttwo=""
end
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_csv=io.open(DirectionSaveFile,"a+")
message(ProgramSmallName..": <-- Связь с сервером прервана "..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.." -->", 3)
message(ProgramSmallName.." Переход в спящий режим, ждём возобновления связи", 3)
SetCell(m_t, 1, 3, "Связь с сервером прервана "..mHou..":"..stxtone..mMin..":"..stxttwo..mSec)
Highlight(m_t, 1, 3, RGB(160, 160, 160), RGB(0,0,0), 600)
my_csv:write(ProgramSmallName..": <-- Связь с сервером прервана "..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.." -->\n")
my_csv:write(ProgramSmallName.." Переход в спящий режим, ждём возобновления связи\n")
my_csv:flush()
my_csv:close()
sleep(10)
ind = -1
indtwo = -1
end
if indtwo == 0 then
MM = TimerVar
indtwo = 1
end
if mHou >= HTimeOut and mMin >= MTimeOut and cnct == 1 then
if mMin<10 then
stxtone="0"
else
stxtone=""
end
if mSec<10 then
stxttwo="0"
else
stxttwo=""
end
SetCell(m_t, 1, 3, "Процедура выгрузки данных")
Highlight(m_t, 1, 3, RGB(149, 200, 216), RGB(0,0,0), 600)
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_cs=io.open(DirectionSaveFile,"a+")
message(ProgramSmallName.." Timer downloads: "..mHou..":"..stxtone..tostring(mMin)..":"..stxttwo..tostring(mSec), 2)
my_cs:write(ProgramSmallName.." Timer downloads: "..mHou..":"..stxtone..tostring(mMin)..":"..stxttwo..tostring(mSec).."\n")
SetCell(m_t, 1, 4, " Timer downloads: "..mHou..":"..stxtone..tostring(mMin)..":"..stxttwo..tostring(mSec))
my_cs:flush()
my_cs:close()
sleep(10)
downloadsdata()
ind = 1
end
if TimerVar >= (MM + 5*60) then
if mMin<10 then
stxtone="0"
else
stxtone=""
end
if mSec<10 then
stxttwo="0"
else
stxttwo=""
end
--открываем файл для записи логов
DirectionSaveFile=tostring("C:\\files\\logs.csv")
my_csv=io.open(DirectionSaveFile,"a+")
if cnct == 1 then
message(ProgramSmallName.." timer ["..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."]")
-- фиксируем логи
my_csv:write(ProgramSmallName.." timer ["..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."]\n")
SetCell(m_t, 1, 3, "режим ожидания ["..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."]")
Highlight(m_t, 1, 3, RGB(149, 200, 216), RGB(0,0,0), 600)
sleep(10)
end
if cnct == 0 then
message(ProgramSmallName.." timer ["..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."] без сервера", 3)
-- фиксируем логи
my_csv:write(ProgramSmallName.." timer ["..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."] без сервера\n")
SetCell(m_t, 1, 3, " режим ожидания ["..mHou..":"..stxtone..mMin..":"..stxttwo..mSec.."] без сервера")
Highlight(m_t, 1, 3, RGB(160, 160, 160), RGB(0,0,0), 600)
sleep(10)
end
-- закрываем файл
my_csv:flush()
my_csv:close()
sleep(10)
MM = TimerVar
end
if ind == 1 then OnStop() end
-- счетчик в базовом варианте будет выставлен на 7 часов
if indtre >= indTimer then
ind = 2
OnStop()
end
--ожидание 15 секунд для разгрузки процессора
sleep(15000)
indtre = indtre + 1
end
endФайл записывает логи по которым можно смотреть всё ли прошло нормально в logs.csv.
В процессе выгрузки если получены нулевые значения, то скрипт ожидает 100 мс и перезапрашивает данные, если за 10 итераций ничего не получено (значит ничего и нет), то переходит далее. В списке (tickers) всегда есть бумаги, по которым торги не проводятся, но биржа их при этом отражает как торгуемые (через iss запросы они аналогично выгружаются с нулевыми объемами, но индикативными ценами).
Предусмотрено, что может отключаться сервер, скрипт ждет восстановления связи. Если далее связь возобновляется скрипт продолжает дожидаться нужного времени и штатно делает выгрузку. Если через 7 часов после старта (я запускаю в начале 6го) выгрузка не состоялась скрипт по таймеру (indTimer) выключает работу. Если ваш компьютер уходит в спящий режим, то скорее всего и терминал «засыпает». Поэтому у меня стоит в настройках никогда не уходить в спящий режим, чтобы всё корректно работало.
Результаты записываются в файлы downloads с датой и временем выгрузки в названии файла всё в той же C:\files\ директории.
Теги: выгрузки котировок на конец дня, qlua выгрузка из торгового терминала, кружок авиамоделизма.
Зачем такое оригинальное решение если можно просто получить список тикеров через getClassSecurities по коду TQBR?
Делал еще в купайле — там функция выдавала не строку, а список, который потом в цикле перебирался как то так
sec_code_list = get_class_securities(class_code)
for sec_code in sec_code_list
и шел по всем тикерам.
Нужно будет покрутить выдачу разными способами, спасибо!
В терминале сейчас посчитал да, ограничение на выдачу сообщения в 899 символов получается. Сама строка по запросу больше 1200 выходит, вот и отсекается.
В таком варианте проходит по всем тикерам в строке:
sec_list = getClassSecurities(«TQBR»)
for msec in string.gmatch(sec_list, "[^,]+") do
message(msec)
end
Попозже сделаю для желающих пост с обновленным первым скриптом, он теперь в разы компактнее.
https://github.com/morefinances/qlua
smart-lab.ru/blog/917203.php
1.убрать/закомментить ind = 1, ind =2 и OnStop в main.
2. Там же в main заменить в строке
>= на == в обоих случаях. Чтобы скрипт не уходил в вечную загрузку.
При этом если при наступлении времени выгрузки сервер брокера разорвет соединение, то скрипт просто ничего не выгрузит после автоматического переподключения. В оригинале у меня (при >=) выгружает.
После этих правок скрипт сам отключаться не будет и сам же повторно запустится через сутки (я не отключаю терминал). И его всегда можно будет отключить вручную в терминале в панеле скриптов.
Но логи будут обновляться при этом каждые 5 минут. Можете поставить ограничения по времени, чтобы вне торгов логи не сохранялись.
На форуме квика обсуждались разные варианты перезапусков скриптов. Как я понимаю, исправно работающих и красивых решений на qlua пока не нашли.