Хочу поделиться новостью о предновогоднем обновлении библиотеки QuikSharp.
Обновление привнесло ряд новых функций, а также демонстрационное приложение на WinForm, о котором так часто просили пользователи.
Берем тут:
https://github.com/finsight/QuikSharp
QuikSharp — это динамически подключаемая библиотека, для обеспечения связи ваших роботов, написанных на C#, с терминалом Quik.
QuikSharp — это «Open source-проект», который развивается благодаря участию других пользователей. Отдельный «респект» хочу выразить автору проекта, т.к. это именно то, что я долго искал когда понял, что уперся в некоторые существенные ограничения QLua.
Легче всего с этой библиотекой будет освоиться тем, что уже пробовал реализовать свои торговые стратегии на QLua, т.к. большинство функций взяты именно из QLua. Но по сравнению с QLua, мы получаем значительно большие возможности, в том числе по производительности. Когда у меня количество одновременно запущенных роботов на QLua превысило десяток, то я столкнулся с очень большими проблемами производительности. Квик стал жрать память в каких-то неимоверных объемах, а загрузка ЦП выросла до 80% (в спокойное время). Перейдя на QuikSharp (правда, перед этим пришлось заняться изучением C#) я одномоментно решил большинство проблем производительности, получил удобный инструмент для создания пользовательских интерфейсов, а также более удобное средство разработки самих роботов. Сейчас у меня одновременно крутятся в реальном времени более 4-х десятков роботов (если считать отдельным роботом сочетание ТС и конкретного инструмента), и при этом я не испытываю НИКАКИХ проблем с производительностью (терминал и роботы крутятся на ноутбуке).
Чтобы начать пользоваться данной библиотекой, необходимо скачать проект по указанной ранее ссылке и скомпилировать его (рекомендую использовать Visual Studio не ниже 2015).
После этого, из папки «bin» необходимо скопировать папку «lua» со всем ее содержимым, туда, где у вас обычно лежат роботы на QLua.
В терминале Квик в диалоговом окне «Lua скрипты...», необходимо добавить файл QuikSharp.lua из ранее скопированной папки «lua» и запустить этот скрипт.
Возможно, потребуется сначала установить LuaForWindows.
Далее, в папке «Examples\QuikSharpDemo\bin\Release» находим exe`шник, и запускаем его. Остальное должно быть понятно интуитивно.
Данная демка не является роботом, а лишь демонстрирует простейшие примеры работы с библиотекой, что в сочетании с открытостью исходников, позволяет без особого труда научиться использовать эту библиотеку в своих целях.
Возможно, позже будет реализован и какой-нибудь простейший робот, в качестве наглядного примера (может я сделаю, а может кто-нибудь еще)
Мне ваши оба проекты нравятся. А только за то, чтобы вы лучше делали.
Оса сырая и непонятная. Может ваш проект (проект, в который вы вносите посильный вклад) подстегнет коллег сделать человеческое.
— мне нужен инструмент технического анализа, работающий в рилтайме. Так я нахожу свои стратегии.
— Мне НЕ нужна сверх-высокая скорость отклика, т.к. на фондовой секции у меня работают краткосрочно-среднесрочные системы, а на срочке — краткосрочные спекуляции (в среднем пара дней в позиции), для которых закладываемого проскальзывания в 5 пунктов пока хватает «за глаза».
— Мне нежелательно лишнее увеличение «костов» на содержание инфраструктуры (квик мне обходится бесплатно)
— Я НЕ являюсь профессиональным программистом
— До QS я писал роботов на QPile, а потом на QLua. Соответственно, после QLua, переход на C#, с использованием QS, практически не составил больших сложностей (не считая необходимости пройти курс обучения языку, который я тупо нашел в Ютубе)
— Я получил в свое распоряжение, совершенно бесплатно, удобную для меня библиотеку-коннектор. Отплатить автору той же монетой для меня не проблема. А если этот проект поддержат больше пользователей, то возможно я еще и что-то полезное для себя приобрету (имеются в виду знания)
Сопоставив описанные выше факторы, для меня выбор был очевиден.
Питон более популярен среди трейдеров. Си больше среди программистов. Вы программист или трейдер? :-)
Что касается классификации (программист или трейдер), то мне трудно ответить однозначно. С одной стороны — те QPile, QLua, C# я изучал только ради того, чтобы роботизировать торговлю, т.к. не имею возможности постоянно сидеть за терминалом (иногда, терминал вижу 2-3 раза в день, где 1 раз — это утренний процесс запуска).
С другой стороны, жизнь так сложилась, что я всюду старался автоматизировать различные нудные повторяющиеся процессы (в училище, в армии, на работе), чтобы высвободить свое время. Как следствие — пришлось изучать программирование, и сейчас этот процесс мне тоже нравится в некоторой степени.
Пока писал, пришел к такому выводу: В моем случае можно сказать, что эффективный трейдинг без программирования невозможен. Взять тот же анализ сделок: Мои кучки роботов генерируют массу логов, и для того, чтобы с ними было удобно работать, мне пришлось написать собственную «читалку логов», с механизмом анализа стратегий.
Мое мнение, вы сильно обеспокоены экзекьюшеном и кодированием, чем поиском альфы. И это плохо. Но это ваше решение, и к чему оно приведет будет известно только вам.
Быстрые решения делаются совершенно не так.
Луа сам по себе легкое порно, а "Луа внутри Квик" — уже хардкор.
Авторам библиотеки QuikSharp хотелось бы пожелать больше тестировать её на нормальных боевых задачах.При нормальном потоке тиковых данных.
Prophetic, =) разумеется, я это проделал. И тесты производительности и всё прочее. Очень сыро. Видно, что именно на серьёзных промышленных задачах эту либу мало используют.
И ещё Вы путаете "производительность отдельной операции в одном синтетическом тесте" и "общую стабильность связки под нагрузкой".
В Plaza2 CGate все эти данные есть.
(в скобках это время ответа луа, до скобок время получения этого ответа в C#)
Похоже или нет к сожалению не знаю, не могу понять где это происходит. Но идею Вы дали, буду пробовать, разбираться. Но врятли сделаю это быстрее Вас.
PavelS, 50 секунд даже Питон наверное висеть не будет, вероятно дело не (только) в GC — так долго мусор не может собираться при любом раскладе. Учитывая, что вся библиотека — это по сути TCP сокет + (де)сериализация, не могу с ходу придумать где я что-то еще мог пропустить. Рад слышать, что стало лучше — надеюсь Вам не показалось :)
Пишите, пожалуйста, на ГитХаб все такие проблемы, если они будут повторятся — мы их поправим!
github.com/finsight/QuikSharp/issues/89#issue-197999438
Подвисает все в QuikService, поток callbackTask. А конкретно вот тут: var lineOrCancelledTask = await Task.WhenAny(readLineTask, _cancelledTcs.Task).ConfigureAwait(false);
Подвисает не постоянно в среднем на 2-5 секунд, но может доходить до нескольких минут.
Подскажите почему такое может происходить, как можно это исправить?
Было бы неплохо сделать логирование на стороне Lua и в этом месте и посмотреть, где именно зависает. То есть если Lua скрипт вызывает нужный метод вовремя, то нужно разбираться в сокетах. Иначе проблема может быть в самом Квике или к коде Луа. Скажите, пакеты все в итоге приходят или некоторые теряются?
Сильно подвисать начинает после одного-двух дней непрерывной работы, колбеки начинают тормозить на 2-5 минут каждый, тоесть если это началось, то так и будет работать пока не перезагрузишь. При этом примерно в 7 раз возрастает объем используемой опер.памяти и нагрузка на ЦП. Квик при этом часто тоже подвисает.
PavelS, есть одна мысль — вы случайно не используете блокирующие методы слишком часто? (по сравнению с асинхронными). Есть такая тема как ThreadPool starvation: https://stackoverflow.com/questions/7600774/threadpool-not-starting-new-thread-instantly. Когда все потоки ThreadPool заняты, то пул ждет одну секунду перед тем, как добавить новый поток. Если у вас в коде много блокирующих методов, то потоки в пуле могут закончится и пул будет ждать секунду. При этом если есть очередь из тасков, то последний может ждать довольно долго.
Q# асинхронный, проверье не используете ли Вы везде Task.Result или Task.Wait() вместо await...
и таких запросов около 10 на весь код, 6 из них работают в цикле в отдельном потоке с паузой 10 мс (это загрузка параметров по инструментам и стаканов, а также графиков). 4 это отправка транзакций например res = _quik.Orders.CreateOrder(order_new).Result;
Больше нигде ничего не жду, кроме этих запросов.
if (lineOrCancelledTask == _cancelledTcs.Task) { break; }
Что делает этот код, зачем он нужен?
Второй день работаю без него, пока все нормально. Только начали наблюдаться задержки 2-10 сек в строке var readLineTask = reader.ReadLineAsync(); но не так часто.
Гружу путем подписки на получение соответствующих таблиц из квика. Вообще-то, в демке это как раз есть. Для того ее и делал.
1. Не засекал. И для меня это момент не критичен, т.к. мне не приходится постоянно выполнять данную операцию. В своих системах для пакета роботов, первичные таблицы свечей робот получает на старте приложения (с учетом обработки почти трех десятков бумаг, этот процесс действительно занимает приличное количество времени — где-то около минуты). Но далее все полученные таблицы записываются в объединенное хранилище, и каждая стратегия не получает данные заново, а просто берет их из хранилища. Обновление таблиц происходит по колбэкам, путем добавления новой свечи в конец соответствующей таблицы. Т.к. я все же не являюсь автором проекта, то даже не задумывался над анализом проблем обработки больших пакетов данных (у меня банально знаний не хватит)
2. Ошибок быть не должно, перед тем как отправить PR я ВСЕГДА компилирую проект и запускаю свои «боевые» приложения на свежей версии библиотеки. То же самое касается демки. Может напишите в каком месте у Вас ошибка вылезла (ведь вряд ли ошибка возникла после слияния)?
3. Собственно и свечки и таблицы заявок и таблицы сделок у меня хранятся в отдельных хранилищах, асинхронно обновляющихся по колбэкам. Если же вы пытаетесь найти плохую оптимизацию в демо-приложении, то это занятие бесполезное. Вполне очевидно, что оно не образец для подражания, и было создано только потому, что многие пользователи, которые пытались познакомиться с библиотекой, просили реальные примеры работы.
У меня все реализовано сильно иначе. Если грубо, то: Есть оболочка, содержащая в себе хранилище, и основные управляющие функции. Есть кучка различных торговых стратегий, каждая из которых упакована в отдельную DLL. Конкретный робот представляет из себя сочетание выбранной ТС из доступных в папке и тикера инструмента. Соответственно, у каждого такого сочетания свои файлы настроек параметров робота.
2. Пишу с телефона, поэтому не могу точно указать на ошибку. Но если примерно то Вы пытаетесь получить некоторые поля таблици, которые не описаны в библиотеке квикшарп. И еще так как нет скомпилированной библиотеке квик шарп, то слетают ссылки в Вашем демо, пришлось собирать библиотеку, и заново указывать ссылки
1. «Вы пытаетесь получить некоторые поля таблици, которые не описаны в библиотеке квикшарп». Если читать это «в лоб», то у меня проект просто не работал бы, а это не так (сейчас попробую скачать прямо по той ссылке проект в отдельную папку и еще раз попробовать скомпилировать). Единственное, что приходит в голову, это то, что я не стал преобразовывать форматы даты, при выводе таблиц. Но это я видел, и просто в соответствующей колонке таблицы, вместо нужного значения выводится всякая белиберда, что не мешает работе демонстрационного приложения (мы ведь не обрабатываем нигде эти даты потом).
2. На счет ссылок — надо подумать. Понятно, что я много раз компилировал библиотеку и лишь потом подключил демку к решению. Возможно, достаточно просто провести повторную компиляцию, без внесения изменений, но это надо проверять. Или надо искать какой-то другой способ указания ссылок, но тут у меня знаний может и не хватить.
Строка: firmID = quik.Class.GetClassInfo(classCode).Result.firmid;
Должна была быть написана так: firmID = quik.Class.GetClassInfo(classCode).Result.FirmId;
Ошибку исправил и перезалил в репозиторий. Спасибо, что заметили.
И кстати: с сылками каких-либо проблем не возникло. Поэтому, тут я даже не представляю где искать возникшую у Вас проблему.
OnParam не пользуюсь, не получается сделать это без проблем, с этим колбеком приходит код и клас инструмента по которому были изменения, что Вы с ними делаете дальше? Если я обращаюсь обратно к квику за параметрами по данный бумаге (из этого же потока или из другого, не важно), то очень скоро поток который обращается к квику зависнет.
Если обобщенно и упрощенно, то как я писал ранее, у меня в хранилище есть таблица заявок. Если робот выдал сигнал на выставление заявки, то отдельно фиксируется номер этой заявки, и далее в каждом цикле проверяется состояние этой заявки. Если заявка в результате была отменена (я задаю время ее жизни), забываем про заявку и работаем «с нуля». Если заявка перестала быть активной и остаток к исполнению не равен стартовому количеству в заявке, то лезем в таблицу сделок (которая также хранится в хранилище), и по номеру заявки находим все сделки. Далее высчитываем среднюю цену и продолжаем обработку согласно логике робота.
запущен или нет QuikSharp.lua значения не имеет.
Чтото-не так с дллками, трудно понять.
Может подскажете, что где проверить?
Спасибо.
Еще есть проблемы с сепаратором в Demo.
по поводу «Events.OnConnectedToQuikCall(_responsePort)» — что-то странное. вроде больше ни у кого проблем в этом месте нет, но вероятно лучше задать вопрос тут: https://github.com/finsight/QuikSharp/issues
А что за проблемы с сепаратором у Вас возникли?
По колбеку ошибка не постоянная, но ловил ее уже несколько раз.
А по сепаратору, Вы насильно даете ему "," а если у кого нибудь в региональных стандартах разделитель стоит "." то будет исключение.
Поэтому если уж так нужно менять разделитель то лучше заменить System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator[0];
на System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]; тогда он берет его из локальных региональных настроек
Это я опытным путем вычислил)) у меня виндовс с русской локализацией а разделитель стоит точка и эта команда выдает все равно запятую.