Enfernuz / quik-lua-rpc

RPC-сервис для вызова API Lua-библиотеки торгового терминала QUIK (ARQA Technologies)
Apache License 2.0
103 stars 43 forks source link

Пример клиента на python для quik-lua-rpc v2.0-alpha.0 JSON? #17

Open euvgub opened 5 years ago

euvgub commented 5 years ago

Пример клиента на python?

Enfernuz commented 5 years ago

Пока только на Java. Не знаю, буду ли я в этом году писать для Python... Можете выложить свои наработки, если таковые имеются, -- наверняка народ подхватит.

euvgub commented 5 years ago

Механизм аутентификации ZeroMQ:"NULL" (нет аутентификации)

-- coding: utf-8 --

import zmq context = zmq.Context() print("Connecting to test server") socket = context.socket(zmq.REQ) socket.connect("tcp://localhost:5560") print("Sending request") socket.send_string('GET_SCRIPT_PATH') message = socket.recv() print("Received reply [ %s ]" % (message))

Connecting to test server Sending request Received reply [ b"\x10\x01\x1a\xe6\x01\xd0\xa0\xd1\x9b\xd0\xa1\xe2\x82\xac\xd0\xa0\xd1\x91\xd0\xa0\xc2\xb1\xd0\xa0\xd1\x94\xd0\xa0\xc2\xb0 \xd0\xa0\xd1\x97\xd0\xa1\xd0\x82\xd0\xa0\xd1\x91 \xd0\xa0\xd1\x95\xd0\xa0\xc2\xb1\xd0\xa1\xd0\x82\xd0\xa0\xc2\xb0\xd0\xa0\xc2\xb1\xd0\xa0\xd1\x95\xd0\xa1\xe2\x80\x9a\xd0\xa0\xd1\x94\xd0\xa0\xc2\xb5 \xd0\xa0\xd0\x86\xd0\xa1\xe2\x80\xa6\xd0\xa0\xd1\x95\xd0\xa0\xd2\x91\xd0\xa1\xd0\x8f\xd0\xa1\xe2\x80\xb0\xd0\xa0\xc2\xb5\xd0\xa0\xd1\x96\xd0\xa0\xd1\x95 \xd0\xa0\xc2\xb7\xd0\xa0\xc2\xb0\xd0\xa0\xd1\x97\xd0\xa1\xd0\x82\xd0\xa0\xd1\x95\xd0\xa1\xd0\x83\xd0\xa0\xc2\xb0: 'C:\Test_QUIK\lua\protobuf\decoder.lua:311: Tag had invalid wire type.'." ]

Enfernuz commented 5 years ago

Эмм, нет, это не так работает. В той версии, что лежит сейчас в ветке master, сообщения от/к серверу сериализуются/десериализуются с помощью Protobuf (гайд для Python). Сами схемы сообщений (файлы .proto) можно найти в директории qlua/rpc RPC-сервиса. То есть, фактически, сервис с Вами общается посредством бинарных сообщений, которые закодированы Protobuf'ом.

Есть наработки для общения посредством JSON, но там ещё не доделано. Думаю, в течение следующей недели дозалью коммиты к альфа-версии.

Если нужна помощью по Protobuf -- пишите.

Enfernuz commented 5 years ago

В ветке master теперь лежит альфа-версия с поддержкой JSON.

Почему альфа?

import zmq
context = zmq.Context()
print("Connecting to test server")
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5560")

print("\nSending request")
socket.send_string("{\"method\":\"message\", \"args\":{\"message\":\"Hello!\",\"icon_type\":\"WARNING\"}}")
message = socket.recv()
print("Received reply [ %s ]\n" % (message))

print("Sending request")
socket.send_string("{\"method\":\"getScriptPath\"}")
message = socket.recv()
print("Received reply [ %s ]\n" % (message))

print("Sending request")
socket.send_string("{\"method\":\"getClassesList\"}")
message = socket.recv()
print("Received reply [ %s ]" % (message))

Connecting to test server

Sending request Received reply [ b'{"result":{"result":1}}' ]

Sending request Received reply [ b'{"result":{"script_path":"D:\\programs\\Quik_KF\\lua\\quik-lua-rpc"}}' ]

Sending request Received reply [ b'{"result":{"classes_list":"CROSSRATE,PSAU,AUCT,INDX,TQTC,EQOB,EQEO,EQDB,EQRP_INFO,TQBR,TQDE,TQOB,EQTC,TQIF,TQTF,SPEQ,TQTD,TQOD,EQTD,CETS,INDXC,CETS_MTL,REPORT,REPORTFORTS,SPBXM,RTSIDX,SPBFUT,SPBOPT,USDRUB,OPTW,"}}' ]

