Последние несколько месяцев время от времени начинал времени ломать голову над одной задачкой.
Суть в следующем.
Я сделал скрипт на питоне, на основе торговых данных пишет заявки в 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?
import zmq context = zmq.Context() socket = self.context.socket(zmq.REQ) socket.connect('tcp://127.0.0.1:5560') socket.send_string('{"method":"datasource.CreateDataSource","args":{"class_code":"SPBFUT", "sec_code":"SiH0", "interval":"INTERVAL_M1", "param":""}}') datasource_uuid = json.loads(socket.recv_string())['result']['datasource_uuid'] socket.send_string('{"method":"datasource.Size","args":{"datasource_uuid":"%s"}}' % (datasource_uuid)) num_candles = json.loads(socket.recv_string())['result']['value'] for i in range(0,num_candles): socket.send_string('{"method":"datasource.C","args":{"datasource_uuid":"%s","candle_index":%d}}' % (datasource_uuid, i)) candle_close = json.loads(socket.recv_string())['result']['value'] socket.send_string('{"method":"datasource.O","args":{"datasource_uuid":"%s","candle_index":%d}}' % (datasource_uuid, i)) candle_open = json.loads(socket.recv_string())['result']['value'] socket.send_string('{"method":"datasource.T","args":{"datasource_uuid":"%s","candle_index":%d}}' % (datasource_uuid, i)) candle_time = json.loads(socket.recv_string())['result']['value']иллюстрация, куда можно это дальше применить
quotes = {} quotes['open']=numpy.asarray([item['open'] for item in data]) quotes['close']=numpy.asarray([item['close'] for item in data]) quotes['high']=numpy.asarray([item['high'] for item in data]) quotes['low']=numpy.asarray([item['low'] for item in data]) quotes['datetime']=numpy.asarray([item['datetime'] for item in data]) fig, ax = plt.subplots(3, sharex=True) candlestick2_ohlc(ax[0],quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6) ax[0].xaxis.set_major_locator(ticker.MaxNLocator(6)) def chart_date(x,pos): try: return quotes['datetime'][int(x)] except IndexError: return '' ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date)) fig.autofmt_xdate() fig.tight_layout() quotes['close'] = numpy.array([float(x) for x in quotes['close']]) sma = talib.SMA(quotes['close'], timeperiod=50) ax[0].plot(sma) ema = talib.EMA(quotes['close'], timeperiod=20) ax[0].plot(ema) macd, macdsignal, macdhist = talib.MACD(quotes['close'], fastperiod=12, slowperiod=26, signalperiod=9) ax[1].plot(macd, color="y") ax[1].plot(macdsignal) hist_data = [] for elem in macdhist: if not numpy.isnan(elem): v = 0 if numpy.isnan(elem) else elem hist_data.append(v*100) ax[2].fill_between([x for x in range(len(macdhist))], 0,macdhist) plt.show()