Посоветуйте как правильно передавать данные?, доступ в квик стороннему программиста без права выставления реальных ордеров (для тестирования стратегии)
Посоветуйте как правильно передавать данные?, доступ в квик стороннему программиста без права выставления реальных ордеров (для тестирования стратегии)
Илья написал: nikolz, Какая будет при этом скорость обмена? (для моих задач достаточно настраиваемой в QUIK от 1 сек до 1 минуты устроит).
такая же как у вас сейчас с брокером. можете сделать еще быстрее для этого Вам надо поставить сервер на компе с квиком и затем сделать к нему доступ из интернета.
Boris написал: Есть исправно работающий обработчик стаканов. Хочется прикрутить вывод информации из Quik в сторонние приложения по средством организации передачи данных через socket сервер. Постоянно запускающаяся зацикленная функция вызываемая из main производит обработку и складирование данных в массив. Socket сервер - должен периодически выдавать эту информацию по запросу подключившегося клиента.
Для запуска в Quik сервера используется библиотека luasocket (под lua 5.4.1). Запуск ожидания коннекта ServerRun() - так же запускается из main. При этом после выполнения server:accept() - выполнение какого либо кода прекращается. Прекращается до тех пор пока на сервер не поступит запрос - он не выдаст ответ и только тогда функция table.load(var, 1000) будет запущена повторно. И тоже застопорится до поступления следующего запроса от socket клиента. client:settimeout(2) - должен вроде как прерывать ожидание коннекта и закрывать коннект - что поспособствовало бы продолжению выполнения иного кода, но этого не происходит. Пробовал многое - но ничего не помогло. Где бы в коде не запускалась server:accept() - она останавливает выполнение любых других функций. Как организовать запуск table.load(var, 1000) и ServerRun() - в раздельных потоках - так чтобы выполнение одной функции не останавливалось на период работы другой ? Код для примера (сильно сокращён)
Код
socket = require ( "socket" )
IPAddr = "127.0.0.1" --IP Адрес
IPPort = 3585 --IP Port
client = nil
function main ()
while is_run do
table.load (var, 1000 )
end
ServerRun()
end
function ServerRun ()
while is_run do
client = server:accept()
client:settimeout( 2 )
local line, err = client:receive()
local result = evalString(line)
if not err then client:send(result .. "\n") end
client:close()
end
end
function OnInit (quik_path)
server = assert( socket.bind ( "127.0.0.1" , IPPort))
end
У вас сервер запускает когда main завершает работу. Т е если main работает то сервер не запускается Вы должны его вставить в цикл main
Settings = {
Name = 'ParamRequest' ,
line = {
{ Name = 'ParamRequest' }
}
}
function Init ()
return # Settings.line
end
local class_code, sec_code
function OnChangeSettings ()
OnDestroy()
local DSI = getDataSourceInfo ()
class_code = DSI.class_code
sec_code = DSI.sec_code
PrintDbgStr (tostring(sec_code))
ParamRequest(class_code, sec_code, 'LAST' )
end
function OnCalculate (index)
if index = = 1 then
ParamRequest(class_code, sec_code, 'LAST' )
end
return nil
end
function OnDestroy ()
if sec_code then
CancelParamRequest(class_code, sec_code, 'LAST' )
end
end
При добавлении / удалении индикатора возникают ошибки:
Цитата
Function OnChangeSettings: ACCESS VIOLATION at address 000007FC524B89CC ACCESS VIOLATION at address 000007FC524B89CC
Что не так?
Предположу, что функция getDataSourceInfo вернула nil. Все дальнейшие действия привели к попытке обратится к несуществующему адресу памяти.
Скорее всего эта ошибка связана с функцией PrintDbgStr
Посоветуйте как правильно передавать данные?, доступ в квик стороннему программиста без права выставления реальных ордеров (для тестирования стратегии)
Подскажите пожалуйста как правильно дать доступ к данным и в каком формате?
Задача дать стороннему (!) программисту данные о торгах по акциям в реальном времени (ну или хотя бы минутными свечами) желательно без права выставления ордеров
Исходные данные находятся в настраиваемых колонках квика на примере Акций - Торговля (Код инструмента — Цена открытия — Количество сделок и тп) Для решении задачи сторонние API не подходят и нужен именно квик.
Интересует название самой технологии и примерный порядок действий.
Саму ТС уже придумал но нужно тестировать на реальных потоковых данных. Обратный тест на истории не подходит так как там есть только цена и временные интервалы.
Буду благодарен тому кто скажет в какую сторону "копать". Спасибо.
если сторонний пользователь удаленный, то вам надо создать сервер доступный из интернет. далее используя socket транслируете данные на сервер. сторонний подключается к серверу и получает от него данные. можно использовать технологию MQTT. Примерно так.
для тех кому лень читать (из документации Lua5.3):
/* @@ LUA_INT_TYPE defines the type for Lua integers. @@ LUA_FLOAT_TYPE defines the type for Lua floats. ** Lua should work fine with any mix of these options (if supported ** by your C compiler). The usual configurations are 64-bit integers ** and 'double' (the default), 32-bit integers and 'float' (for ** restricted platforms), and 'long'/'double' (for C compilers not ** compliant with C99, which may not have support for 'long long'). */
Владимир, Вы хотя бы иногда читали документацию на Lua 5.3 б прежде, чем написать эту чушь: -------------------- " Но народные Lua-умельцы тип integer вообще отменили, заменив его на дурацкий тип number" ------------- На форуме бывают дети, они же вам верят.
На самом деле, если Вы знаете до торгов какими конкретно инструментами будете торговать и Ваш робот работает по свечам на таймах не менее минуты, то колбеки вообще не нужны. ---------------------- При таких условиях , робота проще написать как индикатор, т е скрипты Вам тоже нафиг. ------------------------------------ В итоге у Вас получится универсальный робот, который без переделки можно запускать для любого конкретного инструмента. ----------------- Рекомендую всем, особенно буратинам и чайникам.
Glukator написал: Спасибо за ответ. Ваш подход мне понятен, и я с ним в большинстве согласен. В моем случае уход от любых асинхронных вызовов обусловлен дрянной связью (YOTA), которая имеет привычку отваливаться в любую секунду и восстанавливаться, когда ей вздумается. Отправив заявку, можно OnTrade и не дождаться. А через 10-15 минут, когда QUIK соизволит восстановить подключение после серии ошибок "вы уже работаете в системе", все равно придется разбираться с числом позиций, чтобы понять, что же за это время изменилось. В таких условиях работать на коротких таймфреймах невозможно, и надо в первую очередь обходить различные глюки связи.
Нули в trans_id мне пока не прилетали, возьму на заметку.
В вашем случае надо либо интернет настроить , либо установить квик на виртуальный сервер. Цена вопроса рублей 300 в месяц.
Юрий написал: Вот из-за того что первая сделка на разных инструментах приходит не всегда в одно и тоже время, у меня и получается вынос... Потому что один из инструментов в этот момент получается равен 0. Просто для spred это не критично, а для max/low - получается изкажение...
я это учел в своем варианте. если свечи нет, то результат не должен изменяться
Юрий написал: Хм. Попробую, но мне кажется было логично что их три. Ведь те по которым расчитывается spred вообще на другом графике... Я даже практиковал там другой таймфрейм, и всё работало (если не перезагружать основной график).
свечи формируются по времени , поэтому если тайм одинаковый то момент начала свечи будет синхронизирован при получении первой сделки после начала текущего кванта. ----------------------- Например , время 100000 и свеча будет создана при появлении первой сделки. -------------------- Если сделка не появилась, то свеча не создана. ----------------- Поэтому нет никакой разницы на каком графике инструмент.
function OnCalculate(index)
-- Получение свечей инструментов
C1=С(index);
C2=getCandleByTimeCode(Settings.tag2,timeCode).close
if C2 then
spr =C1-C2 -- Вычисление спреда
if index==1 then max=spr; min=spr - Settings.a;
-- Вычисление максимума минимума среднего для спреда
elseif spr>max_p then max = spr; min = spr - Settings.a;
elseif spr<min_p then min = spr; max = spr + Settings.a; end
med = (max+min)/2;
end
return spr,med,max,min
end
function OnCalculate(index)
-- Получение свечей инструментов
C1=С(index);
C2=getCandleByTimeCode(Settings.tag2,timeCode).close
if c2 then
spr =C1-C2 -- Вычисление спреда
if index==1 then max=spr; min=spr - Settings.a;
-- Вычисление максимума минимума среднего для спреда
elseif spr>max_p then max = spr; min = spr - Settings.a;
elseif spr<min_p then min = spr; max = spr + Settings.a; end
med = (max+min)/2;
end
return spr,med,max,min
end
function OnCalculate(index)
-- Получение свечей инструментов
c1=С(index);
c2=getCandleByTimeCode(Settings.tag2,timeCode).close
if c2 then
spr =C1-C2 -- Вычисление спреда
if index==1 then max=spr; min=spr - Settings.a;
-- Вычисление максимума минимума среднего для спреда
elseif spr>max_p then max = spr; min = spr - Settings.a;
elseif spr<min_p then min = spr; max = spr + Settings.a; end
med = (max+min)/2;
end
return spr,med,max,min
end
function OnCalculate(index)
-- Получение свечей инструментов
c1=С(indwx);
c2=getCandleByTimeCode(Settings.tag2,timeCode).close
if c2 then
spr =C1-C2 -- Вычисление спреда
if index==1 then max=spr; min=spr - Settings.a;
-- Вычисление максимума минимума среднего для спреда
elseif spr>max_p then max = spr; min = spr - Settings.a;
elseif spr<min_p then min = spr; max = spr + Settings.a; end
med = (max+min)/2;
end
return spr,med,max,min
end
Юрий написал: Я Вас понял. У меня получается три инструмента! Первый - по нему определяется нумерация свеч, и два других - по которым я считаю "spred ", в новом окне графика первого инструмента. В первом инструменте есть C(index). Там, получается, "искать" предыдущую свечу?
у Вас первый лишний если спред между двумя инструментами то третий лишний. Номер свечи надо брать из первого
Юрий написал: Спасибо! Обязательно попробую! Подскажите, а как мне max/low предыдущей свечи обозначить? Типа (i-1)...
вообще-то я не понял почему Вы два инструмента читаете. ---------------- Я делаю спред так. Один инструмент - это тот , который на графике А второй инструмент - читаем В этом случае данные по первому инструменту это C(index),O(index),L(index),H(index), а предыдущая свеча по этому инструменту будет ...(index-1) ---------------- При этом индикатор помещаем в новое окно под графиком первого инструмента
Вот вам вариант. проверьте, если что не так, то покажите картинки и напишите что не так.
Код
function OnCalculate(index)
-- Получение свечей дополнительных инструментов
c1=getCandleByTimeCode(Settings.tag1, timeCode).close
c2=getCandleByTimeCode(Settings.tag2, timeCode).close
if c1 and c2 then
p1 = c1; p2 = c2 -- Получение цен дополнительных инструментов
spr =p1-p2 -- Вычисление спреда
if index==1 then max=spr; min=spr - Settings.a;
-- Вычисление максимума минимума среднего для спреда
elseif spr>max_p then max = spr; min = spr - Settings.a;
elseif spr<min_p then min = spr; max = spr + Settings.a; end
med = (max+min)/2;
end
return spr,med,max,min
end
nikolz написал: правильные производители авто отзывают все свои авто с ляпом, а производители QUIK делают новые версии с новыми ляпами, а старые не отзывают.
да ладно Вам. У этих правильных производителей похлеще были ляпы несоразмерные в масштабах с ляпами Quik. Не всегда всё идеально получается, а точнее никогда. Стараются, делают что могут и как могут, мы их тут попинываем и это нормально. Я вот 2ой раз только на этом форуме пишу, хотя Quikом с 2015 постоянно(ежедневно) пользуюсь. Как я обычно говорю: "не надо требовать от человека быть тем, кем он не является", к софту это тоже относится.
Тоже пользуюсь квиком и ничего не требую. чел спросил, я объяснил, что если в новой версии ляпы и она меня с ними не устраивает, то ставлю старую. ------------------------ На самом деле наплевательское отношение к ляпам в софте связано с тем , что оно раздается клиентам брокера "бесплатно" Поэтому никаких претензий. ---------------------- Про бесплатный сыр напоминать не буду. А так халява она и в России халява.
NoneB написал: Иногда при создании метки появляется ошибка "Недопустимые данные". Перезагрузка вкладки может помочь, но не всегда. Также после редактировании метки, размер ее окна может разнести почти на весь график и после этого ее не удалить и не отредактировать. Проблема есть во всех девятых версиях
Вы хотя бы выложите то место, где вы метку создаете. А то телепаты все в отпуске.
для начала, я исправил ошибки в Вашей программе, но не проверял. проверьте, если ошибок нет, то напишите подробнее что не так.
Код
--- Вычислить спред.
-- @param index номер свечи на графике
-- @return значение спреда или nil, если оно неопределено
local function getSpread(index)
local timeCode = getTimeCode(T(index))
local securityPrice = C(index)
if securityPrice then
-- Получение свечей дополнительных инструментов
local candle1 = getCandleByTimeCode(Settings.tag1, timeCode)
local candle2 = getCandleByTimeCode(Settings.tag2, timeCode)
if candle1 and candle2 then
-- Получение цен дополнительных инструментов
local price1 = candle1.close
local price2 = candle2.close
if price1 and price2 then
-- Вычисление спреда
local spread = (50 - (100 / (1 + price1 / price2)))*Settings.k
-- Вычисление максимума минимума среднего для спреда
if index == 1 or (T(index).hour < T(index-1).hour) then
max_price = nil
med_price = nil
low_price = nil
end
if max_price == nil then max_price = spread
elseif spread > max_price then
max_price = spread
low_price = spread - Settings.a
med_price = (max_price+low_price)/2
end
if low_price == nil then low_price = spread
elseif spread < low_price then
low_price = spread
max_price = spread + Settings.a
med_price = (max_price+low_price)/2
end
if med_price == nil then med_price = (max_price+low_price)/2
elseif spread < low_price then med_price = (max_price+low_price)/2
elseif spread > max_price then med_price = (max_price+low_price)/2
end
return spread, (max_price+low_price)/2 , max_price, low_price
end
end
end
end
Исполненные заявки не появляются в таблице сделок, Сделал торгового робота для quik на языке lua. Исполнилось 6 заявок, 3 на покупку и 3 на продажу, но в таблице сделок они не появились
Молчанов Виктор написал: Сделал торгового робота для quik на языке lua. Исполнилось 6 заявок, 3 на покупку и 3 на продажу, остановил скрипт, но в таблице сделок ничего не появилось. Скрипта у меня 2: на покупку и на продажу. Не знаю что делать, раньше такого не было. В заранее благодарен.
поэтому я всегда делаю так. Если новая версия по каким-то причинам начинает сбоить, а старая работает без нареканий, то я просто возвращаюсь к старой и жду, когда новая отлежится.
т.е. всё что выше 8.7 ещё не отлежалось? что ж Вы там такого делаете на своём квике - заинтриговали)
тестирую роботов на истории. относительно версии. Пока нет проблем с 8.7, поэтому то что выше ставить не буду. прикольно то, что например сбер начал распространять 9.4, а разработчики уже много раз признали свои ляпы и в 9.4 и в 9.5 и уже сделали ляпы в 9.7 ---------------- Типа так , на версии 9.4 отказывают тормоза, но вы можете ездить. Если разбиться не хотите, то устанавливайте с нашего сервера новую версию. Но прикольно то, что если Вы установите не с сервера брокера и потом у вас все е....ся, то претензии брокер не примет и вы останетесь с ...
с учетом преобразования числа в строку получим следующее
Код
local x=123.456
nkarray.start()
local a,b=math.modf (x)
local u=0.1*nkarray.stop()
print(a,b,u)
nkarray.start()
local s=tostring(x);
local a,b=string.match(s,"(%d+)%.?(%d*)")
local u=0.1*nkarray.stop()
print(a,b,u)
nkarray.start()
local s=tostring(x);
x1,x2,a,b=string.find(s,"(%d+)%.?(%d*)")
--local a=string.sub(x,1,m-1);
--local b=string.sub(x,m+1);
local u=0.1*nkarray.stop()
print(a,b,u)
nkarray.start()
local s=tostring(x);
local m=string.find(s,".",1,true)
local a=string.sub(s,1,m-1);
local b=string.sub(s,m+1);
local u=0.1*nkarray.stop()
print(a,b,u)
Nikolay написал: Не заметил, что целое. Если известен scale, то умножить на 10 в степени.
Или можно воспользоваться магией динамической
tonumber(tostring(3.12459):match("%.(%d+)")) or 0
Почему не сделать просто? a,b=string.match(123.456,"(%d+)%.?(%d*)")
Впрочем, интересно, а в курсе ли уважаемый топикстартер, что 1.2 и 1.02 дадут одинаковый результат?
еще один вариант и в итоге все варианты : -----------
Код
local x=123.456
local s=tostring(x);
nkarray.start()
local a,b=math.modf (x)
local u=0.1*nkarray.stop()
print(a,b,u)
nkarray.start()
local a,b=string.match(s,"(%d+)%.?(%d*)")
local u=0.1*nkarray.stop()
print(a,b,u)
nkarray.start()
x1,x2,a,b=string.find(s,"(%d+)%.?(%d*)")
--local a=string.sub(x,1,m-1);
--local b=string.sub(x,m+1);
local u=0.1*nkarray.stop()
print(a,b,u)
nkarray.start()
local m=string.find(s,".",1,true)
local a=string.sub(s,1,m-1);
local b=string.sub(s,m+1);
local u=0.1*nkarray.stop()
print(a,b,u)
Евгений написал: Здравствуйте. При попытке расчёта стохастика квик выдаёт ошибку: SO.lua:311:attempt to call a number value (global 'C'). Подскажите, пожалуйста, что может быть.
Возможно неправильно указали параметр. покажите как вызываете.
если надо целую и дробную часть, то так: local x=123.456 local a,b=math.modf (x) local u=0.1*nkarray.stop() print(a,b,u) ------------------------- результат (мкс): 123 0.456 0.6 ================ в 12 раз быстрее, чем с match и в 3 раза быстрее чем с find
Nikolay написал: Не заметил, что целое. Если известен scale, то умножить на 10 в степени.
Или можно воспользоваться магией динамической
tonumber(tostring(3.12459):match("%.(%d+)")) or 0
Почему не сделать просто? a,b=string.match(123.456,"(%d+)%.?(%d*)")
Впрочем, интересно, а в курсе ли уважаемый топикстартер, что 1.2 и 1.02 дадут одинаковый результат?
если надо быстрее, то так: x1,x2,a,b=string.find(x,"(%d+)%.?(%d*)") ================== сравним: local x=123.456 nkarray.start() local a,b=string.match(x,"(%d+)%.?(%d*)") local u=0.1* nkarray.stop() print(a,b,u)
nkarray.start() x1,x2,a,b=string.find(x,"(%d+)%.?(%d*)") local u=0.1*nkarray.stop() print(a,b,u) =================== результат (мкс): 123 456 8.6 123 456 1.8 ================== вариант с find в 4 раза быстрее.
nikolz написал: На момент выставления заявки цена была -одна, а когда выставилась Ваша заявка рынок уже ушел покурить и цена фактическая другая.
Вы невнимательны.
1. Заявка выставлена по рыночной цене и поэтому удовлетворяется вне очереди, а при наличии ликвидности (это высоколиквидный GAZP) - мгновенно. 2. От начала редактирования заявки, до выставления не было такого большого перепада цен, я проверил по ТОС
Нулевой объем в ТЗ до момента, пока заявка не начнет удовлетвлряться, а по завершении сделки - реальный объем из таблицы сделок
Объем в заявке расчитывается по цене выставляемой заявки если заявка отправлена по планке то и объем в деньгах будет по планке
что такое -планка? Объем в рыночной заявке рассчитывается по лучшей цене в последнем полученном стакане перед расчетом, а объем в сделке рассчитывается по цене встречной заявки в которую ударилась ваша заявка.
nikolz написал: На момент выставления заявки цена была -одна, а когда выставилась Ваша заявка рынок уже ушел покурить и цена фактическая другая.
Вы невнимательны.
1. Заявка выставлена по рыночной цене и поэтому удовлетворяется вне очереди, а при наличии ликвидности (это высоколиквидный GAZP) - мгновенно. 2. От начала редактирования заявки, до выставления не было такого большого перепада цен, я проверил по ТОС
Нулевой объем в ТЗ до момента, пока заявка не начнет удовлетвлряться, а по завершении сделки - реальный объем из таблицы сделок
перед выставлением заявки брокер оценивает достаточность у вас средств , очевидно эту оценку Вы и видите. Подача Вами заявки никаких обязательств для брокера не создает. Вы можете просто не обращать на это внимание.