zv78 написал: Как запустить что либо в квике я не знаю. Про это где написано?
Добрый день. В справке по плагину QLUA описаны только функции, сами же основы работы со скриптами Lua в терминале Quik мы постарались подробно описать в документе 'Использование Lua в Рабочем месте Quik.pdf'. Для начала изучения работы со скриптами Lua в терминале Quik информации из данного документа должно быть достаточно. Архив с документацией и примерами скриптов можно скачать здесь: https://arqatech.com/upload/Public/quik_lua.zip
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Андрей написал: И еще вопрос где то видел, что таблицы можно перенести из одной вкладки в другую, но не могу найти как это сделать?
Добрый день, еще есть возможность быстрого переноса таблиц между вкладками, нажимаете клавишу Ctrl, не отпуская клавишу, берете указателем мыши необходимую Вам таблицу за заголовок и перетаскиваете на нужную вкладку.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Анатолий написал: "%%%02X" - что тут означают аж три знака % ?, первый надо понимать экранирующий, но зачем после него еще два знака % а не один? Т.к. сказано что опцией является %02X а не %%02X
Добрый день. Выше на странице, на которую Вы ссылаетесь, описана для чего используется '%%'.
Цитата
By the way, because of those changes, a `%´ in the replacement string must be escaped as "%%".
Т.е. насколько я понял автора, в строке return string.format ("%%%02X", string.byte(с)) он ищет подстроки вида '%00[HEX]' и меняет их на значение передаваемое в параметре c. Т.о. первые '%%' отвечают за символ %, а '%02X' уже за HEX с двумя нулями впереди.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Анатолий написал: Что значат эти два прямых слэша в s = string.gsub(s, "\\(%a+){(.-)}", " %2 ") - "\\(%a+){(.-)}"?
Добрый день. При работе с регулярными выражениями, если нужно использовать какой-либо зарезервированный символы как обычные, то их нужно экранировать, прямой слэш является символом экранирования. Погуглите на тему "экранирование спецсимволов в lua".
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Анатолий написал: растолкуйте мне пожалуйста что они значат и что дает добавление знака плюс
Добрый день. Поищите в интернете статьи об использовании паттернов или регулярных выражений в Lua, это достаточно мощный и интересный функционал, вот для примера официальное описание для Lua https://www.lua.org/pil/20.2.html, на русском так же статей много.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Да, Вы совершенно верно предположили необходимость использования дополнительного флага (в Вашем случе traling). Только нужно переменную traling заранее определить как false. Вот небольшой шаблон
Код
traling = false
function main()
if traling == false then
--что-то делаем, что нужно сделать первоочередно
traling = true
end
if traling == truet then
--что-то делаем, только если выполнен первоочередный шаг
end
end
можно еще использовать вот такую конструкцию:
Код
traling = false
function main()
if traling == false then
--что-то делаем, что нужно сделать первоочередно
traling = true
elseif traling == truet then
--в эту ветку уже не зайдем если зашли в ветку traling == false
end
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Поле flags структуры all_trades нужно интерпретировать как битовую маску (т.е. рассматривать не как число в десятичной системе счисления, а как число в двоичной системе счисления). В вашем случае: 1025 = 0100 0000 0001 (бит 0 (0x1) Сделка на продажу) 1026 = 0100 0000 0010 (бит 1 (0x2) Сделка на покупку)
Для работы с битовыми масками есть специальные функции (см. справку QLua, раздел "Функции для работы с битовыми масками в структурах данных")
Легче всего использовать функцию bit.test, вот примет:
Код
if bit.test(alltrade.flags, 0) then
message("Обезличенная следка на продажу")
elseif bit.test(alltrade.flags, 1) then
message("Обезличенная следка на покупку")
else
message("Направление обезличенной сделки не определено")
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Обработал Ваш код, иначе читать такой объем в таком виде невозможно. Укажите, пожалуйста, в каком именно месте/функции Вам нужно разделить условия, описанные выше
Скрытый текст
Код
p_classcode="SPBFUT" --Код класса
p_seccode="SBRF" --Код инструмента
p_account="" --Код счета
p_clientcode="" --Клиенткий код
p_count=2 --Размер позиции
p_spread=0.7 --Проскальзывание
p_sell_level_RSI=60 --уровень RSI, при котором продаем
p_buy_level_RSI=40 --уровень RSI, при котором покупаем
p_TRANS_ID="2" --идентифкатор транзакций робота, нужен для того, что бы робот отличал свои транзакции от транзакций других роботов и ручных транзакций
p_TRANS_ID_STOP="3" --по работе со стоп ордерами
p_stop_loss_level=3 --Уровень стоп лосса
p_traling_stop_level=3.1 --Уровень стоп лосса, при котором мы "подтягиваем" стоп лосс
p_file = io.open("D:\\userlog.txt", "w") -- тут надо указать путь к файлу лога
--Служебные переменные тут мы запоминаем
is_run = true
count = 0
in_trade = false --признак того, что мы в позиции
order_num = "" --номер заявки по открытой сделке
stop_loss_num = "" --номер стоп заявик по открытой сделке
direction="" --последний тип операции
last_price=0 --цена последней сделки по стратегии
in_set_stop_loss = false --признак, что мы в данный момнет ожидаем результата выставления стоп лосса
function main()
while is_run do
sleep(2000)
robot()
end
end
function to_log(a_msg)
p_file:write(os.date().." "..a_msg.."\n")
end
function robot()
local RSI=getNumCandles("RSI")
local N=getNumCandles("Price")
t,n,i=getCandlesByIndex("Price", 0, N-1, 1)
RSI_t,RSI_n,RSI_i=getCandlesByIndex("RSI", 0, RSI-3, 2)
--сигнла обрабатываем только если мы не в позиции
if not(in_trade) then
--сигнал на продажу (RSI пересекает уровень продажи сверху вниз)
if RSI_t[0].close>p_sell_level_RSI and RSI_t[1].close<p_sell_level_RSI then
Trade("S",count+p_count,t[0].close-p_spread)
end
--сигнал на покупку (RSI пересекает уровень покупки снизу вверх)
if RSI_t[0].close<p_buy_level_RSI and RSI_t[1].close>p_buy_level_RSI then
Trade("B",p_count-count,t[0].close+p_spread)
end
else
--проверить состояние стопа, не надо ли его сдвигать или изменить количество
stop_loss_control()
end
end
--Сначала мы ищем нашу стоп заявку:для поиска используем функцию SearchItems, она у нас вызывает CALLBACK-функцию fn:
function fn(par1)
if stop_loss_num=="" then ----номер стоп заявик по открытой сделке
return false
end
if tonumber(par1) - tonumber(stop_loss_num)==0 then
return true
else
return false
end
end
function stop_loss_control()
local N=getNumCandles("Price") -- индефикатор цены на графике N
if N==nil or N==0 then return end
p_t,p_n,p_i=getCandlesByIndex("Price", 0, N-1, 1)
local NO=getNumberOf("stop_orders") -- Получение данных из таблицы Стоп-заявки:
local is_stop_order=true
if NO==nil or NO==0 then
is_stop_order=false
else
t_so = SearchItems("stop_orders", 0, NO-1, fn, "order_num") --order_num = "" --номер заявки по открытой сделке
end
--если стоп лосса нет, то возможно, его надо выставить
if t_so==nil and is_stop_order then
is_stop_order = false
end
if is_stop_order then
if t_so[1]==nil then
is_stop_order = false
end
end
if not(is_stop_order) then
if in_trade and count~=0 then --in_trade признак того, что мы в позиции
if count>0 then
send_stop_loss("B",count,last_price)--формируем стоп-лосс и выставляем его, вызвав функцию send_stop_loss, last_price --цена последней сделки по стратегии
else
send_stop_loss("S",count,last_price)
end
end
return
end
--А дальше мы вычисляем разницу в ценах, проверяем условие стоп-лосса и, при необходимости перевыставляем его. До этого кода дойдет только в том случае, если у нас уже есть выставленный стоп-лосс:
to_log("stop_loss_control найден стоп ордер count="..count)
t_so_item=getItem("stop_orders", t_so[1])
delta_price=0;
if count>0 then
to_log("count>0")
delta_price=p_t[0].close-t_so_item.condition_price; --condition это состояние, p_t строка 79
l_direction="B"
else
to_log("count<=0")
delta_price=t_so_item.condition_price-p_t[0].close
l_direction="S"
end
to_log("delta_price="..delta_price.." t_so[0].qty="..t_so_item.qty.." p_t[0].close="..p_t[0].close)
if delta_price>=p_traling_stop_level or count~=t_so_item.qty then
to_log("Послылаем новую стоп заявку price="..p_t[0].close.." количество "..count)
send_stop_loss(l_direction,count,p_t[0].close)
end
end
function Trade(a_oper,a_count,a_price)
if a_count>0 then --Количество сделки
--Сначала пошлем обычную заявку
t = {
["CLASSCODE"]=p_classcode,
["SECCODE"]=p_seccode,
["ACTION"]="NEW_ORDER",
["ACCOUNT"]=p_account,
["CLIENT_CODE"]=p_clientcode,
["TYPE"]="L",
["OPERATION"]=a_oper,
["QUANTITY"]=tostring(a_count),
["PRICE"]=tostring(a_price),
["EXPIRY_DATE"]="GTC",
["TRANS_ID"]=p_TRANS_ID
}
res=sendTransaction(t)
--заявку послали и сразу же мы оказались в позиции и будем в ней до тех пор, пока не закроется сделка
--или пока не будет доказано обратное (мы узнаем, что сделка не прошла)
in_trade=true
direction=a_oper--последний тип операции
message("Количество сделки "..tostring(a_count).." тип операции "..a_oper.." Цена "..a_price,1)
end
end
--Обработчик события сделки.
function OnTrade(trade)
nord=trade["order_num"]
price=trade["price"]
to_log("Совершена сделка: номер заявки "..tostring(nord).."; цена "..tostring(price)..": количество "..tostring(trade["qty"]))
if nord==order_num then
qty=trade["qty"]
if direction=="B" then
count=count+qty
else
count=count-qty
end
send_stop_loss(direction,count,price)
last_price=price
end
end
--Обработчик события создания стоп заявки
function OnStopOrder(stop_order)
--бит 0 (0x1) Заявка активна, иначе не активна
if stop_order["order_num"]==stop_loss_num and bit.band(stop_order["flags"],0x1)==0x1 then
to_log("сняли признак что мы в процессе выставления стоп оредра")
in_set_stop_loss=false
end
--бит 0 (0x1) Заявка активна, иначе не активна,
--бит 1 (0x2) Заявка снята. Если не установлен и значение бита 0 равно 0, то заявка исполнена
--в этом случае мы считаем, что позция закрыта по стоп лоссу
if stop_order["order_num"]==stop_loss_num and bit.band(stop_order["flags"],0x1)==0x0 and bit.band(stop_order["flags"],0x2)==0x0 then --stop_loss_num = "" --номер стоп заявик по открытой сделке
in_set_stop_loss=false
count=0
end
end
--Удалить стоп лосс
function delete_stop_loss(a_num)
t = {
["CLASSCODE"]=p_classcode,
["SECCODE"]=p_seccode,
["ACTION"]="KILL_STOP_ORDER",
["ACCOUNT"]=p_account,
["CLIENT_CODE"]=p_clientcode,
["TYPE"]="L",
["OPERATION"]=l_oper,
["STOP_ORDER_KIND"]="SIMPLE_STOP_ORDER",
["TRANS_ID"]=p_TRANS_ID_STOP,
["STOP_ORDER_KEY"]=tostring(a_num)
}
res=sendTransaction(t)
message("Удаляем стоп лосс: сообщение "..res.."; номер "..a_num,1)
end
--Послать стоп заявку
function send_stop_loss(a_direction,a_count,a_price)
to_log("send_stop_loss in_set_stop_loss="..tostring(in_set_stop_loss))
if not(in_set_stop_loss) then
if stop_loss_num~="" then
delete_stop_loss(stop_loss_num)
end
if a_direction=="B" then
l_oper="S"
l_count=a_count
dir=-1
else
l_oper="B"
l_count=-a_count
dir=1
end
l_price=a_price+p_stop_loss_level*dir
if l_count>0 then
to_log("send_stop_loss Зашли сюда",1)
in_set_stop_loss=true
--Пошлем стоп заявку
t = {
["CLASSCODE"]=p_classcode,
["SECCODE"]=p_seccode,
["ACTION"]="NEW_STOP_ORDER",
["ACCOUNT"]=p_account,
["CLIENT_CODE"]=p_clientcode,
["TYPE"]="L",
["OPERATION"]=l_oper,
["QUANTITY"]=tostring(l_count),
["PRICE"]=tostring(l_price+p_spread*dir),
["EXPIRY_DATE"]="GTC",
["STOPPRICE"]=tostring(l_price),
["STOP_ORDER_KIND"]="SIMPLE_STOP_ORDER",
["TRANS_ID"]=p_TRANS_ID_STOP
}
res=sendTransaction(t)
message(res,1)
to_log("Выставли стоп заявку "..l_oper)
end
end
end
--обработка события транзакции
function OnTransReply(trans_reply)
id=tostring(trans_reply["trans_id"])
to_log("Обработка транзакции "..id)
--если это наша транзакция, обработаем ее
if id==p_TRANS_ID then
nord=trans_reply["order_num"]
to_log("Обработка транзакции номер заявки "..nord)
--если заявка выставилась - запоминаем ее номер, иначе считаем, что мы не в сделке
if nord==nil or nord==0 or nord=="0" then
message("Заявка не выставилась ",1)
in_trade=false
else
order_num=nord
end
end
if id==p_TRANS_ID_STOP then
message("Сообщение транзакции стоп ордера "..trans_reply["result_msg"],1)
nord=trans_reply["order_num"] --Номер заявки
--если заявка выставилась - запоминаем ее номер, иначе считаем, что мы закончили выставлять стоп заявку
if nord==nil then
message("Стоп заявка не выставилась ",1)
in_set_stop_loss=false
stop_loss_num=""
else
stop_loss_num=nord
end
end
end
function OnStop(stop_flag)
is_run=false
stop_flag=1
p_file:close();
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: Все мои арифметические операции с секундами. Это главная потребность. Минуты и часы не нужны
Добрый день. Если все операции с секундами, то, действительно, как уже сказал выше s_mike, все вычисления можно делать стандартными функциями. Вот небольшой пример:
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Когда-то для своих нужд писал функцию прибавления минут (не помню почему, но нужно было прибавлять именно только минуты), можно переработать и сделать универсальной для сложения/вычитания двух временнЫх значений:
Код
--функция прибaвляет минуты к времени time.
--time передается в формате {hour, min, sec}
function addTime(time, min)
local _time = copy(time)
if min >= 60 then
local hour = math.floor(min/60)
_time.hour = _time.hour + hour
min = min - hour*60
end
_time.min = _time.min + min
if _time.min >= 60 then
_time.hour = _time.hour + 1
_time.min = _time.min - 60
end
if _time.hour >= 24 then
_time.hour = _time.hour - 24
end
return _time
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Уточните, Вы всегда хотите прибавлять/отнимать секунды?
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: неудобен тем что надо отрывать-закрывать, а для отслеживания новых данных обновлять
Добрый день. "Открывать-закрывать" Вы имеете ввиду, чтобы данные обновились? Попробуйте лог-файл открыть через FAR Manager (кнопкой F3, на чтение), данные будут обновляться в нем сами. Цвет фона настраивается (стандартный синий), плюс лога в том, что сохраняется вся история сообщений, а вот в консоли буфер ограничен и при закрытии консоли все теряется.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: приходится выводить информацию в файл, а это неудобно
А чем вывод в файл не удобен?
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: Я про клуа внутри квика имею в виду. Скрипт робота чтобы логировал в черное окошко
Добрый день. Встроенный в терминал Quik интерпретатор Lua не имеет консоли, т.е. выводить некуда, поэтому обычная функция print() в нем не работает. Уточните, какая цель в отладочных сообщениях именно в консоли? Возможно достаточно будет обычного вывода сообщения через функцию message() или писать сообщения в лог-файл?
Если все же необходимо именно выводить в консоль, попробуйте использовать функцию QLua PrintDbgStr(), подробнее о ее использовании можно почитать в мануале (см. ссылку в моей подписи, раздел 5).
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: стал отфутболивать слепки стакана, если изменения произошли в дальних котировках.
Добрый день. Если Вам не нужна информация по всему стакану, а интересуют только "ближние котировки", в терминале Quik есть функционал ограничения стакана (см. Система -> Настройки -> Параметры инструментов, параметр Глубина стакана), в этом случае с сервера не будут транслироваться изменения по "дальним котировкам". Возможно это поможет Вам снизить поток информации и разгрузить терминал и работу скрипта.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
--разделяет строку на подстроки, используя текстовый разделитель. Возвращает таблицу подстрок
function split(str,sep)
local fields = {}
str:gsub(string.format("([^%s]+)", sep or "%s"), function(c) fields[#fields+1] = c end)
return fields
end
ticker_list="SBER,GAZP"
for _, v in ipairs(split(ticker_list,',')) do
print(v)
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. По мне так проще написать отдельную функцию сплиттер и использовать ее, например, вот один из вариантов
Код
--разделяет строку на подстроки, используя текстовый разделитель. Возвращает таблицу подстрок
function split(str,sep)
local fields = {}
str:gsub(string.format("([^%s]+)", sep or "%s"), function(c) fields[#fields+1] = c end)
return fields
end
ticker_list="SBER,GAZP"
for _, v in ipairs(split(ticker_list)) do
print(v)
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Suntor написал: Но по другим вопрос остаётся. Имена с подчёркиваниями считаются новыми, а без — устаревшими?
Добрый день. Имена параметров с символом подчеркивания являются правильными. Если Вы посмотрите справку по QLua (на данный момент последняя версия терминала 7.16), то увидите, что старые параметры ordernum и tradenum там больше не описаны, но эти параметры оставлены для обратной совместимости, чтобы старые пользовательские скрипты не начали выдавать ошибки. Старые названия параметров в будущем будут удаляться, поэтому их использование при написании новых скриптов не рекомендуется.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Андрей, добрый день. В архиве есть официальный мануал 'Использование Lua в Рабочем месте QUIK.pdf', посмотрите его, может быть с ним Вам будет проще разобраться в структуре QLua скриптов.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Насколько мне известно, отдельной транзакции по закрытию позиции срочный рынок FORTS не предоставляет (если конечно имеется ввиду рынок FORTS). Но зная свою длинную/короткую позицию легко сформировать транзакцию на продажу/покупку по рыночной цене, что приведет к закрытию позиции.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Алексей написал: Нашел ошибку, исправил, спасибо за помощь, есть еще вопрос каким параметром можно получить "текущая чистая позиция" и вариационная маржа, и есть ли команда для закрытия всех сделок?
Для получения Текущей чистой позиции и Вариационной маржи на срочном рынке используйте функцию getFuturesHolding() (формат использования смотрите в официальной справке). Что имеется ввиду под закрытием всех сделок, закрытие позиции?
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Выведите перед проблемным местом значения tonumber(tekPrice) и tonumber(priceMin), диагностика явно говорит, что одно из значений равно nil, т.е. Вы пытаетесь сравнить nil с числом и получаете ошибку. Напишите например так, чтобы точно определить с какими значениями работает оператор if:
Код
message(tostring(tonumber(tekPrice)))
message(tostring(tonumber(priceMin)))
if (tonumber(tekPrice) < tonumber(priceMin) ) then -- 25 строка
....
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
возможно функция не возвращает значения, т.к. были указаны некорректный код класса или инструмента, также можно смотреть на поле getParamEx(...).result
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Функция getParamEx() возвращает таблицу Lua. В диагностике об ошибке явно сказано, 'попробуйте сравнить два значения таблицы'. Т.е. Вам нужно сделать, например, так:
Код
priceMax = getParamEx(KodClass,InstrumentKod,"PRICEMAX").param_value
priceMin= getParamEx(KodClass,InstrumentKod,"PRICEMIN").param_value
function trade()
if(tekPrice <= priceMin) then --20 строка error
...
Почитайте внимательно описание используемых Вами функций QLua в справке.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Почитайте официальный мануал, ссылку смотрите в подписи.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
if bit.test(order.flags,0) == true AND order.balance ~= 0 AND order.balance < order.qty then message('Заявка активна и частично исполнена') end
if bit.test(order.flags,1) == true AND order.balance ~= 0 AND order.balance < order.qty then message('Заявка снята и частично исполнена') end
if bit.test(order.flags,0) == false AND bit.test(order.flags,1) == false then message('Заявка полностью исполнена') end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. При работе с частично исполненной заявкой помимо флагов нужно еще учитывать поле balance на заявке, сравнивая с полем qty на заявке, если order.balance < order.qty, значит заявка частично исполнена, но частично исполненная заявка может быть как активной (т.е. нулевой бит флага = 1), так и снятой (т.е. первый бит флага = 1). При полностью исполненной заявке нулевой бит флага = 0, первый бит флага = 0. Подведем итог:
Код
if bit.test(order.flags,0) == true AND order.balance ~= 0 AND order.balance < order.qty then message('Заявка активна и частично исполнена') end
if bit.test(order.flags,1) == true AND order.balance ~= 0 AND order.balance < order.qty then message('Заявка снята и частично исполнена') end
if bit.test(order.flags,0) == true and bit.test(order.flags,1) == true then message('Заявка полностью исполнена') end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
30 это значение поля flags на заявке. Так будет понятней?
Код
order = getItem('orders', 1)
flags_as_table = Flags2Table(order.flags, 'orders')
if flags_as_table.sate == "Снята" then
message("Заявка " .. tostring(order.order_num) .. " снята")
elseif lags_as_table.sate == "Активна" then
message("Заявка " .. tostring(order.order_num) .. " активна")
else
message("Заявка " .. tostring(order.order_num) .. " исполнена")
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: Есть заявка с номером 28342011321 Как мне узнать, она активная, снятая или исполненная?
В какой момент Вы хотите проверять состояние заявки? В момент ее получения (т.е. при вызове onOrder()) или просто когда Вы ее достаете из хранилища функцией getItem()?
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: Николай, расскажите о вашей функции подробнее. Как ею пользоваться.
Код
table_flags = Flags2Table(30, 'orders')
в переменную table_flags запишется Lua таблица {typeLM<L> type<Лимитированная> KILL_BALANCE<0> FILL_OR_KILL<0> operation<Продажа> operationBS<S> iceberg<0> sate<Снята>}, как работать с таблицей Lua думая знаете...
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Sergey Gorokhov написал: некорректно проверять флаги в десятичном виде, проверять следует в шестнадцатеричном.
Немного поправлю, чтобы человек окончательно не запутался. flags=30 это значение в десятичной системе счисления, а флаги это значение бита в определенной позиции числа в двоичной системе счисления, так, например, если число 30 в двоичной системе счисления будет иметь вид 00011110, значения чисел в соответствующей позиции и смотрим (справа на лева, нумерация с 0). Собственно функция bit.test и дает возможность легко проверить значение бита в позиции: bit.test(30, 0)=False bit.test(30, 1)=True bit.test(30, 2)=True bit.test(30, 3)=True bit.test(30, 4)=True bit.test(30, 5)=False bit.test(30, 6)=False bit.test(30, 7)=False
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Когда-то для себя писал вот такую функцию, думаю этот пример поможет Вам разобраться как работать с битами (описание функции bit.test смотрите в документации, раздел 'Функции для работы с битовыми масками в структурах данных'):
Код
function Flags2Table(flags, qtableName)
local t={}
if qtableName == "orders" or qtableName == "trades" or qtableName == "neg_deals" or qtableName == "neg_trades" or qtableName == "neg_deal_reports" then
if bit.test(flags, 0) then
t["sate"] = "Активна"
elseif bit.test(flags, 1) then
t["sate"] = "Снята"
else
t["sate"] = "Исполнена"
end
if bit.test(flags, 2) then
t["operation"] = "Продажа"
t["operationBS"] = "S"
else
t["operation"] = "Купля"
t["operationBS"] = "B"
end
if bit.test(flags, 3) then
t["type"] = "Лимитированная"
t["typeLM"] = "L"
else
t["type"] = "Рыночная"
t["typeLM"] = "M"
end
if bit.test(flags, 5) then
t["FILL_OR_KILL"] = 1
else
t["FILL_OR_KILL"] = 0
end
if bit.test(flags, 8) then
t["KILL_BALANCE"] = 1
else
t["KILL_BALANCE"] = 0
end
if bit.test(flags, 9) then
t["iceberg"] = 1
else
t["iceberg"] = 0
end
elseif qtableName == "all_trades" then
if bit.test(flags, 0) then
t["operation"] = "Продажа"
elseif bit.test(flags, 1) then
t["operation"] = "Купля"
else
t["operation"] = ""
end
elseif qtableName == "stop_orders" then
if bit.test(flags, 0) then
t["sate"] = "Активна"
elseif bit.test(flags, 1) then
t["sate"] = "Снята"
else
t["sate"] = "Исполнена"
end
if bit.test(flags, 2) then
t["operation"] = "Продажа"
t["operationBS"] = "S"
else
t["operation"] = "Купля"
t["operationBS"] = "B"
end
if bit.test(flags, 3) then
t["type"] = "Лимитированная"
t["typeLM"] = "L"
else
t["type"] = "Рыночная"
t["typeLM"] = "M"
end
else
return nil
end
return t
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Возможно проверку существования self.data[row][col_ind] делать и не надо, поэкспирементируйте, думаю достаточно и так:
Код
if self.data and self.data[row] and self.data[row][col_ind]==data then return true end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Let_it_go написал: Вы можете видеть, что я пытаюсь отловить эту ошибку через message, но он спокойно проходит эту проверку. Подскажите где искать иэтот "нил"
Добрый день. Предположу, что дело не в переменных
Код
row, col_name, data, col_ind
раз скрипт не заходит внутрь
Код
if row==nil or col_name==nil or data==nil or col_ind==nil then
message ((row or "nil").." | "..(col_name or "nil").." | "..(data or "nil").." | "..(col_ind or "nil")),1)
end
значит они имеют какое-то значение отличное от nil. Перепишите проблемную строчку вот так:
Код
if self.data and self.data[row] and self.data[row][col_ind] and self.data[row][col_ind]==data then return true end
Дословно - если self.data не nil И таблица self.data имеет запись с ключом row И таблица self.data[row] имеет запись col_ind тогда выполняем проверку значений этой многоуровневой таблицы.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. В приведенном примере создания таблицы нет кода добавления значений в ячейки (функция SetCell). Вот выдержка из справки: ------------------------------------------------------------------------------------------------------------------------------------------------------------ BOOLEAN SetCell(NUMBER t_id, NUMBER key, NUMBER code, STRING text, NUMBER value) Параметр «text» задает строковое представление значение параметра «value». Параметр «value» необязательный и по умолчанию равен «0». Для столбцов со строковыми типами данных параметр «value» не задается. Если параметр «value» не задан для ячеек всех остальных типов, то по столбцам, содержащим такие ячейки, не будет корректно работать сортировка, фильтрация и условное форматирование (см. Приложение 2). ------------------------------------------------------------------------------------------------------------------------------------------------------------
Именно по значению value происходит сравнение значений при форматировании, а значение text служит для визуализации значения в ячейке таблицы. Соответственно проверьте какие значения передаются в value при заполнении Вашей таблицы.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Sergey Gorokhov написал: на мой взгляд, это не так критично как это
ЦитатаLet_it_go написал: trades*comiss
Да, действительно, trades здесь однозначно лишнее.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
во-первых непонятно зачем умножаете на 2 и на 1, с математической точки зрения умножение на 1 бессмысленно, во-вторых количество заявок не гарантирует что Вы учли все транзакции, некоторые транзакции могут отвергаться, а я предполагаю, что биржа их тоже учитывает, поэтому Вам нужно считать не количество успешно выставленных заявок, а количество дошедших до биржи транзакций, например через OnTransReply (подробнее см. в справке по Qlua, фильтруйте транзакции по полю status в ответе на транзакцию, чтобы понять какие транзакции дошли до биржи, а значит были учтены ей).
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
s_mike@rambler.ru написал: Толпа колбеков OnDisconnected на уже отсоединенном от сервера терминале. Откуда и что они означают - сказать трудно. При этом в 02-48-44 связь как ни в чем не бывало уже имеется и никаких onconnected и близко нет. Туманно, загадочно и волки воют.
Михаил, добрый день. Колбеки OnDisonnected() вызывались по следующий причине:
10/02/17 в 02:16:37 Ваш терминал был отключен от сервер Quik, но из-за того, что у Вас скорее всего настроено автоматическое восстановление связи с сервером при разрыве, терминал пытался подключиться к серверу, но его отключало по таймауту и на каждый разрыв срабатывал OnDisonnected();
10/02/17 в 02:48:44 сервер QUIK был запущен и терминал подключился корректно, без отрыва по таймауту, но на сервере отсутствовали классы (т.е. ни один шлюз после рестарта сервера еще не подключился), соответственно сервер QUIK не меняет дату торгов, он ее поменяет только после прихода хотя бы одного шлюза с новой датой торгов;
10/02/17 в 03:16:26 на сервер QUIK пришел какой-то шлюз => сменилась дата торгов и сессия на сервере, в терминале сработали OnCleanUp т.к. сменился идентификатор сессии и OnConnected с flag=true т.к. терминал получил класс и дата торгов поменялась.
Все как ранее мной и было сказано.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Михаил, "простыни" я пишу, чтобы Вам объяснить более детально, но можно и коротко: получайте утром новую дату торгов после срабатывания цепочки OnCleanUp() -> OnConnected().
По поводу срабатывания OnConnected(), если терминал подключен с 23-50 до 10-00. Во первых, такого не может быть, т.к. брокеру для корректной работы системы необходимо выполнить рестарт сервера между сессиями, а значит будет разрыв связи терминала с сервером QUIK (исключением может быть выходные дни). Во вторых, в документации явно написано: ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- OnConnected Функция вызывается терминалом QUIK при установлении связи с сервером QUIK и получении терминалом описания хотя бы одного класса. Если в течение торгового дня терминал получает новый класс, то функция вызывается еще раз, при этом параметр вызова flag принимает значение «false». Формат вызова: OnConnected(BOOLEAN flag) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
s_mike@rambler.ru написал: а вы уверены, что торговая дата всегда меняется при с разрывом связи? Я не уверен. А точно это никто не знает)
Михаил, добрый день. Что Вы имеете ввиду под изменением торговой даты с разрывом связи? Давайте разберем возможные варианты: (1) При подключении к серверу сработал OnCleanUp() следовательно (=>) идентификатор сессии в терминале не совпадает с идентификатором сессии на сервере (это возможно когда действительно сменился идентификатор сессии на сервер или когда Вы подключились к другому/резервному серверу или Вы подключились другим пользователем), дальше возможны два пути: 1 - после вызова OnConnected() смотрим на дату торгов в терминале и сравниваем ее с прошлой датой торгов (например можно хранить прошлую дату торгов в файле), если новая дата торгов БОЛЬШЕ старой => дата торгов сменилась; 2 - после вызова OnConnected() смотрим на дату торгов в терминале и сравниваем ее с прошлой датой торгов, если новая дата торгов РАВНА старой => дата торгов НЕ сменилась (такое в теории возможно, например когда брокер рестартует сервер QUIK с чисткой данных среди дня => сервер поменяет идентификатор сессии, НО дата торгов после прихода шлюзов останется прежней);
(2) При подключении к серверу OnCleanUp() НЕ СРАБОТАЛ => Вы подключились к серверу QUIK в этой сессии не первый раз и идентификатор сессии на сервере и в терминале совпадают => дата торгов не поменяется, т.к. Вы уже сегодня подключались и прошли по алгоритму (1).
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
скрипт должен работать и без подключения к серверу.
Тогда нужно реализовывать две ветки, собственно работа скрипта оффлайт (дата торгов не поменяется точно) и работа скрипта после коннекта к серверу (только тут уже смотреть не на OnCleanUp, а на OnConnected), а там уже в зависимости от того поменялась дата торгов или нет свои алгоритмы...
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Попробую помочь в решении Вашей задачи. В документации на QLua написано: ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- OnCleanUp Функция вызывается терминалом QUIK в следующих случаях: смена сервера QUIK внутри торговой сессии; смена пользователя, которым выполняется подключение к серверу QUIK, внутри торговой сессии; смена сессии. Формат вызова: OnCleanUp() При выполнении сразу нескольких из перечисленных условий, функция OnCleanUp() вызывается терминалом QUIK для каждого из них. Под сменой сессии подразумевается изменение идентификатора сессии при подключении к серверу QUIK. ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
из описания видно, что OnCleanUp никак не связан с TRADEDATE, не нужно путать сессию (SESSIONID) с датой торгов. Иными словами, OnCleanUp сработает, если при подключении к серверу терминал посчитает, что нужно почистить старые данные. Соответственно СРАЗУ после вызова OnCleanUp в терминале не будет новых данных, терминал просто информирует о том, что он почистил старые заявки, сделки и т.д. из-за смены сессии на сервере и ожидает новые данные.
Теперь к решению Вашей задачи. Чтобы получить дату торгов Вам необходимо смотреть на колбек OnConnected: ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- OnConnected Функция вызывается терминалом QUIK при установлении связи с сервером QUIK и получении терминалом описания хотя бы одного класса. Если в течение торгового дня терминал получает новый класс, то функция вызывается еще раз, при этом параметр вызова flag принимает значение «false». Формат вызова: OnConnected(BOOLEAN flag) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Соответственно из описания видно, что терминал окончательно установил связь с сервером QUIK, если он получил ХОТЯ БЫ один класс. Из описания проблемы, которую Вы указали в посте #1 предположу, что Ваш терминал подключился к серверу QUIK и не получил ни одного класса (возможно просто еще отсутствовали шлюзы на сервере). OnCleanUp сработал, потому что на сервере сменилась сессия (SESSIONID), но TRADEDATE не поменялась, она меняется когда на сервер утром подключился шлюз с новыми данными и прислал классы. Собственно все.
Итог - получайте дату торгов после вызова OnConnected.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Используйте поле flags на структуре заявки. Вот выдержка из документации на QLua:
бит 0 (0x1) Заявка активна, иначе – не активна бит 1 (0x2) Заявка снята. Если флаг не установлен и значение бита «0» равно «0», то заявка исполнена
перехватываете в OnOrder() изменение заявки и смотрите на флаг.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Используйте поле flags на структуре заявки. Вот выдержка из документации на QLua:
бит 0 (0x1)
Заявка активна, иначе – не активна
бит 1 (0x2)
Заявка снята. Если флаг не установлен и значение бита «0» равно «0», то заявка исполнена
перехватываете в OnOrder() изменение заявки и смотрите на флаг.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Добрый день. Для определения кода параметра, включите в настройках рабочего места Quik настройку Формальное представление данных (раздел 'Программа->Буфер обмена'), добавьте в Таблицу текущих торгов необходимые параметры, скопируйте ее содержимое в буфер обмена (Ctrl+C) и вставьте, например, в блокнот, и Вы увидите, какие значения нужно передавать в STRING param.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Николай Камынин написал: Вообще-то,шлюз ничего не может решать. Он работает по правилу FIFO. ----------------------------- Решать могут, например, маршрутизаторы.
Еще уточню, использую терминологию "шлюз" мы не говорим об обычном сетевом шлюзе, "шлюз Quik" это по сути маршрутизатор, который может роутить транзакции в разные подключения в зависимости от настроенных в нем правил, например в зависимости от кода клиента или торгового счета.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Николай Камынин написал: Вообще-то,шлюз ничего не может решать. Он работает по правилу FIFO. ----------------------------- Решать могут, например, маршрутизаторы. ----------------------------- Вы уж старайтесь не фантазировать, а придерживаться реальной схемы каналов.
Николай, шлюз ничего не ждет, да, в прямом направлении, т.е. входящие в шлюз транзакций от сервера Quik обрабатываются по правилу FIFO, т.е. если ему сервер Quik пришлет транзакции снятия заявок в порядке 1, 2, 3, 4, 5 в таком порядке и будут обработаны и отправлены запросы на Биржу о снятии, но как уточнил Михаил Булычев, транзакционных подключений к Бирже может быть больше чем одно, работают они отдельными потоками и если последовательность снятия заявок 1, 2, 3, 4, 5 была разослана в разные транзакционные подключений, то и обратно отчеты о снятии могут прийти уже в другом порядке.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip