Блог им. AlekseyManin
Приветствую всех!
Сам я не программист, но решил написать скрипт, который будет выводить табличку по доходности синтетических облигаций (покупка акций/продажа фьючерса). Идея в получении дохода от контанго. Скрипт работает и табличка выводится, но через некоторое время появляется ошибка о недостатке памяти.
Подскажите, что я сделал не так?
<code>-- ©2022 by Aleksey Manin -- Таблица расчета доходности синтетической облигации -- Какие инструменты(тикеры) отслеживаем. Таблица пар тикер - площадка tickers = {GAZP = {GAZP = "TQBR", GZZ2 = "SPBFUT"}, SBER = {SBER = "TQBR", SRZ2 = "SPBFUT"}, PLZL = {PLZL = "TQBR", PZZ2 = "SPBFUT"}, GMKN = {GMKN = "TQBR", GKZ2 = "SPBFUT"}, LKOH = {LKOH = "TQBR", LKZ2 = "SPBFUT"}, AFLT = {AFLT = "TQBR", AFZ2 = "SPBFUT"}, NVTK = {NVTK = "TQBR", NKZ2 = "SPBFUT"}, YNDX = {YNDX = "TQBR", YNZ2 = "SPBFUT"}, --MOEX = {MOEX = "TQBR", MXZ2 = "SPBFUT"}, ALRS = {ALRS = "TQBR", ALZ2 = "SPBFUT"}, VTBR = {VTBR = "TQBR", VBZ2 = "SPBFUT"}, SNGS = {SNGS = "TQBR", SNZ2 = "SPBFUT"}, MGNT = {MGNT = "TQBR", MNZ2 = "SPBFUT"}, NLMK = {NLMK = "TQBR", NMZ2 = "SPBFUT"}, MTSS = {MTSS = "TQBR", MTZ2 = "SPBFUT"}, ROSN = {ROSN = "TQBR", RNZ2 = "SPBFUT"}} rows = {} -- Список строк в таблице по количеству тикеров oblig_t = AllocTable() -- Указатель на саму таблицу stopped = false -- Остановка скрипта -- Функция вызывается перед вызовом main function OnInit(path) AddColumn(oblig_t, 0, "Ticker_BA", true, QTABLE_STRING_TYPE, 8) -- "Ticker"- название первого столбца в таблице AddColumn(oblig_t, 1, "Lot_BA", true, QTABLE_INT_TYPE, 8) -- AddColumn(oblig_t, 2, "Ask_BA", true, QTABLE_DOUBLE_TYPE, 10) -- AddColumn(oblig_t, 3, "Ticker_F", true, QTABLE_STRING_TYPE, 10) -- AddColumn(oblig_t, 4, "Lot_F", true, QTABLE_INT_TYPE, 8) -- AddColumn(oblig_t, 5, "Bid_F", true, QTABLE_DOUBLE_TYPE, 10) -- AddColumn(oblig_t, 6, "Day_EXP", true, QTABLE_INT_TYPE, 10) -- AddColumn(oblig_t, 7, "Date_EXP", true, QTABLE_DATE_TYPE, 15) -- AddColumn(oblig_t, 8, "Dohod%", true, QTABLE_DOUBLE_TYPE, 10) -- AddColumn(oblig_t, 9, "Dohod", true, QTABLE_DOUBLE_TYPE, 10) -- CreateWindow(oblig_t) -- Создание окна таблицы SetWindowCaption(oblig_t, "Синтетическая облигация") -- Даем название таблице for ticker, two in pairs(tickers) do -- Перебираем пары БА-Фьючерс rows[ticker] = InsertRow(oblig_t, -1) -- Заносим тикер в список строк end end function Run() for ticker, two in pairs(tickers) do -- Перебираем пары БА-Фьючерс ask_ba = 0.0 bid_f = 0.0 lot_f = 0 for ticker_two, board in pairs(two) do -- Перебираем Тикеры внутри пары БА-Фьючерс if ticker == ticker_two then -- Если Тикер БА SetCell(oblig_t, rows[ticker], 0, ticker_two) -- Заполняем ячейке Тикера БА SetCell(oblig_t, rows[ticker], 1, -- Заполняем лот БА string.format("%u", getParamEx (board, ticker_two, "LOTSIZE").param_value)) ask_ba = getParamEx (board, ticker_two, "OFFER").param_value SetCell(oblig_t, rows[ticker], 2, string.format("%.2f", ask_ba)) -- Аск БА else -- Если Тикер фьючерса SetCell(oblig_t, rows[ticker], 3, ticker_two) -- Заполняем ячейку Тикера фьючерса lot_f = getParamEx (board, ticker_two, "LOTSIZE").param_value SetCell(oblig_t, rows[ticker], 4, string.format("%u", lot_f)) bid_f = getParamEx (board, ticker_two, "BID").param_value SetCell(oblig_t, rows[ticker], 5, string.format("%u", bid_f)) day_exp = getParamEx (board, ticker_two, "DAYS_TO_MAT_DATE").param_value SetCell(oblig_t, rows[ticker], 6, string.format("%u", day_exp)) SetCell(oblig_t, rows[ticker], 7, string.format("%u", getParamEx (board, ticker_two, "MAT_DATE").param_value)) --message('Дата:'..getParamEx (board, ticker_two, "MAT_DATE").param_type) end end sum_ba = ask_ba * lot_f --message('Тикер:'..ticker..' lot_f:'..lot_f..' sum_ba:'..sum_ba) sum_year = (bid_f - sum_ba) / day_exp * 365 percent = sum_year * 100 / sum_ba SetCell(oblig_t, rows[ticker], 8, string.format("%.2f", percent)) SetCell(oblig_t, rows[ticker], 9, string.format("%.2f", bid_f - sum_ba)) end end -- Функция вызывается перед остановкой скрипта function OnStop(signal) stopped = true end -- Функция вызывается перед закрытием квика function OnClose() stopped = true end; -- Основная функция выполнения скрипта function main() while not stopped do Run() sleep(10) end end</code>
При sleep(10) вы опрашиваете 100 в секунду.
При проблемах связи вы тупо забиваете запросами.
Нужно ли вам чаще чем 1 раз в минуту данные?
Так что ставите sleep не меньше 1000 — раз в секунду, а то и раз в минуту.
Либо оборачивайте в колбек обновления таблицы параметров.
не спрашивать каждый момент, а реагировать на изменения
Просто у разных брокеров с серверов приходят разные времена срабатывания колбека. И часто onParam по ходит пачкой.
Хотя данными замерами я занимался давно. Может что и поменялось
вам точно подойдет onParam.
OnParam (STRING class_code, STRING sec_code)
вашу логику вижу так:
1. при запуске скрипта, при подключении / переподключении — создаете таблицы, формируете список тикеров, добавляете константы (параметры тикеров, как тикер базового актива, лот, данные экспирации и т.д.) и остальные, как доход, аски/биды и т.п.
2. при колбеке ОнПарам проверяете нужен ли вам колбек по пришедшему тикеру и обрабатываете свежие данные.
3. проверяйте есть ли связь с сервером, ведутся ли торги.
хотя может вам нужно смотреть стакан, то тогда через OnQuote, только незабудьте запросить стакан котировок getQuoteLevel2. но тут не совсем актуальная информация изза левых заявок роботов, которые то ставятся, то снимаются.
если нужны данные про прошедшей сделки, то через OnAllTrade. прошла сделка — обработали таблицу по новым данным.
вывод в эксель намного быстрее настраивается и поддерживается
*себе сделал в эксель, ковырять lua нет настроения
**и еще разве скрипт работает когда QUIK не активное окно? (у меня в QUIK РСХБ если ушел смотреть youtube, то скрипт останавливается — не знаю почему)
в общем 2 quik пишут в один эксель у меня
за 20 минут в lua можно только понять что это)
не настаиваю на экселе. если хочется робота на lua, то пусть
и у меня есть робот, но на экселе)
тут согласен, помучился, и то потому что не понятно какие коды инструмента надо было вписывать. а теперь все гуд
Quik->DDE->Excel->VBA->File->Quik
или
Quik->DDE->Excel->Python(pandas)->File->Quik
Подскажите, а через Python, хуже будет работать? Типа, дольше?
Ведь в VBA можно прописать скрипт автосохранения файла обновляемого по DDE, а потом этот файл считать Пайтоном.
или на другой версии qlua запустить