Алексей Манин
Алексей Манин личный блог
20 октября 2022, 16:53

Синтетическая облигация. Помогите с 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>
23 Комментария
  • nicknh
    20 октября 2022, 17:02
    Помимо того что всегда выводятся данные, которые можно вывести один раз (размер лота, экспирация), стоит увеличить sleep до 50. При работе с таблицами это уже важно.
      • Eldar Shaymardanov
        20 октября 2022, 19:39
        Алексей Манин, sleep 1 это одна миллисекунда. 1/1000 секунда.
        При sleep(10) вы опрашиваете 100 в секунду.
        При проблемах связи вы тупо забиваете запросами.
        Нужно ли вам чаще чем 1 раз в минуту данные?
        Так что ставите sleep не меньше 1000 — раз в секунду, а то и раз в минуту.
        Либо оборачивайте в колбек обновления таблицы параметров.
        • evg_gen
          20 октября 2022, 19:56
          Eldar Shaymardanov, а использовать OnParam не легче?
          не спрашивать каждый момент, а реагировать на изменения
          • Eldar Shaymardanov
            20 октября 2022, 21:37
            evg_gen, можно и его. Любой колбек.
            Просто у разных брокеров с серверов приходят разные времена срабатывания колбека. И часто onParam по ходит пачкой.
            Хотя данными замерами я занимался давно. Может что и поменялось
          • Eldar Shaymardanov
            21 октября 2022, 09:29
            Алексей Манин, я использую три колбека: OnAllTrade, OnParam, OnQuote.
            вам точно подойдет onParam.
          • Eldar Shaymardanov
            21 октября 2022, 09:42
            Алексей Манин, по поводу пачки. пришел пакет от сервера в квик- вызвался колбек, но там сразу много колбеков придет и по очереди их обрабатываете.
            OnParam (STRING class_code, STRING sec_code)

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

            хотя может вам нужно смотреть стакан, то тогда через OnQuote, только незабудьте запросить стакан котировок getQuoteLevel2. но тут не совсем актуальная информация изза левых заявок роботов, которые то ставятся, то снимаются.
            если нужны данные про прошедшей сделки, то через OnAllTrade. прошла сделка — обработали таблицу по новым данным.
  • evg_gen
    20 октября 2022, 19:55
    если не программист, зачем ломать голову над этим?
    вывод в эксель намного быстрее настраивается и поддерживается

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

        за 20 минут в lua можно только понять что это)
        не настаиваю на экселе. если хочется робота на lua, то пусть
        и у меня есть робот, но на экселе)
        • Eldar Shaymardanov
          21 октября 2022, 09:29
          evg_gen, а обратно из экселя автоматом?
          • evg_gen
            21 октября 2022, 09:32
            Eldar Shaymardanov, тут конечно не оптимальный вариант. через tri файл пишу заявку и квик её забирает
            тут согласен, помучился, и то потому что не понятно какие коды инструмента надо было вписывать. а теперь все гуд
  • evg_gen
    21 октября 2022, 09:42
    Quik->DDE->Excel->VBA->File->Quik
      • evg_gen
        21 октября 2022, 10:10
        Алексей Манин, тут не подскажу
  • Konfuzzz
    22 октября 2022, 16:45
    можно попробовать сборщик мусора прикрутить, collectgarbage()
    или на другой версии qlua запустить

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн