Простой MA-робот QLua с выставлением тэйк-профит и стоп-лимит

Автор записи: Дмитрий (Admin)
1 звезда2 звезды3 звезды4 звезды5 звезд (Голосов 8, среднее: 5,00 из 5)
Загрузка...

!!! ДЛЯ ИСПОЛЬЗОВАНИЯ ТОЛЬКО В ОБРАЗОВАТЕЛЬНЫХ ЦЕЛЯХ НА ДЕМО-СЧЕТЕ !!!

img-2015-09-12-22-41-55

Скачать "Простой MA-робот"

Робот торгует по 2-м простым(simple) скользящим средним (MA), выставляет тэйк-профит и стоп-лимит.
1. Если нет открытых роботом позиций выполняется следующий алгоритм:
1. Если быстрая скользящая пересекает медленную снизу вверх и на текущей свече еще не открывались позиции, совершается покупка.
2. Если быстрая скользящая пересекает медленную сверху вниз и на текущей свече еще не открывались позиции, совершается продажа.
2. Если открылась позиция, выставляется "Тэйк-профит и Стоп-лимит"
3. Робот ждет, пока закроется позиция по Стоп-лоссу, либо Тэйк-профиту, после чего переходит к пункту №1

Особенности:
1. Робот выводит в текстовых сообщениях информацию о ключевых моментах алгоритма, у всех его сообщений префикс "Простой MA-робот:".
2. Робот всегда находится в 1-м из 2-х состояний(ROBOT_STATE):'В ПРОЦЕССЕ СДЕЛКИ', либо 'В ПОИСКЕ ТОЧКИ ВХОДА'.
3. Если при выставлении заявки на продажу робот узнает, что операции шорт запрещены по данному инструменту, он больше не будет открывать шорт, только лонг.
4. Когда робот получает сигнал на открытие сделки, он совершает 10 попыток с прмежутками в 100 мс открыть позицию, если этого не удается, останавливает скрипт.
5. После открытия позиции робот совершает 10 попыток с прмежутками в 100 мс выставить Тэйк-профит и Стоп-лимит, а затем дождаться закрытия позиции, если этого не удается, останавливает скрипт.
6. Если стоп-заявка сработала, но позиция не закрылась в течении 10 секунд, пытается за 10 попыток принудительно закрыть позицию встречной сделкой.
Если позицию удалось закрыть (даже принудительно), продолжает работать, иначе скрипт останавливается.

Если найдете какие-то ошибки, недочеты, или просто придумаете как сделать алгоритм более оптимальным, пишите в комментариях, или на почту reply@quikluacsharp.ru. Буду очень признателен!!!

Код скрипта

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Добавить комментарий

