Андрей К
Андрей К личный блог
16 февраля 2016, 01:13

Изучаю FIX протокол с нуля. Подводим итоги первой части. Первая борьба за миллисекунды.

Начало положено тут
Продолжение тут

Вступление

     Разработка обертки протокола, только на первый взгляд, кажется простым. Нахрапом такую задачу не взять. Тут, как я уже говорил, важно посидеть с кружкой чая, полистать документацию, построить различные схемы, структуры. На основе этого, разработать логику обертки, иерархию классов и тд. Разберем иерархию команд протокола. Для анализа была взята документация самой биржи.

Теоретически аспекты. Разложим немного по полочкам.

     Все сообщения протокола можно разложить на несколько тем. Я начну с первой группы:
  1. Сообщения для поддержания связи.
  • Logon; Тип=A; Сообщение для инициализации сессии. Грубо говоря для подключения к серверу
  • Logout; Тип=5; Сообщение для завершения сессии. Сообщаем серверу о прекращении связи
  • Hearbeat; Тип=0; Сообщение для поддержания связи. 
  • Request; Тип=1; Сообщение для поддержания связи. Запрос второй стороны, жива ли первая
  • Reject; Тип=3; Сообщение об ошибке. Получаем его, если мы не правильно оформили свое сообщение
  • Resend Request; Тип=2; Повторный запрос сообщений, в случае утери. Задается интервал номеров сообщений.
  • Sequence Reset; Тип=4; Используется для сброса номеров сообщений. 
     На этом наверное буду заканчивать первую часть описания. В нее вошли функции, отвечающие исключительно за связь между клиентом и сервером. Давайте посмотрим теперь немного практики. И еще почертим.
Когда мы устанавливаем подключение к серверу, мы должны передать ему три параметра:
  • метод шифрования (0 по умолчанию)
  • интервал в секундах. Этот параметр указывает с каким интервалом мы будем обмениваться сообщениями поддержания связи (Hearbeat и Request)
  • флаг сброса счетчика сообщений. (Y — сбросит на ноль).
При успешной операции, сервер нам отвечает тем же.
Изучаю FIX протокол с нуля. Подводим итоги первой части. Первая борьба за миллисекунды.
     Далее, сервер с указанной периодичностью, начнет слать в наш адрес сообщения запросы подтверждения связи. Я написал быстренько небольшое приложение, которое поможет показать на практике этот процесс. Я сделал таймер, который каждую секунду проверяет, не пришло ли нам что нибудь на сокет. 
Тут я моделирую, что мы глухи
Изучаю FIX протокол с нуля. Подводим итоги первой части. Первая борьба за миллисекунды.
А тут, я ему отвечаю на его запросы
Изучаю FIX протокол с нуля. Подводим итоги первой части. Первая борьба за миллисекунды.  В принципе, вот и все общение. Далее, с опытом, придется еще отработать механизмы обрыва связи и механизм потери сообщений. 

Боевой кодинг. Начало борьбы за миллисекунды

     С получением опыта пришлось существенно доработать классы. Где то появилась избыточность кода. Все идет на минимизацию расчетов.
К примеру. Приведу старые скрины кода из первой части. В каждом классе у меня были 2 метода:
  • ToString() — создавал на основе класса строку соответствующего сообщения в формате FIX для передачи на сервер
  • GetMessageSize() — подсчет длины строки для формирования заголовка сообщения

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

     Для этого я пошел на избыточность. Я создал в каждом классе еще по два поля, которые заполнялись при первом расчете.
Изучаю FIX протокол с нуля. Подводим итоги первой части. Первая борьба за миллисекунды.
И уже стал использовать их при построении сообщения.
Изучаю FIX протокол с нуля. Подводим итоги первой части. Первая борьба за миллисекунды.

