В руководстве пользователя QUIK идущем в комплекте с терминалом:
Цитата
Раздел 5: Торговые операции клиента 5.2.2 Окно «Ввод заявки» .......... 12.*«Условие исполнения» определяет порядок обработки остатка заявки при ее частичном исполнении: .......... (*) Указанные параметры отсутствуют при операциях на срочном рынке FORTS.
После вашего комментария решил все же тоже проверить. Вы правы. Как минимум лимитка с условием "Снять остаток" на срочном рынке выставляется и при отсутствии встречки сразу же снимается. Получается, что в документации ошибка.
На мосбирже рыночных заявок по срочному рынку нет как таковых. А то что в квике называется рыночной заявкой, при торговле на срочном рынке как раз превращается в обычную лимитную.
Владимир написал: Это была демонстрация абсолютной НЕработоспособности CreateDataSource
Неработоспособности? Может вы забыли запустить скрипт? Кто-то не умеет работать с данной функцией, кто-то умеет. А на вкус и цвет, как говорится, все фломастеры разные.
Цитата
Владимир написал: на основе которой ВААПЩЕ НЕЛЬЗЯ "реализовать что-либо интересное", такой способ доступа к данным - это КРЕТИНИЗМ!
Опять я наблюдаю столь категоричные высказывания от вас Вы хоть как-то аргументируйте свою позицию-то, а то спорить скучно.
Цитата
Владимир написал: Не говоря уже о том, что функция эта относится к разделу работы с графиками.
Тут согласен, но это уже вопрос терминологии, а не программирования.
Цитата
Владимир написал: С нею невозможно работать при ЛЮБОМ коде, даже вылизанным до последней запятой.
Як так??? Да вы ради интереса хоть попробуйте поработать что ли, а то получается классическое "не читал, но осуждаю".
Цитата
Владимир написал: Во-первых, Lua я знаю. Мало того: я здесь чуть ли не единственный, кто пишет на чистом Lua.
На чистом LUA?? Да быть такого не может! Вы LUA и QLUA не путаете случаем?
Цитата
Владимир написал: Я имел в виду, что оператор этот дурацкий, я так никогда не делал, и делать не буду.
Чем это обычный логический оператор OR то провинился? Прекрасный оператор на мой взгляд, как минимум ни чуть не хуже чем AND и NOT. Кстати, вы знали что в LUA оказывается нет оператора XOR? Мне, например, в свое время его очень не хватало для работы с битовыми флагами.
Цитата
Владимир написал: Во-первых, свечи у меня начинаются с 15-секундных.
А я это и упомянул, что самостоятельно считать свечи стоит только для нестандартных интервалов.
Цитата
Владимир написал: Во-вторых, они считаются по-другому: я уже не раз говорил, что классические мат. ожидание и дисперсия в миллион равз информативнее всей этой "японской" дребедени.
Звучит логично. Поверю на слово, мне лень проверять.
Цитата
Владимир написал: В-третьих, Вы не ответили на мой вопрос: СКОЛЬКО свечей она мне даст по каждому интервалу?
Формирует 3000 последних свечей, но может дать больше, если ранние свечи уже есть в истории терминала
Цитата
Владимир написал: И что она будет делать при появлении очередной свечи? Будет всё время дописывать? Или даже и дописывать не будет?
Создаст свечу с новым индексом и будет обновлять ее данные, пока не появится следующая свеча.
Владимир написал: Нет, я не понимаю: Вы ВСЕРЬЁЗ предлагаете подобную хрень реализовать или прикалываетесь?
Побойтесь бога, зачем мне вам что-то предлагать? Это была демонстрация работоспособности CreateDataSource, на основе которой можно уже реализовать что-либо интересное, но вы это не смогли понять.Или вы думали, что я вам тут полноценного робота со всеми вашими хотелками предоставлю? Ну нафиг...
Цитата
Владимир написал: что делает хреновина вида "ds[tikers[j][1]]=ds[tikers[j][1]] or {}" я не знаю, да и знать не хочу
Понимаю, старость не радость, но вы там держитесь, не унывайте...
Special for you
Код
function main()
ds={}
intervals={INTERVAL_M15,INTERVAL_M30,INTERVAL_H1,INTERVAL_H2,INTERVAL_H4,INTERVAL_D1}
tikers={{"SPBFUT","SiZ1"},{"SPBFUT","SiH2"},{"SPBFUT","SiM2"},{"SPBFUT","SiU2"}}
for i=1,#intervals do
for j=1,#tikers do
ds[tikers[j][1]]=ds[tikers[j][1]] or {}
ds[tikers[j][1]][tikers[j][2]]=ds[tikers[j][1]][tikers[j][2]] or {}
ds[tikers[j][1]][tikers[j][2]][intervals[i]]=CreateDataSource(tikers[j][1],tikers[j][2],intervals[i])
while(ds[tikers[j][1]][tikers[j][2]][intervals[i]]:Size()==0) do sleep(1) end
end
end
-- Пример получения свечи
local need_ds=ds["SPBFUT"]["SiZ1"][INTERVAL_H1]
local size=need_ds:Size()
message("O="..need_ds:O(size).." H="..need_ds:H(size).." L="..need_ds:L(size).." C="..need_ds:C(size))
end
Владимир, Не ожидал Тут же даже кулинарить нечего, все и так очевидно
Создать датасурс и выдернуть из него последнюю свечу проблем нет никаких (см. пример в первом посте). А как в цикле пробежаться по заданным интервалам и инструментам думаю сами догадаетесь.
Владимир, это вы просто не умеете их готовить ))) Я вот часовые свечки дергаю используя CreateDataSource, и никакого атавизма в этом не замечаю, все работает.
Алексей написал: Обрабатывать коллбэк OnOrder? Опять же таки я не нашел в документации ни слова о том при каком условии он вызывается? Только при условии что trans_reply.status = 3 или вообще при любой попытке отправить заявку, даже неудачной?
OnOrder вызывается при получении новой заявки или при изменении параметров существующей заявки и с OnTransReply никак не связан. Ну то есть при trans_reply.status==3 по логике должен прийти OnOrder (и обычно приходит), но как бы прямой взаимосвязи нет.
Цитата
Алексей написал: В первом случае получив и обработав OnOrder можно не запариваться с OnTransReply и его статусом по идее, разве что для информации. Во втором случае в коллбэке OnOrder обязательно нужно проверить trans_reply.status. И опять же появляется другой вопрос, в какой последовательности оба этих коллбэка идут??? Если OnOrder может прийти раньше OnTransReply, то получается полнейшая ерунда, order_num в OnTransReply я получить не могу, а OnOrder не могу обработать, т.к. понятия не имею о статусе заявки...
А тут все гораздо интереснее, и последовательность прихода этих коллбеков может быть любая, но это совершенно не проблема если мы используем очереди событий для указанных коллбеков. Сначала ищем определенное время в очереди OnTransReply нужный ответ с order_num, либо отлуп. После чего так же определенное время в очереди OnOrder ищем нужную нам заявку.
Алексей написал: Но остается открытым вопрос, что же делать то? Но из вашего пояснения получается, что OnTransReply может вызываться на каждую заявку неоднократно? Если это так, достаточно ли фильтровать те, что пришли с order_num = nil и тупо ждать коллбэк с заполненным этим полем, он обязательно появится?
У себя проверял, при trans_reply.status==3 trans_reply.order_num всегда заполнен и равен номеру заявки (при выставлении - новой, при снятии - снимаемой)
Но если я правильно понимаю, то OnTransReply формируется сервером брокера, а не биржей, так что думаю от настроек брокера может зависеть заполненность полей и количество ответов.
Вам стоит проверить сколько и каких ответов придет для конкретно вашего случая
Код
function OnTransReply(trans_reply) -- Функция вызывается терминалом QUIK при получении ответа на транзакцию пользователя
local str="OnTransReply:"
for k,v in pairs(trans_reply) do
str=str.."\n"..tostring(k).."="..tostring(v)
end
message(str)
end
Пропали ценовые колонки в таблице текущих торгов, Пропали ценовые колонки в таблице текущих торгов. В доступных параметрах их тоже нет - добавить нельзя. Брокер виноват?
Лично я запускаю квик с ключом запуска "-clear" (можно прописать его, например, в ярлыке quik)
Цитата из документации
Цитата
-clear – очистить служебные файлы, которые содержат торговые данные (info.log (или curr_data.log в зависимости от настроек терминала), acnt.dat, alert.ik, alltrade.dat, trades.dat, orders.dat). Это позволяет ускорить загрузку программы.
Данные за последнюю сессию автоматом подтянутся при подключении к серверу.
Короче, составляем список нужных файлов, и скармливаем их в винрар, он умеет архивировать заранее заданный список файлов и скидывать архив куда требуется. Архив должен сохраняться по сети на другой комп/сервер. Автоматизируем эту процедуру на запуск каждую ночь.
Так как в квике все настройки расположены в файлах, а жесткий диск поменяли, то настройки вам придется вручную все восстанавливать.
Обычно диски одномоментно не помирают, так что возможно со старого диска еще можно вытащить инфу? Достаточно найти на старом диск папку в которой был расположен квик, и скопировать его на новый диск.
Ну и напоследок. Люди делятся на два типа: те кто делают бекапы и те, кто пока еще их не делают. Первым гораздо спокойнее живется.
Олег написал: Вопрос: как прописать код, чтобы сообщение появлялось либо раз в N минут (но тогда именно сразу после открытия новой свечи)
Примерно так можно выдавать сообщение не чаще чем раз в N секунд
Код
delta=5 -- время задержки в секундах
is_run=true
function main()
while is_run do
if(os.time()>=(last or 0)+delta)then last=os.time() message("Чпок раз в "..delta.." секунд") end
sleep(100)
end
end
function OnStop()
is_run=false
end
условие появления новой свечи, сами добавите, мне писать лень
Цитата
Олег написал: либо просто появлялось всего один раз на каждое условие, а не зацикливалось по кругу?
А в таком случае надо сохранять предыдущие условия и добавить проверку на из изменение этих условий
Владимир, а можно ссылку на то кто вам "популярно объяснил" про расчет свечей на клиенте? Просто звучит как что-то неразумное. Всегда считал, что свечи с сервера получаем.
Владимир написал: А какие у Вас основания "так не считать"?
Ну так совершенно не честно, ибо это вопрос из разряда, "докажи что бога нет". Бремя доказательства всегда лежит на утверждающем наличие чего-либо, а не наоборот.
Цитата
Владимир написал: У человека просто нет шансов против компьютера!
А это тут причем? Компьютер, по сути счетная машинка, только охрененно быстрая.
Вот когда кто-нибудь сможет написать программу умнее его самого, вот тогда будет изобретен искусственный интеллект. А до того знаменательного момента, мы имеем лишь программы работающие по заранее заданному алгоритму, пускай и очень сложному, но сути то это не меняет.
PS: Вы бы уж тогда ссылку на свою книгу кинули, кому интересно - почитает. А пытаться приводить доказательства цитатами из своей же книги, на мой скромный взгляд, слишком уж оригинально.
Роман, это нормально. Дело в том, что при открытом графике данные уже находятся у вас в терминале, поэтому CreateDataSource отдает данные практически моментально, ну или с минимальной задержкой. Если же график закрыт, то данные сначала должны загрузиться с сервера на терминал, а на это нужно некоторое время.
Добавьте в код ожидание загрузки данных, должно помочь.
Код
ds,error_desc=CreateDataSource(class_code,sec_code,interval)
local n=0
while(ds:Size()==0)and(n<100)do sleep(100) n=n+1 end -- Ждем загрузки данных не более 10 секунд
if(ds:Size()>0)then message("Данные графика получены") else message("Ошибка получения данных") end
Владимир, я вас услышал. Причину разногласий понял так, что вы считаете, что алгоритм может быть умнее его разработчика, я же так не считаю.
Я рад за вас, что ваш робот так хорошо прогнозирует ситуацию, которую вы, как утверждаете, даже оценить не можете. Мой тоже молодец, но все его действия я отлично понимаю, и знаю когда и почему он что-либо делает.
У нас просто принципиально разный взгляд на зависимость возможностей написанных разработчиком алгоритмов от его умственных способностей.
Робот торгует по алгоритму заложенному в него разработчиком. И если в алгоритм заложено, что при определенных обстоятельствах робот должен совершать определенные сделки, это значит, что разработчик считает, что именно так он бы и поступил. И если брать конкретно ваш пример с покупкой, то когда вы закладывали в алгоритм робота данную покупку при повышении, неужели не считали, что именно так и надо поступать при сложившихся обстоятельствах? Ну не поверю я, что алгоритм написан против своей же логики, типа хрен с ним, сам бы никогда не купил, а робот пускай покупает.
А то что вы пишите, мол не смогли бы сотворить такого руками, это уже конкретно ваш психологический момент, от которого, кстати, легко избавиться при желании. Но к программированию это совершенно не относится, тут другие специалисты нужны.
PS: про шахматы даже комментировать не буду, пример не корректен.
Робот это всего лишь автоматизация, его цель делать то же самое, что бы делал трейдер, только быстрее.
Так что ответы очевидны. 1) Робот будет зарабатывать (ну или терять) столько же, сколько зарабатываете вы руками. 2) Стоит, если вы руками умеете зарабатывать, но надоело постоянно торчать за терминалом. 3) Когда робот отлажен, то времени на него уже не тратится. Другой вопрос, что пока пишите, замучаетесь ловить и обходить косяки квика.
Виталий написал: Необходимо каждый день находить код обновляемого инструмента. Из данных имеется только лишь его префикс от короткого имени. Обычно делается следующим кодом:
Код
function findSecurity ()
local mdt = 0
local now = os.time ()
local foundcode = ""
for i = 0 , getNumberOf ( "SECURITIES" ) - 1 do
local row = getItem ( "SECURITIES" , i)
if (row.class_code = = "PSAU" ) and ( autolib.CheckAssetName (row.short_name) = = true ) then
--message(row.short_name)
local info = getSecurityInfo (row.class_code, row.code)
if info ~ = nil then
local expdt = strDateToEpoch(info.mat_date)
--message(tostring(info) .. " " .. tostring(expdt) .. " " .. tostring(now))
if expdt > mdt and expdt > now then
mdt = info.mat_date
foundcode = row.code
--message(tostring(info.mat_date) )
end
end
end
end
if foundcode ~ = "" then
autobuyerlib.LogU8 ( string.format ( "Найден инструмент %s" , foundcode))
end
end
Проблема в том, что часто (процентов 20% случаев) запуск кода дает ошибку ACCESS VIOLATION. Есть ли иной способ решить задачу?
Проще надо быть, зачем такой огород городить то?
Код
local sec_list=getClassSecurities(class_code)
for test_sec_code in string.gmatch(sec_list,"("..pref.."[^,]+)") do
-- в test_sec_code инструмент с нужным префиксом, далее ищите по mat_date нужный вам, мне лень писать
end
Daniil Pozdnyakov написал: Добрый день, Могли бы вы уточнить, что вы имеете в виду под "market"
у class TQBR возвращает micex. У SPBXM - nil. У class CETS возвращает nil. Вот и думаю, может, вручную задать этот параметр.
class="CETS" market=get_market(class)
Да не нужны никакие маркеты для торговли. Достаточно class_code и sec_code. Все.
Вам со своим роботом разобраться надо, что за market он там у вас возвращает и главный вопрос нахрена он вашему роботу нужен. Короче смотрите код своего робота и начните с функции get_market
Egor Zaytsev написал: Дело в том,что описание инструментов засылает биржа, после экспирации старый контракт шлюз с биржи уже не получает и транслировать на сервер нечего.
Egor Zaytsev написал: Но брокер может решить Вашу задачу, на стороне сервера QUIK есть решение, которое поможет Вам получать с сервера описание экспирированных фьючерсов
Вы предлагаете запрашивать вручную у брокера данные по инструментам которые и так уже имеются у пользователя и меняться не будут никогда? Если я вас правильно понял, то решение, думаю, рабочее, но ведь не логичное.
Давайте еще раз и медленно 1) В терминале имеются исторические данные по инструментам 2) Обратиться к ним нет возможности 3) Прошу дать возможность работать с этими данными 4) Я даже предложил способ как это сделать
Если делать склейки инструментов при экспирации? Данные будут склеиваться, правда имя инструмента будет новое, но исторические данные получить сможете. Или такой вариант не удобен?
Такой вариант очень неудобен.
Может все же рассмотрите озвученное мной предложение?
Каждый при желании может написать свой тестер стратегий. Но на данный момент нет возможности получить доступ к историческим данным, однако исторические данные у многих имеются в папке archives терминала. Разве не логично бы было дать способ доступа к ним?
Ошибки в Qlua - двойной прогон всех индексов через функцию OnCalculate(), При добавлении индикатора на график происходит двойной прогон всех индексов через функцию OnCalculate()
vladindre написал: У меня из-за этой фичи пишутся в файл две одинаковые записи , что приводит к дальнейшему слому моего алгоритма чтения/записи. Приходится выкорячиваться и обходить эту фичу всякими нецензурными методами. Зато программерское мастерство сильно хорошо оттачивается.
Как уже сказали, этому косяку уже много лет, и фиксить его разрабы почему-то не желают.
У себя я решил проблему примерно так (упростил и вырезал стратегию)
Код
function OnCalculate(i)
if(sec_code~=getDataSourceInfo().sec_code)or(class_code~=getDataSourceInfo().class_code)or(interval~=getDataSourceInfo().interval)then
lines={} -- Массив со кешем рабочих линий
interval=getDataSourceInfo().interval
sec_code=getDataSourceInfo().sec_code
class_code=getDataSourceInfo().class_code
end
if CandleExist(i) and lines[i]==nil then
-- тут мои вычисления
lines[i]={}
lines[i]["S"]=sell
lines[i]["B"]=buy
end
return lines[i]["S"],lines[i]["B"]
end
В результате индикатор рассчитывается для каждой свечи только один раз, и полностью пересчитывается при смене инструмента или интервала
Примите еще одно пожелание по тестированию стратегий. Сам тестер стратегий у меня давно написан, но остался вопрос в исторических данных для него.
Так вот хотелось бы иметь возможность работать и историческими данными инструментов утративших актуальность. Поясню. Работаю с фьючерсами, на данный момент актуален SiU1. А мне хочется протестировать мою стратегию на более старых инструментах, например SiH1 и SiM1 Как я понимаю исторические данные по инструментам лежат в терминале в папке archive. У меня например имеются файлы SPBFUT_SiH1_60.dat и SPBFUT_SiM1_60.dat ну и некоторые другие
На данный момент, если я пытаюсь обратиться через CreateDataSource к SiH1, то получаю ошибку "SiH1 - unknown sec code." Так вот хотелось бы иметь возможность обращаться из скрипта к вышедшим из оборота инструментам. Все данные то имеются у меня имеются.
Решение вижу в добавлении необязательного параметра в функцию CreateDataSource, при установке которого данные будут напрямую браться из архивного файла с историческими данными игнорируя запрос инструмента у сервера и не проверяя его актуальность.
Владимир написал: Предлагаю радикальное решение проблемы.
Насколько я понимаю, существует некий "регламент работы с клиентами", который обязывает реагировать на замечания и предложения участников форума, но не обязывает их исправлять - достаточно стандартной отписки: "Ваше предложение зарегистрировано", после чего проблема как бы закрыта, и следующее аналогичное или даже тождественное предложение начинает жить своей жизнью, и так по кругу. Мало того: сами сотрудники техподдержки не помнят (или делают вид, что не помнят), что данное предложение уже подавалось. А нужно бы изменить регламент примерно так: 1. Заводится страничка, в которой сидит таблица со всеми предложениями, пронумерованными, прошнурованными, столбцы которое примерно такие: а) Порядковый номер предложения б) Автор (ник) в) Дата подачи предложения (и ссылка на него) г) Содержание предложения (лучше в "приглаженной" форме, убирая эмоции, если они там есть) д) Решение по предложению е) Причина отклонения либо предполагаемая дата реализации ж) Дата фактической реализации либо причина, по которой предложение не было реализовано.
Собрать такую страничку не так уж сложно - например, я сам могу не полениться и денька три посидеть в сообщениях сотруждников техподдержки и вытащить оттуда все посты о регистрации. Да, в конце концов, могу даже у себя на сайте такую таблицу сварганить! И я считаю, что подобное действие в состоянии серьёзно изменить отношения к пожеланиям пользователей: регламент - штука СТРРРРАШНАЯ!
Ну как, господа из техподдержки - регистрируем моё предложение? ::
Предложение у вас правильное и реально хорошее. Вот только готов поспорить, что никто не допустит вас к списку заявок арки.
Помнится ранее были уже предложения дать доступ с списку заявок, отказали. Не желают никому показывать сей секретный список.
Игорь написал: BlaZed, Наверное так правильно да, просто кажется бесконечным. Чем больше узнаешь, понимаешь как много ты еще не знаешь)
Это нормально. Я вот своего писал неделю если не меньше , зато потом еще где-то полгода ловил и исправлял ошибки которых по логике-то и быть не должно. Это у вас еще впереди. Просто учти, что написать робота это несложно, сложно будет заставить его корректно обрабатывать постоянно встречающиеся нестандартные ситуации.
Бегло пробежавшись по коду, сражу же понятно что его не стоит использовать. 1) CreateDataSource нет проверки что он хоть что нибудь вернул 2) SetEmptyCallback не надо вызывать в цикле, одного раза достаточно 3) getInfoParam("SERVERTIME") в нерабочее время может вернуть все что угодно, будете посылать свои заявки в пустоту и ловить ошибки 4) не учтено время клирингов, в которое будете получать от биржи всякий бред, который надо жестко фильтровать 5) С таблицей futures_client_holding тоже не все так просто, она запросто может оказаться например пустая, хотя позиции есть, но еще не прогрузились. Ну или например сделка уже прошла, но колбек задерживается из-за нагрузки сервера и таблица не успела обновиться, в результате получаем некорректные данные. 6) ну про стратегию торговли по SMA тут и говорить не чего
Да не стоит брать чужих роботов, бед только хлебнете. Пишите с нуля неспешно, чтобы понимать полностью весь код.
Дело в том, что чистый код робота это по сути-то получил позиции, получил данные на основе которых выдал/не выдал сигнал, после чего и создал заявку и так по кругу Но в реальной торговле это совершенно не жизнеспособно.
А в результате чуть ли ни половина кода робота будет обработка не стандартных ситуаций возникающих при торговле и устранение косяков qlua через разнообразные костыли.
Сначала выполните рекомендованные настройки от разработчиков. Заходим сюда https://arqatech.com/ru/support/files/ и находим в разделе документации файл "Инструкция по устранению затруднений, связанных с нечитаемым отображением шрифтов в терминале QUIK для ПК на Windows 10"
Владимир написал: Самый надёжный способ - не запускать ничего автоматом.
А как же максимальная автоматизация всего и вся?
Цитата
Владимир написал: Я не понимаю, что такое "быть постоянно привязанным к терминалу"
Тут можно только показать что такое быть минимально привязанным к терминалу.
У себя настроил так. Отдельный системник, на котором кроме квика и нескольких служебных утилит ничего нет. При загрузке системы автологин пользователя, при логине пользователя автостарт квика, при старте квика автологин у брокера плюс смски при двухфакторной авторизации принимаю и подставляю тоже автоматом, а после коннекта к брокеру начинает работать торговый скрипт. Обновления винды разрешены по умолчинию, а в период неактивности, что установлен на неторговое время, разрешил перезагружаться при необходимости. При восстановлении питания после отключения электричества машина автоматом включается, хотя беспребойник держит. Ну и каждую ночь бекап файлов настроек квика и скриптов. Плюс всякая мелочевка о которой и упомянать не стоит.
Короче все до чего дотянулись руки автоматизировал.
Полтора года так работаю изредка только что-то допиливая, полет нормальный.
Если в скриптах ничего не меняю, то могу и по неделе в терминал не заглядывать, дольше просто не выдерживаю.
Михаил написал: В связи с этим еще вопрос, планируется ли адаптация QuikJunior под реальные торги
Так нечего адаптировать, QuikJunior и Quik это один и то же терминал, только настройки отличаются. Тут весь вопрос в корректности трансляции данных игрушечного сервера арки.