Документацию по API пока не написал, но вскоре займусь ей. В общих чертах, формат сообщений такой:

Запрос:

{
  "method":"НАЗВАНИЕ_QLUA-ФУНКЦИИ",
  "args": {
    // АРГУМЕНТЫ QLUA-ФУНКЦИИ
  }
}

Ответ:

{
  "method": "НАЗВАНИЕ_QLUA-ФУНКЦИИ",
  "result": // РЕЗУЛЬТАТ QLUA-ФУНКЦИИ (число, объект, строка -- в зависимости от вызываемой функции)
}

Ответ в случае ошибки сервиса:

{
  "method":"НАЗВАНИЕ_QLUA-ФУНКЦИИ",
  "error": {
    "code": // ЧИСЛОВОЙ КОД ОШИБКИ,
    "message": "ИНФОРМАЦИЯ ОБ ОШИБКЕ"
  }
}

!!! Все дробные числа передаются как строки (что в аргументах, что в ответе от сервиса).

euvgub commented 5 years ago

Чудесно! В отдельный бы репозиторий quik-lua-rpc-python-client - Пример Python-клиента к сервису 'quik-lua-rpc'.

Enfernuz commented 5 years ago

Ну, по сути, кроме этих сниппетов кода на Python как такового и нет... Клиент, в моём понимании, -- это всё же некая библиотека, позволяющая скрыть от пользователя низкоуровневую работу с сообщениями и ZeroMQ. Если вдруг раньше меня напишете такую на Python -- дайте знать.

sholoma commented 5 years ago

Может кто в курсе. А нет просто нормального РФ брокера с апи? Чтобы не мучаться с этим адом квиком

Enfernuz commented 5 years ago

Какие-то брокеры предоставляют доступ на MOEX через MetaTrader. QUIK, имхо, -- он больше для профессиональных трейдеров в фирмах (в том числе брокерских), поэтому может показаться, что в нём много всякой "ненужной фигни".

sholoma commented 5 years ago

Квик для компа бесспорно норм. Но вот именно прямого апи у брокера жалко нету. Те недобиржи по крипте это все сделали давно...( Но они меня не интересуют.

sholoma commented 5 years ago

Ладно хоть Квик под wine пашет. Хоть что-то немного радует.)

euvgub commented 5 years ago

Вот уже есть пример Python-клиента к сервису quik-lua-rpc https://github.com/yofi2tofi/mmvddss

Enfernuz commented 5 years ago

sholoma, под прямым API Вы имеете в виду прямой доступ к бирже, минуя всякие терминалы? Если так, то такая штука давно существует и её предоставляют почти все брокеры.

Получение маркет-даты через следующие протоколы:

Отправка транзакций:

Но, уверяю, работа с этими протоколами на порядок сложнее, чем с QUIK (особенно по части обработки транзакций -- говорю из собственного опыта), даже при использовании каких-то готовых библиотек. Проще всех из них, наверное, Plaza2. И по латенси не сказать что бы андердог.

Enfernuz commented 5 years ago

Вот уже есть пример Python-клиента к сервису quik-lua-rpc https://github.com/yofi2tofi/mmvddss

Да, в качестве клиента к первой версии, где только protobuf, очень даже сойдёт. Добавлю ссылку в доку. Да и для второй версии сгодится, если в нём перегенерировать .py-обвязки над .proto-файлами (я поменял везде название message Request на message Args -- так лучше вписывается в модель).

euvgub commented 5 years ago

Может кто в курсе. А нет просто нормального РФ брокера с апи? Чтобы не мучаться с этим адом квиком

Это прямо готовая идея подпольного стартапа moex data sharing по аналогии со спутниковым шарингом

euvgub commented 5 years ago

Актуальное руководство по Qlua QUIK Lua. Версия 7.24 от 21.01.2019 Интерпретатор языка Lua. Руководство пользователя. Версия 7.24 https://euvgub.github.io/

В ветке master теперь лежит альфа-версия с поддержкой JSON.

  • не обновлял структуры данных коллбэков (OnFirm и прочие) в соответствии с последним руководством к терминалу (у меня структуры от руководства ~июля 2018) -- каких-то полей, добавленных позднее, может не хватать
euvgub commented 5 years ago

Python клиент для второй версии quik-lua-rpc v2.0-alpha.0 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":"SiU9", "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']
euvgub commented 5 years ago
import zmq

context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://127.0.0.1:5561")
socket.setsockopt(zmq.SUBSCRIBE, b"OnAllTrade")
while True:
    print(json.loads(socket.recv_unicode()))