Вроде как мелочь, да и переписывать классы пришлось часа 4. Но такой ход позволил скосить в среднем до 10 миллисекунд на операцию и теперь на отправку и получения ответа уходит стабильно менее 90мл сек (раньше было около 100 постоянно и выше). Мелочь, а приятно.
На этом пока все. Теперь предстоит долгий путь создания кода под торговые операции.


51 Комментарий
    • Aberkromb Garell
      16 февраля 2016, 09:21
      Андрей К, это было бы оч круто
  • собачки в самолёте
    16 февраля 2016, 01:28
    Очень интересный топик плюс однозначно
  • Александр Ф.
    16 февраля 2016, 01:47
    Глубоко  раскрыл молодец
  • Niktesla (бывш. Бабёр-Енот)
    16 февраля 2016, 02:00
    100 мс? это с пингом до биржи туда/обратно?
    10 мс сыкономить на каком-то методе при формировании сообщения??? а вы точно милли- с микро- секундами не путаете?
      • _landy
        16 февраля 2016, 09:53
        Андрей К, время, затраченное процессором на твой код, должно измеряться даже не микро-, а наносекундами, ибо микросекундами измеряются сетевые задержки. А теперь прикинь — сможешь ты ускорить свой код на пять порядков в текущей парадигме с классами на каждую несчастную подстроку? Ты когда текстовый редактор пишешь — каждую букву тоже отдельным классом со своим интерфейсом описываешь?
    • Niktesla (бывш. Бабёр-Енот)
      16 февраля 2016, 02:21
      Андрей К, не, круто на самом деле... 
      А мне чет показалось сначала что вы локально к эмулятору какому-то конектитесь...)
  • Игорь
    16 февраля 2016, 08:37

    Я одно не пойму, зачем вы это делаете, когда есть открытый quickfixn.org/ Не проще ли присоединиться к проекту и его оптимизировать если это потребуется?

  • Vadim S
    16 февраля 2016, 09:17
    Молодец. Продолжай дальше.
  • Михаил Иванов
    16 февраля 2016, 11:01
    весьма сомневаюсь что 10 мс получились в результате такого примитивного рефакторинга. ну если вы конечно не миллиардами эти сообщения клепаете. и для «боевого кодинга» переходите на с++ или вообще на си, там будет побыстрее.
      • Евгений
        16 февраля 2016, 11:13
        Андрей К, на фиксе борьба идет за микросекунды. Миллисекунды даже скрипты на луа выдают.

        Согласен с выше написанным — сильное сомнение в применимости вышенаписанного в боевых торгах.
          • Евгений
            16 февраля 2016, 11:43
            Андрей К, ваше сообщение больше похоже на проплаченного автора с хабры. Пишите много, разумоного мало. Задача — набрать кючевые слова. Может я и не прав, но все именно так и выглядит.
              • Евгений
                16 февраля 2016, 11:52
                Андрей К, ваш ответ как раз выдает проф писателя за деньги.

                Согласитесь, странно это все. Зарегистрированы 2 года назад. Ничего не писали. Теперь начали, и сразу в стиле платных писателей — слов много, смысла мало.

                Пишите, конечно. Раз раскрутка сайта идет.
                  • Евгений
                    16 февраля 2016, 12:02
                    Андрей К, где вы еще пишите?
      • Михаил Иванов
        16 февраля 2016, 11:37
        Андрей К, а как проводили замеры? я не троллю, мне весьма интересно откуда могла получится такая штуковина. если я вас правильно понял, то раньше вы три раза составляли строку и подсчитывали ее длину (строка на предпоследнем скриншоте). строка состоит из двух Int.ToString и одного bool.ToString, к которым добавлены некоторые Tags. Эта работа займет скорее микросекунды. Откуда же взяться целым 10мс?
          • Михаил Иванов
            16 февраля 2016, 12:46
            Андрей К, понятно. Вот такой код делается за 19 мс. комп — скромный ноутбук с i5. И все же, откуда у вас взялось 10 мс?

             DateTime n1 = DateTime.Now;

                        int one = 1;
                        int two = 551;
                        bool yes = true;

                        for (int i = 0; i < 10000; i ++)
                        {

                            string res = String.Format("{0}={1}\u0001{2}={3}\u0001{4}={5}\u0001",
                                1,
                                one.ToString(),
                                2,
                                two.ToString(),
                                3,
                                yes.ToString()
                                );
                            int len = res.Length;
                        }

                        TimeSpan n2 = DateTime.Now — n1;
                        Console.WriteLine(n2.Milliseconds.ToString());
                        Console.ReadKey();
              • Михаил Иванов
                16 февраля 2016, 12:53
                Андрей К, посмотрите пожалуйста. вполне возможно вы и увеличили скорость работы, но явно не понимаете, как именно ;)
      • _landy
        17 февраля 2016, 11:16
        Андрей К, несмотря на твое мнение — Delphi прекрасно справляется с этой задачей, укладываясь в те самые наносекунды…
          • _landy
            17 февраля 2016, 11:33
            Андрей К, я тоже, поэтому и говорю, что именно семерка как раз показывает недостижимую для последующих версий компактность и эффективность кода.

            PS: Самый главный тормоз в твоем коде - String.Format, тебе нужно уйти от него, формируя строку обычными конкатенациями.
  • crazyFakir
    16 февраля 2016, 21:21
  • crazyFakir
    16 февраля 2016, 22:12
    как ты на винде собрался лоулатенсиничать та?

    прям беда :)
      • crazyFakir
        17 февраля 2016, 14:02
        Андрей К,  странные подходы, тк писать на с++
        то далеко не быдлокодить на шарпе
        ну а джава к шарпу ближе как никто и опля — линукс в работе прям щас :)
          • crazyFakir
            17 февраля 2016, 14:44
            Андрей К, ответ вполне ламерский, ткчт — нет вопросов :)
              • crazyFakir
                17 февраля 2016, 15:25
                Андрей К, 
                будем как есть.

                ну дык почитай про шедулер виндов и не теряй время зря

                экономить мс на винде это как на спининг вместо лески надеть льняную веревку — БЕССМЫСЛЕННО :)
                делятся именно на c#/c
                писали такие же кодеры как  и ты… вы будете явно  рады встрече :)

                пс: говорю по-доброму, без издевок. просто треп :)
                  • crazyFakir
                    17 февраля 2016, 16:21
                    Андрей К, да упаси бес советовать, просто на досуге грю, что нет смысла ловить мс на винде. это будет не медленно, а себе на уме.

                    линукс более предсказуем и имеет какой-то инструментарий для более-менее понятного времени отклика системы.

                    для более жесткого реал-тайма нужно что-то типа qnx видимо, сам не делал.

                    просто если уж шагать в пром. программировние, то от джавы и линукса. это хотя бы понятные шаги в правильном напрямку.

                    иначе получиться всеравно эС-шарп — т.е. ни то ни сё, а времени сожрет кучу. имхо :)

                    что до работы, то пройдя от джуниора лучше ее искать на западе нынче, а там сильно больше джавы требуется.
                    имхо-2. :)
                      • crazyFakir
                        17 февраля 2016, 17:20
                        Андрей К, ну уж прям не все, но многие. :)
                  • crazyFakir
                    17 февраля 2016, 16:27
                    Андрей К, если учесть что FIX это вполне себе суръезно, то да — джава на линухе будет более правильно.

                    всмысле нет разниц с С# почти по сути за редким, а вот кроссплатформеность у джавы сильно лучше.

                    скорости примерно равны будут на такой задаче.

                    джава + линукс > вин+шарп // стопудова :)
  • crazyFakir
    17 февраля 2016, 16:30
    еще тынц

    старт очень простой
  • SMT
    02 мая 2016, 13:15
    спасибо!!!

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн