[BUG] getFuturesHolding: ошибка в работе

Страницы: 1
RSS
[BUG] getFuturesHolding: ошибка в работе
 
По мотивам этой темы.
Скрипт 1
Скрытый текст

Скрипт 2
Скрытый текст

Запускаем скрипт 1 и несколько скриптов 2 по разным бумагам. Любуемся результатом.

Возможно, другие функции getЧегоТоТам также работают нестабильно. Проверяйте сами.
Надо делать так, как надо. А как не надо - делать не надо.
 
getFuturesLimit при одновременном запросе из нескольких скриптов по разным счетам ничего не возвращает (буквально).
Надо делать так, как надо. А как не надо - делать не надо.
 
Возникает вопрос: а корректно ли работает поиск SearchItems, если так совпало, что он производится в двух или более скриптах одновременно?
Надо делать так, как надо. А как не надо - делать не надо.
 
*одновременно по одной таблице
Надо делать так, как надо. А как не надо - делать не надо.
 
Старатель, добрый день!

Озвученные проблемы изучаются, постараемся в ближайшее время дать ответ.
 
Старатель, добрый день!

Действительно, в ПО QLUA есть ошибка одновременной работы скриптов использующих лимиты. Мы исправим её в очередном обновлении ПО.
Приносим извинения за причинённые неудобства.
 
в очередном это в каком или когда !?
 
 Это ответ функции при добавлении нового тикера:
Цитата
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGU4; self.type = 0 number
Все параметры введены правильно, не должна выводить local holdings = nil? Выводит nil а правильно сказать ни чего не выводит по данному инструменту! Не понимает пока не обновил таблицу "состояние счета", то есть прогнал пустой ордер чтоб отобразился тикер. Ну почему, Все за что не возьмешься, через одно место? Программе столько лет, все уже должно идеально работать.
Вот сама функция, что не так?
Код
-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)
    if holdings then
        self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        --self.session_status = math.floor(holdings.session_status) or 0
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if getFuturesHolding ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
    else
        Log:info("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end
 
Мне тоже хотелось бы знать, безопасно ли использовать getFuturesHolding в скрипте из разных потоков (main и основной поток квика), т.к. у меня мистические краши квика происходят в скрипте, в котором есть такие вызовы.
 
Цитата
VPM написал:
Вот сама функция, что не так?
Цитата
if getFuturesHolding ~= 'основная сессия' then

Вы сравниваете функцию и строку на равенство.
 
funduk, Да заметил спасибо, но это дописано после, хотел уменьшить частоту вывода. Исправил
Код
if self.session_status ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
 
Мое мнение:
Чтобы найти ошибку надо видеть вызов функции и результат.
Вполне возможно, что ошибка происходи так как поток не успеет выбрать значение из архива до прихода новых данных.
Надо ставить ожидание события, чтобы не было мучительно больно.  
 
nikolz, Выше я показал функцию вызова и ответ на нее. Все прекрасно работало на старом тикере. Сбой происходит в момент ввода нового тикера. Ответ на вызов
local holdings = nil? при этом все входящие данные верны, более того изменился только код тикера.
Цитата
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGU4; self.type = 0 number
 Функция возвращает таблицу Lua, не может быть здесь отсутствие самой таблицы, могут отсутствовать поля этой таблицы, но не сама таблица?

Вот из справки
Цитата

Функция предназначена для получения информации по фьючерсным позициям.

Формат вызова:

TABLE getFuturesHolding(STRING firmid, STRING trdaccid, STRING sec_code, NUMBER type)

Функция возвращает таблицу Lua с параметрами Таблицы «Позиции по клиентским счетам».

В случае ошибки функция возвращает «nil».

Я и допустил что при обновлении тикера не проходит какая - то инициализация, так как таблица отражает владение, то и активировал просто ордер по этому тикеру, сразу функция заработала нормально. Об этом мое сообщение.
 
Цитата
VPM написал:
nikolz, Выше я показал функцию вызова и ответ на нее. Все прекрасно работало на старом тикере. Сбой происходит в момент ввода нового тикера. Ответ на вызов
local holdings = nil? при этом все входящие данные верны, более того изменился только код тикера.
Цитата
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGU4; self.type = 0 number
  Функция возвращает таблицу Lua, не может быть здесь отсутствие самой таблицы, могут отсутствовать поля этой таблицы, но не сама таблица?

Вот из справки
Цитата
Функция предназначена для получения информации по фьючерсным позициям.  Формат вызова:  TABLE getFuturesHolding(STRING firmid, STRING trdaccid, STRING sec_code, NUMBER type)  Функция возвращает таблицу Lua с параметрами Таблицы «Позиции по клиентским счетам».  В случае ошибки функция возвращает «nil».
Я и допустил что при обновлении тикера не проходит какая - то инициализация, так как таблица отражает владение, то и активировал просто ордер по этому тикеру, сразу функция заработала нормально. Об этом мое сообщение.
Так как повторить данную ситуацию не могу, то могу лишь предположить следующее.
Эта функция по указанным параметрам ищет информацию в архиве терминала.
Если это новый тикер и он поступил в колбеке, то его еще нет архиве и в таблицах, так как информация в колбек приходит до ее записи в таблицы.
--------------------  
Чтобы такой ситуации не происходило , или для того чтобы определить причину,
я бы поставил ожидание данных при возникновении ситуации и запись состояния при этом в лог файл.
По результатам  в лог файле можно было бы что-то решить.
 
nikolz, Функция вызова обрабатывается в потоке маин, работает правильно и со стороны пользователя защищена проверкой на nil,  
Цитата
В случае ошибки функция возвращает «nil».
На этот случай дополнительно выводится сообщение и проверяемся корректность ввода пользователем входных параметров. В случае описанном нет ошибки на стороне пользователя (все введено корректно изменился тикер)! Ошибка возникает на стороне функции (Разработчиков), так как возвращает nil то есть - ошибку (читаем документацию)! Вот я и пытаюсь получить комментарий Разработчиков, понять где не точность в функции или документации? Описание говорит что должна вернуться таблица.
 
Цитата
VPM написал:
nikolz, Функция вызова обрабатывается в потоке маин, работает правильно и со стороны пользователя защищена проверкой на nil,  
Цитата
В случае ошибки функция возвращает «nil».
На этот случай дополнительно выводится сообщение и проверяемся корректность ввода пользователем входных параметров. В случае описанном нет ошибки на стороне пользователя (все введено корректно изменился тикер)! Ошибка возникает на стороне функции (Разработчиков), так как возвращает nil то есть - ошибку (читаем документацию)! Вот я и пытаюсь получить комментарий Разработчиков, понять где не точность в функции или документации? Описание говорит что должна вернуться таблица.
просто хотел посмотреть на демо сервере и понять причину.
Возможно я не нашел примера, но этот код не содержит  вызова, результата  и рабочего скрипта, который можно запустить чтобы обнаружить проблему:
Код
-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)
    if holdings then
        self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        --self.session_status = math.floor(holdings.session_status) or 0
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if getFuturesHolding ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
    else
        Log:info("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end
 
nikolz,  Не понял что мешает организовать свой поток маин? Вот накидал на скорую руку, попробуйте так поставив свои данные.
Код
local MoneyManagement = {}
MoneyManagement.__index = MoneyManagement

function MoneyManagement:new()
    local self = setmetatable({}, WindowCoordinates)
    
-- поставить свои данные

    self.firmid = ''
    self.account = ''
    self.type = 0

    return self
end

-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)
    if holdings then
        self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        --self.session_status = math.floor(holdings.session_status) or 0
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if getFuturesHolding ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
    else
        Log:info("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end

    local working = nil
   
function OnStop(stop_flag)
  message(' OnStop: '..'stop_flag = '..tostring(stop_flag) )
  working = false
end

--[[ MAIN LOOP ]]--
function main()

    local symbol_names = {
                     'NGU4' 
                  , 'BRQ4' 
                        , 'GDU4'
                   ,
                        }
    working = true
   message("Robot started")
    local mm = MoneyManagement:new()
   
    while working do
   
       for _, symbol in ipairs(symbol_names) do
          mm:FuturesHolding(symbol)
      end
      
   end
end
 
Заметил не точность в строке, нужно исправить на                   local self = setmetatable({}, MoneyManagement)
 
Вот поправил рабочий вариант
Код
local MoneyManagement = {}
MoneyManagement.__index = MoneyManagement

function MoneyManagement:new(firmid, account )
    local self = setmetatable({}, MoneyManagement)
    
    self.firmid = firmid
    self.account = account
    self.type = 0
    self.holdings = {}

    return self
end

-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = nil --getFuturesHolding(self.firmid, self.account, symbol, self.type) 
    if holdings then
        
   self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if self.session_status ~= 'основная сессия' then
            message('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
      
    else
        message("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end

    local working = nil
   
function OnStop(stop_flag)
  message(' OnStop: '..'stop_flag = '..tostring(stop_flag) )
  working = false
end

--[[ MAIN LOOP ]]--
function main()
    
   --local type = 0
   local firmid = ''
    local account = ''
   
    local symbol_names = {'NGU4' , 'BRQ4' , 'GDU4', 'NGU4' , 'NGX4' ,}
    working = true
   message("Robot started")
   
    local mm = MoneyManagement:new( firmid, account )-- , type
   
    while working do
   
       for _, symbol in ipairs(symbol_names) do
          mm:FuturesHolding(symbol)
      end
      
   end
end
 
Для тех кто будет пробовать нужно добавит задержку в код, чтоб не подвешивать процессор. sleep(1000)
Код
function main()
    
   --local type = 0
   local firmid = 'SPBFUT'
    local account = 'SPBFUT00hkv'
   
    local symbol_names = {'NGU4' , 'BRQ4' , 'GDU4', 'NGU4' , 'NGX4' ,}
    working = true
   message("Robot started")
   
    local mm = MoneyManagement:new( firmid, account )-- , type
   
    while working do
   
       for _, symbol in ipairs(symbol_names) do
          mm:FuturesHolding(symbol)
      end
      sleep(1000)
   end
end
В моем случае ошибка - nil получена по 3 тикерам.

Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = BRQ4; self.type = 0 number
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = GDU4; self.type = 0 number
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGX4; self.type = 0 number

Вот и возникает вопрос а что делаю не так как описано в инструкции?
 
Цитата
VPM написал:
local holdings = nil --getFuturesHolding(self.firmid, self.account, symbol, self.type)
Хоть к теме и не относится, но что-то часто такие ошибки у Вас в коде...

А так -- ну да, getFuturesHolding даёт nil, если не было ордеров по тикеру с прошлого клиринга и одновременно если нет позиции. Наверняка это деталь реализации для какого-нибудь ускорения...
 
Цитата
VPM написал:
nikolz,  Не понял что мешает организовать свой поток маин? Вот накидал на скорую руку, попробуйте так поставив свои данные.
[CODE][/CODE]
Да ничего не мешает.   Функцию я эту использую.  Но у меня все иначе написано и проблем с этой функцией не было.
-----------------------
Поэтому и хотел посмотреть именно ваше решение, в котором есть проблемы.
------------------------
Относительно задержки процессора.
Я использую Event, об этом писал и вы знаете.
В результате реакция на колбек запаздывает не более, чем на 0.00001 сек, а загрузка процессора 3-7%.  
 
Цитата
funduk написал:
Цитата
VPM написал:
local holdings = nil --getFuturesHolding(self.firmid, self.account, symbol, self.type)
Хоть к теме и не относится, но что-то часто такие ошибки у Вас в коде...

А так -- ну да, getFuturesHolding даёт nil, если не было ордеров по тикеру с прошлого клиринга и одновременно если нет позиции. Наверняка это деталь реализации для какого-нибудь ускорения...
Это заглушка для проверки кода в среде луа (без квик), в квик просто нужно раскомментировать строку.

Так и я про это, как без этих выкрутасов можно понять как работает getFuturesHolding? И где здесь вообще логика? Сделал запрос вернулась таблица, нет запросов зачистили память.
Обломали полумесячный тест.

nikolz, Трудно представить что тут можно по другому local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)  
 
Цитата
nikolz написал:
Относительно задержки процессора. Я использую Event, об этом писал и вы знаете. В результате реакция на колбек запаздывает не более, чем на 0.00001 сек, а загрузка процессора 3-7%.  
Дело тут не в задержке а в инициализации. Я использую задержки но в данном случае зачем? Сколько не задерживай получишь нил, пока не инициализируешь. И запроса здесь одного мало. И хотелось бы что то услышать от разработчиков это задумка такая или оплошность. И как поступать в алгоритме при смене тикера?
 
Мало словить проблему, нужно найти ее решение. Решение оказалось на столько элегантным настолько и простым. Асинхронный подход - вызов функций qlua в сопрограммах, элегантно решет данную проблему. В чем суть, вот из "букваря". "В асинхронных программах ключевой элемент — event loop. Ивент луп — это цикл в программе, который ждёт событий и вызывает обработчиков." "Плюс корутины в том, что она умеет останавливаться несколько раз. С корутинами, Ивент луп получил событие A и вызвал корутину - обработчик. Корутина же отправила HTTP-запрос и уснула. Теперь ивент луп её разбудит, когда получит событие B, что соединение установлено. И корутина продолжит работу с того момента в коде, как уснула, что очень удобно. А пока она спит, могут работать другие корутины."
Кому стало интересно, лучше почитать здесь, все просто "разжевано", нужно только "скушать". https://fingercomp.gitlab.io/lua-coroutines/#code-1.3
Всем, хорошего кода!
 
Чуть поясню о чем здесь.
В QUIK есть два подхода обработки фьючерсных позиций: 1. OnFuturesClientHolding` через обратный вызов и 2. getFuturesHolding. На первый взгляд очень соблазнительно выглядит 1 вариант, получил автоматически и забыл, про производительность можно и вообще не вспоминать. Но есть одно НО, к существенному недостатку, приводит обработка данных в неожиданный момент, что усложняет синхронизацию с другими процессами. У себя в программах контролирую момент прихода, по времени, это важно так как всегда есть две координаты {time,price}, поэтому предпочитаю пользоваться 2 вариантом. Ситуация которая заставила задуматься описана выше, чтоб избегать ее применил корутину. Корутинный подход снижает нагрузку и предоставляет больше контроля над частотой обновлений, требуется явный вызов функции. Получаем гибкость в управлении запросами и возможностью контролировать нагрузку на систему, запрашиваем там где требуется и когда требуется. Задача - данные по запросу, например, при анализе состояния позиций в определенные моменты. Корутинный подход позволяет не обращать внимания на nil, не блокировать основной поток, программа продолжает выполнение, а данные обновим при следующим запросе. Чем и как пользоваться каждый решает для себя сам, я лишь озвучил подход.
Страницы: 1
Читают тему
Наверх