local run = true
function OnStop()
run = nil
end
function main()
local pos
while run do
local fut_pos = getFuturesHolding(FIRMID, ACCOUNT, SEC_CODE, TYPE)
if type(fut_pos) == "table" then
local totalnet = fut_pos.totalnet
if pos ~= totalnet then
message(SEC_CODE .. ": pos = " .. tostring(pos) .. "\n" .. fut_pos.sec_code .. ": totalnet = " .. tostring(totalnet), 3)
pos = totalnet
end
else
message("getFuturesHolding error", 3)
end
sleep(1)
end
end
Скрипт 2
Скрытый текст
Код
local run = true
function OnStop()
run = nil
end
function main()
while run do
getFuturesHolding(FIRMID, ACCOUNT, SEC_CODE, TYPE)
sleep(1)
end
end
Запускаем скрипт 1 и несколько скриптов 2 по разным бумагам. Любуемся результатом.
Возможно, другие функции getЧегоТоТам также работают нестабильно. Проверяйте сами.
Надо делать так, как надо. А как не надо - делать не надо.
Действительно, в ПО 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 и основной поток квика), т.к. у меня мистические краши квика происходят в скрипте, в котором есть такие вызовы.
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 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%.
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, не блокировать основной поток, программа продолжает выполнение, а данные обновим при следующим запросе. Чем и как пользоваться каждый решает для себя сам, я лишь озвучил подход.