Простой MA-робот QLua с выставлением тэйк-профит и стоп-лимит: 340 комментариев

  1. Значения МА на графике и значение МА рассчитанное роботом иногда совпадают, а иногда разняться - кто правильно считает все таки.

      1. Код функцию МА в студию скину? посмотришь? Я сделал как у тебя - вроде все правильно - сегодня еще день посвятил тому что наблюдал и полазил по сайтам как кто что делает - все так делают - как написано. Других подходов по расчетам МА не нашел и не увидел. Кидаю часть кода?

          1. 1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            
            function Mashka() -- Функция возвращает значение МА по индексу свечи
               --DS = CreateDataSource("SPBFUT", Fut, 1) -- Получает доступ к свечам графика (вот так было - вис терминал - перенес в ОнИнит - хорошо все стало. Периоды 5 и 10 и график 1 минутка - ну это мне так надо в своем боте)
               local Index = DS:Size()
               local Fast = 0
               for i = Index, Index - (5 - 1), -1 do -- Перебирает последние свечи
                  Fast = Fast + DS:C(i)
               end
               Fast = RtS(Fast / 5) -- Быстрая МА (текущая свеча)
               local Slow = 0
               for i = Index, Index - (10 - 1), -1 do -- Перебирает последние свечи
                  Slow = Slow + DS:C(i)
               end
               Slow = RtS(Slow / 10) -- Медленная МА (текущая свеча)
               return {["Fast"] = Fast, ["Slow"] = Slow}
            end
                  1. Все понятно как всегда - щас подправлю у себя. Спасибо. Но в принципе то расчет же у меня верный, почему все таки данные разнятся - ну сейчас подписку сделаю может поможет.

                    1. Проверил - результат - разные, иногда одинаковые данные - сравнивал Квик индикаторы на графике с данными бота - разнобой.

                    2. Дмитрий, ты меня таким вопросом "оскорбил" - я че дебил по твоему, совпадают конечно (проверял и перепроверял не однократно). Говорю иногда значения один в один, но чаще всего разные в пунктов 5 примерно - на Si реал 1 минута. Я подозреваю может индикатор тот что в Квике по другому, более сложно высчитывает и более правильно (по графику то индюк хорошо показывает, а вот бот косячит) нежели чем расчет Lua (ну все так считают как у тебя написано). Но в принципе этот вопрос то же можно обойти поставить некий фильтр да и все. Моя задача получить более менее надежное пересечение - если будет 50/50 (что сейчас и происходит), то у меня там все равно есть свои фишки как ложные пробои отработать.

                    3. Ни в коем случае не хотел обидеть, просто дьявол в мелочах всегда кроется, чаще всего ошибка на поверхности, где даже не думал, с какого периода расхождения начинаются ? На периоде 1 не может ведь быть расхождений, это же просто цена закрытия будет.

                    4. На обиженных воду возят поговорка такая есть вроде бы - я про оскорбление же пошутил - все четко - правильный вопрос ты задал, что настройки индикатора типа проверь - да это так, все проверяю все делаю и если тупик то к тебе на сайт бегом - тупых или дурацких то вопросов вроде не задаю, сначала сам пытаюсь разобраться ну как ты и говорил и всем такой посыл - сначала сами, потом сюда к Дмитрию (а то есть чуваки разжуй им, тесты проведи и деньги еще им отдай - ну это то же +/- шутка).
                      "просто дьявол в мелочах всегда кроется" - смотришь в книгу видишь фигу - да так бывает - но это чисто если код пишешь и там есть ошибки - здесь в расчетах МА ошибок то нет - НО возможно что то где то не так надо искать и рыть буду смотреть делать
                      "чаще всего ошибка на поверхности, где даже не думал" - Дак да так и есть просто че то не вижу видимо
                      "с какого периода расхождения начинаются" - Я просто текущую свечу с показаниями бота (в таблице бота выведены) сравниваю
                      На периоде 1 не может ведь быть расхождений, это же просто цена закрытия будет - дак и я о том же - но происходит это - если вот интересен этот вопрос и время есть сам проверь увидишь

                    5. Еще как вариант может все таки я где то что не понял и накосячил - ну как вариант то же возможно - хотя функция вверху вот такая ей считаю

                    6. Ну посмотри пожалуйста, просто интересно сравнить результаты и тему все таки эту отработать и добить.

                    7. Во первых я не знаю что такое функция RtS, а во вторых, я думаю, что все дело в том, что у тебя в коде идет разбег по времени. Если ты в коллбеке графика считаешь ма, то он, скорее всего сначала приходит в скрипт, а потом ма на графике пересчитывается, в тот момент когда ты посчитал свою ма, ма на графике еще не пересчиталась. Либо наоборот, ты берешь значение ма с графика, а потом считаешь свою, но в скрипте ты берешь последнее значение из DS, а оно может успеть поменяться в момент расчета и опять несовпадение, попробуй отключиться от сервера и тогда считай и сравнивай.

                    8. RtS - округляет до шага цены инструмента.
                      А так что то не понял совсем.
                      DS:SetEmptyCallback() - Эту строку убрать? Так ее и не было у меня первоначально - с ней и без нее все равно не так считает

                    9. Ты не понял что я имел в виду, SetEmptyCallback убирать не нужно, нужно при разорванном соединении с сервером тестировать, чтобы исключить изменяющуюся в моменте цену закрытия последней свечи.

                    10. Попробовал разорвать соединение сравнил - та же картина.

                      1
                      2
                      
                      while (Error == "" or Error == nil) and DS:Size() == 0 do sleep(100) end -- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт)
                         if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) return end

                      Щас только заметил при включенном графике все работает, если графика нет терминал виснет сразу и потом только перезагрузка. Удалил эту часть кода - график открыт - ну понятно все работает, графика нет - робот включается и 1-2 сек ждет потом начинает данные показывать.

                    11. Вот такой скрипт нормально работает (проверял):

                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12
                      13
                      14
                      15
                      16
                      17
                      18
                      19
                      20
                      21
                      22
                      23
                      24
                      25
                      26
                      27
                      28
                      29
                      30
                      31
                      32
                      33
                      34
                      35
                      36
                      37
                      38
                      
                      RUN = true
                       
                      Period = 5
                       
                      main = function()
                         -- Подключается к графику цен для входа
                         DS, err = CreateDataSource('SPBFUT', 'SRZ7', INTERVAL_M1)
                         -- Подписывается на обновления
                         -- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт)  
                         while RUN and err == nil and DS:Size() == 0 do
                            sleep(1) 
                         end
                         if not RUN then return false end
                         -- Если произошла ошибка, выводит ее и останавливает скрипт
                         if err ~= nil then
                            message('Ошибка: '..err)
                            OnStop()
                            return false
                         end
                         DS:SetUpdateCallback(Callback)
                       
                         while RUN do
                            sleep(10)
                         end
                       
                      end
                       
                      OnStop = function()
                         RUN = false
                      end
                       
                      Callback = function(idx)
                         local sum = 0
                         for i = idx + 1 - Period, idx do
                            sum = sum + DS:C(i)
                         end
                         message('MA = '..sum/Period)
                      end
                    12. Ну короче рано радовались - запустил и твой скрипт в месседже смотрел смотрел - как назло все было одинаково (долго наблюдал), а сейчас смотрю (твой расчет вписал в своего бота для сравнения с моим расчетом - один в один все те же цифры ни разу не видел расхождений - наблюдаю долго), а с графиком щас вот опять пошло расхождение - я так заметил когда тихо спокойно, то все четко цифры одинаковые - как только дернулась цена, то все значения разные - вот так вот (ну наши расчеты одинаковые, а график другой)

                    13. Может у тебя скрипт как-то терминал подвешивает в моменты движений и он отрисовываться не успевает.

                    14. А при чем здесь мой скрипт (скрипты, боты мои в подвешивании терминала ни разу не были уличены - все четко работает) я смотрю в меседже за твоим скриптом и твоим расчетом/моим расчетом один в один все показывает. В меседже твой код то же расходится с графиком - я долго наблюдаю (сначала все с графиком сходилось щас пошли разночтения ну иногда так как в графике иногда нет)

                    15. Ну хочешь скину свой код тебе на почту - там уже вписан твой расчет и посмотришь - если да то да нет так нет

  2. я не нашёл, можете попустил? а где указывается количество Лотов для торговли? Робот будет торговать только одним лотом? или этот параметр можно изменить? Где?

    1. я нашёл в тексте торгует 1 лотом. а в программе там где "дополнительные функции" с строки 214 до строки 224 есть данные 1 лот - количество. Значит если там изменить данные на другое количество, то этого достаточно , чтобы он торговал другим количеством лотов? или что-т еще требуется?

  3. доброго времени суток
    возникла такая проблема - из программы по сигналу отправляется команда в скрипт в виде строки и распарсивается на вменяемую команду, которую квик без проблем съедает, далее выставляется заявка на покупку/продажу по рынку И сразу же снимается
    в чем может быть подвох или проблема?

    цена, по которой выставляется заявка, берется из стакана в режиме онлайн

  4. Вечер добрый, Дмитрий!
    Помогите разобраться с кодом, сам не знаю что вышло:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    -- Если быстрая пересекла медленную СНИЗУ ВВЕРХ
    if FastMA(DS:Size()-1)  SlowMA() then
       -- Выводит сообщение
       message('Простой MA-робот: пересечение СНИЗУ ВВЕРХ');
       local totalnet == nil;
       -- ЖДЕТ пока изменится состояние ТС
       while Run do
          -- Перебирает строки таблицы "Позиции по клиентским счетам (фьючерсы)", ищет Текущие чистые позиции по инструменту
          for i = 0,getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do
             -- ЕСЛИ строка по нужному инструменту И отсутствует чистая позиция ТО
             if getItem("FUTURES_CLIENT_HOLDING",i).SEC_CODE == SEC_CODE and getItem("FUTURES_CLIENT_HOLDING",i).totalnet == 0 then
                -- Выводит сообщение
                message('Простой MA-робот: отсутствует чистая позиция при пересечении СНИЗУ ВВЕРХ');
                -- Задает направление НА ПОКУПКУ
                CurrentDirect = 'BUY';
                message('CurrentDirect = "BUY"');
                -- Меняет СОСТОЯНИЕ ТС на "В ПРОЦЕССЕ СДЕЛКИ"
                ROBOT_STATE = 'В ПРОЦЕССЕ СДЕЛКИ';

    при пересечении средних появляется только сообщение, например "Простой MA-робот: пересечение СНИЗУ ВВЕРХ"
    Что-то не так наваял 🙂
    Буду признателен за указание на ошибки.

    1. п.с. знаки больше, меньше или равно не отражаются, но в коде присутствуют и работаю, так как сообщение о пересечении приходит своевременно

      1. Здравствуйте! А что не работает-то? В приведенном Вами коде кроме вывода сообщений больше ничего и нет.
        Есть в нем ошибка:
        local totalnet == nil
        чтобы присвоить значение переменной используется одинарный знак равно, а у Вас двойной, двойной используется в выражениях сравнения только. По идее, такой скрипт вообще не должен запускаться, а должно появляться сообщение о синтаксической ошибке в окне "Доступные скрипты" и в "Таблица сообщений", которую можно открыть нажав F7 и "Таблица сообщений"

        1. Спасибо, Дмитрий, за подсказку на строчные буквы в коде.
          Я пытался изобразить логику: перебор таблицы "Позиции по клиентским счетам (фьючерсы)", при отсутствии чистых сделок задать направление и изменить состояние робота, но явно что-то не учел, что не дает коду работать дальше сообщения

          1. Всегда пожалуйста! Ставьте message после каждой строки и увидите как код работает, или где перестает работать. Возможно у Вас в таблице позиций по счетам нет ни одной строки и цикл for не выполняется по этому, в общем, когда не понятно что происходит, нужно месседжами узнавать, т.е. отладку делать.

            1. Отлично, методом месседжей самое то!
              Спасибо за совет, иначе у меня знаний недостаточно узнать где косяк в коде 🙂
              Но логика ведь есть в том, что я описал?

  5. Приветствую, Дмитрий.
    Изменил Ваш код с отработкой на вход/выход только по условию пересечения средних. При тестировании на демо в Quik заметил, что иногда открывается в том же направлении еще одна позиция без видимого пересечения на графике Quik (видно разрабы заложили в алгоритм прорисовки линий некий фильтр), после чего при закрытии свечи пересечения на графике так и не происходит. Думаю причина в шумовых выбросах цены с последующим отловом Вашим кодом расчета момента пересечения по значениям МА.
    Как можно исключить последовательное открытие в одном направлении более одной заявки?
    Думаю, такая проверка (контроль кол-ва открытых позиций) должна быть ПОСЛЕ проверки условия на пересечение МА и ДО смены направления. Заранее благодарен

    1. Здравствуйте! Заведите переменную и запоминаете в ней индекс свечи, на которой открываете позицию и, перед открытием новой позиции, проверяйте не равен ли индекс текущей свечи индексу, на котором была открыта предыдущая позиция. Если равен, то не открывайте больше, если не равен, то открывайте и сохраняйте текущий индекс в этой переменной.

  6. Здравстуйте! А как можно с помощью <> изменить размер стопа (если например 2 тейка и один сработал) или размер тейка (если например было усреднение и надо тейк изменить)?
    Т.е. чтоб не делать лишних движений с удалениями старых и выставлениями новых...

            1. Пожалуйста, печально только в момент написания кода, потом робот будет это делать и Вас никак не будет это напрягать 🙂 В любом случае, любое изменение любой заявки происходит по факту с промежуточным снятием, даже если для этого используется всего одна транзакция.

        1. А Вы не на QLua пишите? Я, кстати, не помню сейчас, помню только, что был какой-то нюанс с этим типом транзакций, вроде бы такая транзакция не поддерживается при отправке через библиотеку trans2quik.dll, но, мне кажется что через QLua должно работать. Если Вы на QPILE пишите, то я Вам ничего не подскажу, т.к. вообще не писал на нем никогда ничего, когда я познакомился с квиком, в нем уже была QLua и я ее сразу стал осваивать, тем более сейчас уже даже поддержку QPILE разработчики убрали, т.е. это "умирающая" технология и не рекомендуется ее использовать.

            1. Вот какой ответ тех.поддержки нашел на форуме квика от 15.02.2016 10:46:21

              Добрый день,
              Причина в том, что функции
              «KILL_ALL_ORDERS» – снять все заявки из торговой системы,
              «KILL_ALL_STOP_ORDERS» – снять все стоп-заявки,
              «KILL_ALL_NEG_DEALS» – снять все заявки на внебиржевые сделки и заявки на сделки РЕПО.
              не предназначены для использования в LUA.

                  1. Теперь я решил снимать по одной заявке. Но мне выдаёт ошибку:"Не указан режим транзакции"
                    Вот код:

                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
                    9
                    10
                    11
                    12
                    13
                    14
                    15
                    16
                    17
                    18
                    19
                    20
                    21
                    
                    function killStopOrders(sec_code)
                    	tryToSendTransaction2(class_code, sec_code, isBuy, price)
                     
                    end
                     
                    function tryToSendTransaction2(class_code, sec_code, isBuy, price)
                    	t = {
                    		["ACCOUNT"] = DEPO_ACCOUNT,
                    		["SECCODE"] = sec_code,
                    		["ACTION"] = "KILL_STOP_ORDER",
                    		["CLASSCODE"] = class_code,
                    		["CLIENT_CODE"] = CLIENT_CODE,
                    		["STOP_ORDER_KEY"] = tostring(orderNum),
                    		["TRANS_ID"] = "3"
                    	}
                    	local res = sendTransaction(t)
                    	if res ~= '' then
                    		WriteToLog('Транзакцию не удалось отправить1'..res, 3, true)
                    	end
                     
                    end
                    1. Вот такие поля только нужны:

                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      
                      local Transaction = {
                            ["TRANS_ID"]            = tostring(trans_id),
                            ["CLASSCODE"]           = class_code,
                            ["SECCODE"]             = sec_code,
                            ["ACTION"]              = "KILL_STOP_ORDER",                                    -- Тип заявки 
                            ["STOP_ORDER_KEY"]      = tostring(stop_order_num)                              -- Номер стоп-заявки, снимаемой из торговой системы
                         }