Блог им. AlekseyManin

Синтетическая облигация. Помогите с Qlua.

Приветствую всех!

Сам я не программист, но решил написать скрипт, который будет выводить табличку по доходности синтетических облигаций (покупка акций/продажа фьючерса). Идея в получении дохода от контанго. Скрипт работает и табличка выводится, но через некоторое время появляется ошибка о недостатке памяти.

Подскажите, что я сделал не так?

Синтетическая облигация. Ошибка памяти.
<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>
  • обсудить на форуме:
  • Quik Lua
★1
23 комментария
Помимо того что всегда выводятся данные, которые можно вывести один раз (размер лота, экспирация), стоит увеличить sleep до 50. При работе с таблицами это уже важно.
avatar
nicknh, Спасибо!
avatar
Алексей Манин, sleep 1 это одна миллисекунда. 1/1000 секунда.
При sleep(10) вы опрашиваете 100 в секунду.
При проблемах связи вы тупо забиваете запросами.
Нужно ли вам чаще чем 1 раз в минуту данные?
Так что ставите sleep не меньше 1000 — раз в секунду, а то и раз в минуту.
Либо оборачивайте в колбек обновления таблицы параметров.
avatar
Eldar Shaymardanov, а использовать OnParam не легче?
не спрашивать каждый момент, а реагировать на изменения
avatar
evg_gen, можно и его. Любой колбек.
Просто у разных брокеров с серверов приходят разные времена срабатывания колбека. И часто onParam по ходит пачкой.
Хотя данными замерами я занимался давно. Может что и поменялось
avatar
Eldar Shaymardanov, колбек — это который вызывается по какому-либо событию? onParam, насколько я понял, не совсем подходит из-за прихода пачки. Посоветуйте, по какому колбеку лучше.
avatar
Алексей Манин, я использую три колбека: OnAllTrade, OnParam, OnQuote.
вам точно подойдет onParam.
avatar
Eldar Shaymardanov, Спасибо!
avatar
Алексей Манин, по поводу пачки. пришел пакет от сервера в квик- вызвался колбек, но там сразу много колбеков придет и по очереди их обрабатываете.
OnParam (STRING class_code, STRING sec_code)

вашу логику вижу так:
1. при запуске скрипта, при подключении / переподключении — создаете таблицы, формируете список тикеров, добавляете константы (параметры тикеров, как  тикер базового актива, лот, данные экспирации и т.д.) и остальные, как доход, аски/биды и т.п.
2. при колбеке ОнПарам проверяете нужен ли вам колбек по пришедшему тикеру и обрабатываете свежие данные.
3. проверяйте есть ли связь с сервером, ведутся ли торги.

хотя может вам нужно смотреть стакан, то тогда через OnQuote, только незабудьте запросить стакан котировок getQuoteLevel2. но тут не совсем актуальная информация изза левых заявок роботов, которые то ставятся, то снимаются.
если нужны данные про прошедшей сделки, то через OnAllTrade. прошла сделка — обработали таблицу по новым данным.
avatar
Eldar Shaymardanov, Спасибо, за подробный ответ!
avatar
если не программист, зачем ломать голову над этим?
вывод в эксель намного быстрее настраивается и поддерживается

*себе сделал в эксель, ковырять lua нет настроения
**и еще разве скрипт работает когда QUIK не активное окно? (у меня в QUIK РСХБ если ушел смотреть youtube, то скрипт останавливается — не знаю почему)
avatar
evg_gen, скрипт всегда работает внк активности квика.
avatar
Eldar Shaymardanov, вот и я так думал. вообще quik от РСХБ какой-то уникальный… даже экспорт в эксель по DDE останавливается, если в экселе формулу (очень быстро по времени) поправить. при этом экспорт в эту же книгу и на эту же страницу из quik КИТов работает стабильно
в общем 2 quik пишут в один эксель у меня
avatar
evg_gen, конечная идея была создать робота. А через Excel сделать робота, думаю, что очень заморочно.
avatar
Алексей Манин, настройка экселя заняла у меня 10 минут и 10 минут создание формул

за 20 минут в lua можно только понять что это)
не настаиваю на экселе. если хочется робота на lua, то пусть
и у меня есть робот, но на экселе)
avatar
evg_gen, а обратно из экселя автоматом?
avatar
Eldar Shaymardanov, тут конечно не оптимальный вариант. через tri файл пишу заявку и квик её забирает
тут согласен, помучился, и то потому что не понятно какие коды инструмента надо было вписывать. а теперь все гуд
avatar
evg_gen, как у вас реализовано?
Quik->DDE->Excel->VBA->File->Quik
или
Quik->DDE->Excel->Python(pandas)->File->Quik
avatar
Quik->DDE->Excel->VBA->File->Quik
avatar
evg_gen, Спасибо!
Подскажите, а через Python, хуже будет работать? Типа, дольше?
Ведь в VBA можно прописать скрипт автосохранения файла обновляемого по DDE, а потом этот файл считать Пайтоном.
avatar
Алексей Манин, тут не подскажу
avatar
можно попробовать сборщик мусора прикрутить, collectgarbage()
или на другой версии qlua запустить
avatar
Konfuzzz, спасибо за инфу!
avatar

теги блога Алексей Манин

....все тэги



UPDONW
Новый дизайн