Последние несколько месяцев время от времени начинал времени ломать голову над одной задачкой.
Суть в следующем.
Я сделал скрипт на питоне, на основе торговых данных пишет заявки в tri файл квиковский.
Чтоб заявку создать нужно принять решение на основе каких то данных из таблиц квика (например исполнилась какая то ранняя заявка, или банально цена дошла до нужного уровня, и т.п.)
Данные из таблиц квика, как известно, встроенными методами можно экспортировать через ДДЕ сервер, или в базы данных через ODBC.
То есть — для этого не надо обладать знаниями по программированию, это простые, очевидные способы, доступные всем, у кого установлен квик.
Я выбрал способ по ODBC, и пользуюсь им.
Связка работает стабильно, ничего не рушится, правда пару раз за несколько месяцев зависал сам квик из за того, что кончалась оперативная память (сервер слабенький у меня).
Но у такой связки есть слабое место, приходится в питоне запускать таймер, по кjторому питон опрашивает базу данных.
Это не логично, робот должен совершать какие то действия в ответ на событие, а не просто молотить запросы в БД.
В итоге, путем гугления выяснилось что существуют в теории еще два пособа экспорта данных из квика.
Первый способ — это экспорт в библиотеку dll trans2quik — библиотека позволяет как импортировать заявки в квик, так и экспортировать заявки и сделки из квика.
С импортом заявок я разобрался (кому интересно, по простому могу объяснить), а вот по поводу экспорта так и не понял, суть в том, что сделки приходят в бибдиотеку dll а оттуда уже в скрипт питона. Подписаться на отправку удается, а вот как получать сами сделки в переменные, я так и не понял.
второй способ, использование сокет соединений. Общий смысл в том, что в локальной сети (в данном случае в рамках одного компьютера), создается сокет сервер и сокет клиент, и клиент может отправлять что либо серверу.
В итоге идея в том, чтобы создать на питоне сокет сервер, а на языке LUA встроенном в квик, создать клиент, который будет отправлять все нужные события в робота на питоне.
На питоне очень много понятной для нубов инфы в интернете, все просто найти. Сокет библиотеку для питона даже устанавливать не надо, она уже встроена.
А вот с LUA это просто капец насчет инфы, для тех кто начинает с нуля, разобраться не возможно. Там какой то междусобойчик, люди чего то там знают уже, какие то вопросы задают, сами себе отвечают.
В итоге методом простого тыканья пальцем в небо удалось найти старую библиотеку Сокет для луа, также пример кода на LUA, и создать наконец рабочий клиент.
Как это все я запустил?
Из библиотеки с архивом сокета кинул все файлы в корневой каталог квика, не заменял только основной файл lua5.1.exe (оставил родной)
туда же положил и файл со скриптом клиента, перед тем как запускать клиент, само собой надо запустить сервер на питоне,
и после этого все сразу заработало на 32 разрядной версии квика.
Кому надо, могу прислать ту библиотеку сокет, которая у меня заработала, а также примеры скриптов сервера и клиента
проблема в том, что на 64 разрядной версии не запускается, пишет ошибку
error loading module 'socket.core' from file 'C:\QUIK_VTB24\socket\core.dll':
%1 не является приложением Win32.
пока времени нет нагуглить решение, может кто знает как наладить?
Update:
библиотеку 64 нашел, все заработало с сокетами
Она сразу нагуливается.
А вот по поводу собрать из исходников, пока для меня это звучит, как абракадабра
https://github.com/Enfernuz/quik-lua-rpc
Пример клиента на python для quik-lua-rpc JSON?
иллюстрация, куда можно это дальше применить
Не стоит искать сокеты для Луа.
Уходим из Луа в С++ DLL, а в ДЛЛ уже делаем сокет(ы) клиент(ы) на С++. Экземплы сокетов на С++ есть в инете. Куча.
Что значит уходить в ДЛЛ?
Как вообще в С++ что то запилить? Там какая то среда разработки визуал студио просто сумашедшая, гигабайты установочных файлов.
Вот если просто по ДЛЛ, можете ответить совсем, совсем для тупых чайников на такой вопрос
мне дали библиотеку для работы с trans2quik.dll
я оттуда могу вызывать разные функции,
в частности
функции для соединения и отправки транзакций работают четко, например
def send_async_transaction(transaction):
lpstTransactionString = LPCSTR(transaction.encode())
return SEND_ASYNC_TRANSACTION(lpstTransactionString)
подставляю вместо transaction строку в кавычках с параметрами заявки, и вуаля — заявка в квике.
Все четко.
А вот такая функция оттуда
def start_orders(callback):
c = ORDER_STATUS_CALLBACK(callback)
start_orders.callback = c
return START_ORDERS©
у меня толком не работает, так как я во первых не понимаю, что точно передавать в качестве callback, и как передавать,
а во вторых, как и куда в итоге потом получать сами заявки, куда они записываются?
в самой библиотеке есть внизу всякие переменные типа
order_qty = ORDER_QTY = _declare_method(TRANS2QUIK.TRANS2QUIK_ORDER_QTY, c_long, c_long)
# long TRANS2QUIK_ORDER_DATE(long nOrderDescriptor)
order_date = ORDER_DATE = _declare_method(TRANS2QUIK.TRANS2QUIK_ORDER_DATE, c_long, c_long)
предполагаю что эти order_date и прочее и есть каллбаки,
пробовал их подставлять в функцию
trans2=trans2quik.start_orders(trans2quik.order_qty)
если заявкок по нужном инструменту нет то пишет none
а если есть заявки то
File "_ctypes/callbacks.c", line 232, in 'calling callback function'
TypeError: this function takes 1 argument (11 given)
и ожидает ввода чего то. Типа я передал один аргумент, а надо 11 передать??? Каких 11 и как передать?
И правильно ли я понимаю что потом в переменную trans2 наконец запишутся эти так ожидаемые заявки?
По идее нафиг мне эти сокеты, если можно через ДЛЛ все получить, но вот тыкаюсь как слепой котенок, задаю вопросы, а мне дают ответы типа Вашего, да, все можно сделать, а как сделать нигде не написано ((((
Я же не программист, я торгаш, мне это просто как инструмент надо, но освоить это для меня явно сложнее, чем торговать
Это надо хотя бы пару часов с вами посидеть — поразбираться.
ЗЫ Посмотрел профиль, далековато вы.
может в виде какого то списка, просто через запятую пробовал, не получается, пробовал в спискок заранее записать, а потом его передать, тоже ругается
Никак!
Коллбэки — это события терминала. Вы должны определить эти функции в своей программе строго в соответствии с их шаблонами.
При вызове их из терминала вы можете использовать переданные вам аргументы в определенной вами функции, и также вызывать из своей коллбэк функции некоторый ограниченный набор функций-запросов к терминалу. Сами эти функции-запросы определены в документации.
У меня есть библиотека, там есть две функции.
Первая это подписка на отправку в dll из квика данных например по какой то бумаге.
Эта функция работает.
Я передаю в качестве аргументов класс и код бумаги.
Далее я вызываю из этой библиотеки другую функцию, о кторой я писал ранее. Эта функция непосредственно из квика принимает эти заявки и должна передать в мой скрипт питона.
И она тоже работает.
У нее единственный аргумент.
Когда передашь туда произвольную строку, скрипт ругается, что такая строка не определена.
Если передает туда, то что что привел в пример ранее, функция выполняется, причем столько раз, сколько к меня по факту заявок было по этой бумаге в квик.
Но каждый раз выводит сообщение об ошибке.
Вот скрин из документации. Там пример.
Проблема в том, что в примере в аргументах этой функции пусто .
Или Вы имеете в виду другую документацию?
File "_ctypes/callbacks.c", line 232, in 'calling callback function'
TypeError: this function takes 1 argument (11 given)
и ожидает ввода чего то. Типа я передал один аргумент, а надо 11 передать??? Каких 11 и как передать?
Эта ошибка должна означать, что я передаю 11 аргументов , а принимается только один.
Сейчас только дошло.
1. void __stdcall TRADE_STATUS_CALLBACK (long nMode, double dNumber, double dOrderNumber, LPCTSTR ClassCode, LPCTSTR SecCode, double dPrice, long nQty, double dValue, long nIsSell, long nTradeDescriptor)
2. void __stdcall ORDER_STATUS_CALLBACK(long nMode, DWORD dwTransID, double dNumber, LPCTSTR ClassCode, LPCTSTR SecCode, double dPrice, long nBalance, double dValue, long nIsSell, long nStatus, long nOrderDescriptor)
и никак иначе (это в С++). Внутреннее наполнение функции вы делаете сами. Функции вызываются непосредственно из терминала, не вами. Вы туда ничего не передаете, и не можете передать.
Или уже я что-то не понимаю. Мы же про коллбэки говорим?
TRANS2QUIK_START_ORDERS
еще раз посмотрел, вот что написано в доках
Функция запускает процесс получения заявок по классам и инструментам, определенных функцией TRANS2QUIK_SUBSCRIBE_ORDERS.
void __stdcall TRANS2QUIK_START_ORDERS (TRANS2QUIK_ORDER_STATUS_CALLBACK pfnOrderStatusCallback)
то есть у нее в аргументах сидит как раз то что Вы написали, то есть другая функция
как мне все это передать с помощью питона, я не понимаю.
Скрипт который кто то до меня написал, там что то есть, но так как я не понимаю, что именно писать в аргументах, то у меня это и не работает
вот кусок кода, который об этом
# void TRANS2QUIK_ORDER_STATUS_CALLBACK(
# long nMode,
# DWORD dwTransID,
# double dNumber,
# LPSTR lpstrClassCode,
# LPSTR lpstrSecCode,
# double dPrice,
# long nBalance,
# double dValue,
# long nIsSell,
# long nStatus,
# long nOrderDescriptor
# )
ORDER_STATUS_CALLBACK = \
WINFUNCTYPE(c_void, c_long, DWORD, c_double, LPSTR, LPSTR,
c_double, c_long, c_double, c_long, c_long, c_long)
# void TRANS2QUIK_START_ORDERS(
# TRANS2QUIK_ORDER_STATUS_CALLBACK pfnOrderStatusCallback
# )
START_ORDERS = _declare_method(
TRANS2QUIK.TRANS2QUIK_START_ORDERS, c_void,
ORDER_STATUS_CALLBACK
)
#----------------------------------------------------------------------
def start_orders(callback):
c = ORDER_STATUS_CALLBACK(callback)
start_orders.callback = c
return START_ORDERS©
Как их конкретно использовать в Питон? — Понятия не имею. Мало информации. В этом супе чего-то не хватает.)
Пока не разберетесь, этот код лучше вообще руками не трогать, и скорее всего, вообще менять не придется, если в нем нет ошибок.
ЗЫ В общем, ясно, это PyQuik. Проект не обновлялся с 12 года, если не ошибаюсь. Не факт, что он будет работать без редактирования на современном Питон. Хотя, и не факт, что не будет.
Схемы сообщений JSON
В общих чертах, формат сообщений такой:
Запрос:
Ответ:
Решение :
1. добавить в связку коммуникатор 32бит/64бит (не занимался).
2. перекомпилировать библиотеку под 64 бита через… VS14+ (пробовал через MinGW и встроенные скрипты компиляции — у меня не вышло)
Ответ: Готовое решение: с помощью https://github.com/Enfernuz/quik-lua-rpc
Можно сделать триггер, что при вставке-изменении значений в конкретной таблице что-то делать, кажется там можно дергать стороннее приложение даже в рамках этой функциональности.
Как бы есть механизмы вообще без ODBC экспорта, вообще я так понимаю, самый популярный, чем все пользуются, это trans2quik.dll наверное надо копать дальше сюда, его можно одновременно и для отправки заявок, и для получения данных использовать
Поэтому и не думал изучать другие терминалы с их апи
(Возможно через другого брокера/др. софт решить вашу проблему будет гораздо проще)
Например — тарифы на фонде, плечи на фонде, техподдержка, стабильность работы терминала, отчеты, мелкий шрифт регламентов, визуальная экономическая надежность брокера и можно еще перечислять ньюансы.
Экспериментировать с другими брокерами может появиться желание, только если чем то начнет не устраивать втб
trans2quik – это официальное документированное API для взаимодействия внешних приложений с торговым терминалом QUIK. Оно позволяет из внешних программ выполнять различные операции, в основном это отсылка транзакций, получение информации о заявках и сделках. Рыночная информация через это API не доступна
Технически данное API устроено следующим образом: разработчиками QUIK поставляется DLL-библиотека, которую внешнее приложение загружает и вызывает из нее доступные интерфейсные функции.
На примем данных Автор срипта не дописал срипт.
Там он функцию написал, только на подписку на данные, но она не работает, я в другом срипте посмотрел, чуток переделал, она тоже заработала.
Но к сожалению для функции TRANS2QUIK_START_ORDERS (и TRADES ) он код вообще не написал, а я не понимаю, как написать, чтоб эта функция исполнялась.
Короче говоря, у меня такой же функционал как и здесь тоже есть, и тоже на прием не работает, только на отправку
Может служить примером для написания такого же на python
Функции для работы с транзакциями через API
https://euvgub.github.io/quik_user_manual/ch6_11.html
Получение информации о заявках и сделках https://euvgub.github.io/quik_user_manual/ch6_9_19.html
сделать триггер, чтобы изменения в тяжелых таблицах делали изменения в легкой сигнальной, а опрашивать эту легкую — её вообще можно сделать чисто в оперативке.
Вот здесь гляньте 64-битная, там все как в 32-битной, сама dll называется lua51.dll (без точки 5.1). Работает «странненько» на восьмерке Квика. Может полгига данных передать, поработать минут 30 — потом внезапно отваливается. А бывает почти сразу отваливается. Время не было разобраться. У кого получится стабильная работа — напишите, если не трудно.
download.zerobrane.com/misc/luasec-0.6-openssl-1.0.2o-luasocket-3.0-win64.zip
заработало, теперь только потестить
У коллеги по такой схеме запрос к базе до 100 раз в секунду, и ничего вроде не тормозит, но у него ссд диск.
У меня один раз в тридцать секунд, я пробовал раз в секунду и у меня уже увеличивается потребление оперативной памяти и загружается процессор.
По поводу нелогичности, если изменение базы раз в час у кого то, и чтоб уловить изменение, делают 10000 запросов к базе, я думаю это не логично.
Так получается? Если так,
Хорошо, давайте еще утрируем, а если у меня будет запущен не один скрипт , а 1000, или 10000, и по каждый отправляет по 100 раз в секунду.
Ну и дальше можно еще утрировать, согласно Вашей логике, все равно ЕДИНСТВЕННОЕ, это обеспечить легкий запрос?
Вроде какие школе по экономической географии проходили , есть экстенсивный путь развития а есть интенсивный.
Увеличение запросов к базе это экстенсивный путь, вообще с таким подходом денег заработаешь меньше при том, что затраты больше.
Это уж экономические законы, их не перепрыгнешь по этому я настаиваю на том, что много бессмысленных запросов- не логично
Тут ведь реальная диалектика ))). По сути я продолжаю с этим мудохаться по двум причинам, привычка все доводить до конца, и просто интересно решить логическую задачу. А вовосе не из за денег. Действительно ведь сам робот и так работает как мне надо Просто в обоих перечисленных мной случаях с длл библиотекой и сокетами решение где то на поверхности, в первом случае надо понять как передать аргумент в функцию, во втором случае найти 64 разр библиотеку, не хочется бросать уже потратив некторое время на решение.
Спасибо.
Как в mysql таблицы выгружать квиковские ?
затем подготовить таблицу для экспорта, это можно посмотреть в документации — нажимешь в квике ф1,
совместная работа с другими приложениями и раздел приложения.
Там для каждой таблицы квик для каждого параметра указан формат
типа данных mysql
затем правой кнопкой мыши на любую нужную таблицу квика нажимаешь, выбираешь экспорт odbс, вводишь логин и пароль к базе если создавал его, справа появляются названия таблиц, которые заранее создал, выбираешь, куда хочешь экспортировать, ниже соотносишь поля таблиц квика и mysql, и погнали
там есть ньюансы конечно, если сложности будут по ходу дела спрашивайте.
Этот экспорт к LUA отношения не имеет вообще.
+ см там последний коммент от swerg'a,
вообщем в итоге сам погуглил, нашел 64 бит core.dll
download.zerobrane.com/misc/luasec-0.6-openssl-1.0.2o-luasocket-3.0-win64.zip
и с ним у меня заработало все.
Только ньюанс, пришлось библитеку открыть прогой depense
оказывается она ссылается на файл lua51.dll а в оригинале lua5.1.dll
переименовал и заработало
WebQuik <--> Websocket <--> Python
Или если экспортирую таблицу сделок, в ьаблицу выводятся сделки, как только строка со сделкой появляется в таблице эта строка и выволится
ЗЫ. Понял в чем дело. С автонумерацией первого столбца.