589 lines
42 KiB
Python
589 lines
42 KiB
Python
import socket # Обращаться к LUA скриптам QuikSharp будем через соединения
|
||
import threading # Результат работы функций обратного вызова будем получать в отдельном потоке
|
||
import json # Передавать и принимать данные в QUIK будем через JSON
|
||
import time # Задержка при чтении буфера
|
||
|
||
|
||
class Singleton(type):
|
||
"""Метакласс для создания Singleton классов"""
|
||
def __init__(cls, *args, **kwargs):
|
||
"""Инициализация класса"""
|
||
super(Singleton, cls).__init__(*args, **kwargs)
|
||
cls._singleton = None # Экземпляра класса еще нет
|
||
|
||
def __call__(cls, *args, **kwargs):
|
||
"""Вызов класса"""
|
||
if cls._singleton is None: # Если класса нет в экземплярах класса
|
||
cls._singleton = super(Singleton, cls).__call__(*args, **kwargs)
|
||
return cls._singleton # Возвращаем экземпляр класса
|
||
|
||
|
||
class QuikPy(metaclass=Singleton): # Singleton класс
|
||
"""Работа с Quik из Python через LUA скрипты QuikSharp https://github.com/finsight/QUIKSharp/tree/master/src/QuikSharp/lua
|
||
На основе Документации по языку LUA в QUIK из https://arqatech.com/ru/support/files/
|
||
"""
|
||
bufferSize = 4096 # Размер буфера приема в байтах
|
||
socketRequests = None # Соединение для запросов
|
||
callbackThread = None # Поток обработки функций обратного вызова
|
||
|
||
def DefaultHandler(self, data):
|
||
"""Пустой обработчик события по умолчанию. Его можно заменить на пользовательский"""
|
||
pass
|
||
|
||
def CallbackHandler(self):
|
||
"""Поток обработки результатов функций обратного вызова"""
|
||
# TODO Проверить работу при переходе на следующую сессию (отключение и включение QUIK)
|
||
socketCallbacks = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Соединение для функций обратного вызова
|
||
socketCallbacks.connect((self.Host, self.CallbacksPort)) # Открываем соединение для функций обратного вызова
|
||
currentThread = threading.currentThread() # Получаем текущий поток
|
||
while getattr(currentThread, 'process', True): # Пока поток нужен
|
||
fragments = [] # Гораздо быстрее получать ответ в виде списка фрагментов
|
||
while True: # Пока есть что-то в буфере ответов
|
||
fragment = socketCallbacks.recv(self.bufferSize) # Читаем фрагмент из буфера
|
||
fragments.append(fragment.decode('cp1251')) # Переводим фрагмент в Windows кодировку 1251, добавляем в список
|
||
if len(fragment) < self.bufferSize: # Если в принятом фрагменте данных меньше чем размер буфера
|
||
break # то это был последний фрагмент, выходим из чтения буфера
|
||
time.sleep(0.000001) # Может так получиться, что буфер будет считываться быстрее, чем заполняться. Поэтому, ставим небольшую задержку перед следующим чтением
|
||
data = ''.join(fragments) # Собираем список фрагментов в строку
|
||
dataList = data.split('\n') # Одновременно могут прийти несколько функций обратного вызова, разбираем их по одной
|
||
for data in dataList: # Пробегаемся по всем функциям обратного вызова
|
||
if data == '': # Если функция обратного вызова пустая
|
||
continue # то ее не разбираем, переходим на следующую функцию, дальше не продолжаем
|
||
data = json.loads(data) # Возвращаем полученный ответ в формате JSON
|
||
# Разбираем функцию обратного вызова QUIK LUA
|
||
if data['cmd'] == 'OnFirm': # 1. Новая фирма
|
||
self.OnFirm(data)
|
||
elif data['cmd'] == 'OnAllTrade': # 2. Получение обезличенной сделки
|
||
self.OnAllTrade(data)
|
||
elif data['cmd'] == 'OnTrade': # 3. Получение новой / изменение существующей сделки
|
||
self.OnTrade(data)
|
||
elif data['cmd'] == 'OnOrder': # 4. Получение новой / изменение существующей заявки
|
||
self.OnOrder(data)
|
||
elif data['cmd'] == 'OnAccountBalance': # 5. Изменение позиций по счету
|
||
self.OnAccountBalance(data)
|
||
elif data['cmd'] == 'OnFuturesLimitChange': # 6. Изменение ограничений по срочному рынку
|
||
self.OnFuturesLimitChange(data)
|
||
elif data['cmd'] == 'OnFuturesLimitDelete': # 7. Удаление ограничений по срочному рынку
|
||
self.OnFuturesLimitDelete(data)
|
||
elif data['cmd'] == 'OnFuturesClientHolding': # 8. Изменение позиции по срочному рынку
|
||
self.OnFuturesClientHolding(data)
|
||
elif data['cmd'] == 'OnMoneyLimit': # 9. Изменение денежной позиции
|
||
self.OnMoneyLimit(data)
|
||
elif data['cmd'] == 'OnMoneyLimitDelete': # 10. Удаление денежной позиции
|
||
self.OnMoneyLimitDelete(data)
|
||
elif data['cmd'] == 'OnDepoLimit': # 11. Изменение позиций по инструментам
|
||
self.OnDepoLimit(data)
|
||
elif data['cmd'] == 'OnDepoLimitDelete': # 12. Удаление позиции по инструментам
|
||
self.OnDepoLimitDelete(data)
|
||
elif data['cmd'] == 'OnAccountPosition': # 13. Изменение денежных средств
|
||
self.OnAccountPosition(data)
|
||
# OnNegDeal - 14. Получение новой / изменение существующей внебиржевой заявки
|
||
# OnNegTrade - 15. Получение новой / изменение существующей сделки для исполнения
|
||
elif data['cmd'] == 'OnStopOrder': # 16. Получение новой / изменение существующей стоп-заявки
|
||
self.OnStopOrder(data)
|
||
elif data['cmd'] == 'OnTransReply': # 17. Ответ на транзакцию пользователя
|
||
self.OnTransReply(data)
|
||
elif data['cmd'] == 'OnParam': # 18. Изменение текущих параметров
|
||
self.OnParam(data)
|
||
elif data['cmd'] == 'OnQuote': # 19. Изменение стакана котировок
|
||
self.OnQuote(data)
|
||
elif data['cmd'] == 'OnDisconnected': # 20. Отключение терминала от сервера QUIK
|
||
self.OnDisconnected(data)
|
||
elif data['cmd'] == 'OnConnected': # 21. Соединение терминала с сервером QUIK
|
||
self.OnConnected(data)
|
||
# OnCleanUp - 22. Смена сервера QUIK / Пользователя / Сессии
|
||
elif data['cmd'] == 'OnClose': # 23. Закрытие терминала QUIK
|
||
self.OnClose(data)
|
||
elif data['cmd'] == 'OnStop': # 24. Остановка LUA скрипта в терминале QUIK / закрытие терминала QUIK
|
||
self.OnStop(data)
|
||
elif data['cmd'] == 'OnInit': # 25. Запуск LUA скрипта в терминале QUIK
|
||
self.OnInit(data)
|
||
# Разбираем функции обратного вызова QuikSharp
|
||
elif data['cmd'] == 'NewCandle': # Получение новой свечки
|
||
self.OnNewCandle(data)
|
||
elif data['cmd'] == 'OnError': # Получено сообщение об ошибке
|
||
self.OnError(data)
|
||
socketCallbacks.close() # Закрываем соединение для ответов
|
||
|
||
def ProcessRequest(self, Request):
|
||
"""Отправляем запрос в QUIK, получаем ответ из QUIK"""
|
||
rawData = json.dumps(Request) # Переводим запрос в формат JSON
|
||
self.socketRequests.sendall(f'{rawData}\r\n'.encode()) # Отправляем запрос в QUIK
|
||
fragments = [] # Гораздо быстрее получать ответ в виде списка фрагментов
|
||
while True: # Пока фрагменты есть в буфере
|
||
fragment = self.socketRequests.recv(self.bufferSize) # Читаем фрагмент из буфера
|
||
fragments.append(fragment.decode('cp1251')) # Переводим фрагмент в Windows кодировку 1251, добавляем в список
|
||
if len(fragment) < self.bufferSize: # Если в принятом фрагменте данных меньше чем размер буфера
|
||
break # то это был последний фрагмент, выходим из чтения буфера
|
||
time.sleep(0.000001) # Может так получиться, что буфер будет считываться быстрее, чем заполняться. Поэтому, ставим небольшую задержку перед следующим чтением
|
||
data = ''.join(fragments) # Собираем список фрагментов в строку
|
||
return json.loads(data) # Возвращаем ответ в формате JSON в Windows кодировке 1251
|
||
|
||
# Инициализация и вход
|
||
|
||
def __init__(self, Host='127.0.0.1', RequestsPort=34130, CallbacksPort=34131):
|
||
"""Инициализация"""
|
||
# 2.2. Функции обратного вызова
|
||
self.OnFirm = self.DefaultHandler # 1. Новая фирма
|
||
self.OnAllTrade = self.DefaultHandler # 2. Получение обезличенной сделки
|
||
self.OnTrade = self.DefaultHandler # 3. Получение новой / изменение существующей сделки
|
||
self.OnOrder = self.DefaultHandler # 4. Получение новой / изменение существующей заявки
|
||
self.OnAccountBalance = self.DefaultHandler # 5. Изменение позиций
|
||
self.OnFuturesLimitChange = self.DefaultHandler # 6. Изменение ограничений по срочному рынку
|
||
self.OnFuturesLimitDelete = self.DefaultHandler # 7. Удаление ограничений по срочному рынку
|
||
self.OnFuturesClientHolding = self.DefaultHandler # 8. Изменение позиции по срочному рынку
|
||
self.OnMoneyLimit = self.DefaultHandler # 9. Изменение денежной позиции
|
||
self.OnMoneyLimitDelete = self.DefaultHandler # 10. Удаление денежной позиции
|
||
self.OnDepoLimit = self.DefaultHandler # 11. Изменение позиций по инструментам
|
||
self.OnDepoLimitDelete = self.DefaultHandler # 12. Удаление позиции по инструментам
|
||
self.OnAccountPosition = self.DefaultHandler # 13. Изменение денежных средств
|
||
# OnNegDeal - 14. Получение новой / изменение существующей внебиржевой заявки
|
||
# OnNegTrade - 15. Получение новой / изменение существующей сделки для исполнения
|
||
self.OnStopOrder = self.DefaultHandler # 16. Получение новой / изменение существующей стоп-заявки
|
||
self.OnTransReply = self.DefaultHandler # 17. Ответ на транзакцию пользователя
|
||
self.OnParam = self.DefaultHandler # 18. Изменение текущих параметров
|
||
self.OnQuote = self.DefaultHandler # 19. Изменение стакана котировок
|
||
self.OnDisconnected = self.DefaultHandler # 20. Отключение терминала от сервера QUIK
|
||
self.OnConnected = self.DefaultHandler # 21. Соединение терминала с сервером QUIK
|
||
# OnCleanUp - 22. Смена сервера QUIK / Пользователя / Сессии
|
||
self.OnClose = self.DefaultHandler # 23. Закрытие терминала QUIK
|
||
self.OnStop = self.DefaultHandler # 24. Остановка LUA скрипта в терминале QUIK / закрытие терминала QUIK
|
||
self.OnInit = self.DefaultHandler # 25. Запуск LUA скрипта в терминале QUIK
|
||
|
||
# Функции обратного вызова QuikSharp
|
||
self.OnNewCandle = self.DefaultHandler # Получение новой свечки
|
||
self.OnError = self.DefaultHandler # Получено сообщение об ошибке
|
||
|
||
self.Host = Host # IP адрес или название хоста
|
||
self.RequestsPort = RequestsPort # Порт для отправки запросов и получения ответов
|
||
self.CallbacksPort = CallbacksPort # Порт для функций обратного вызова
|
||
self.socketRequests = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Создаем соединение для запросов
|
||
self.socketRequests.connect((self.Host, self.RequestsPort)) # Открываем соединение для запросов
|
||
|
||
self.callbackThread = threading.Thread(target=self.CallbackHandler, name='CallbackThread') # Создаем поток обработки функций обратного вызова
|
||
self.callbackThread.start() # Запускаем поток
|
||
|
||
def __enter__(self):
|
||
"""Вход в класс, например, с with"""
|
||
return self
|
||
|
||
# Фукнции связи с QuikSharp
|
||
|
||
def Ping(self, TransId=0):
|
||
"""Проверка соединения. Отправка ping. Получение pong"""
|
||
return self.ProcessRequest({'data': 'Ping', 'id': TransId, 'cmd': 'ping', 't': ''})
|
||
|
||
def Echo(self, Message, TransId=0):
|
||
"""Эхо. Отправка и получение одного и того же сообщения"""
|
||
return self.ProcessRequest({'data': Message, 'id': TransId, 'cmd': 'echo', 't': ''})
|
||
|
||
def DivideStringByZero(self, TransId=0):
|
||
"""Тест обработки ошибок. Выполняется деление на 0 с выдачей ошибки"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'divide_string_by_zero', 't': ''})
|
||
|
||
def IsQuik(self, TransId=0):
|
||
"""Скрипт запущен в Квике"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'is_quik', 't': ''})
|
||
|
||
# 2.1 Сервисные функции
|
||
|
||
def IsConnected(self, TransId=0): # 1
|
||
"""Состояние подключения терминала к серверу QUIK. Возвращает 1 - подключено / 0 - не подключено"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'isConnected', 't': ''})
|
||
|
||
def GetScriptPath(self, TransId=0): # 2
|
||
"""Путь скрипта без завершающего обратного слэша"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getScriptPath', 't': ''})
|
||
|
||
def GetInfoParam(self, Params, TransId=0): # 3
|
||
"""Значения параметров информационного окна"""
|
||
return self.ProcessRequest({'data': Params, 'id': TransId, 'cmd': 'getInfoParam', 't': ''})
|
||
|
||
# message - 4. Сообщение в терминале QUIK. Реализовано в виде 3-х отдельных функций в QuikSharp
|
||
|
||
def Sleep(self, Time, TransId=0): # 5
|
||
"""Приостановка скрипта. Время в миллисекундах"""
|
||
return self.ProcessRequest({'data': Time, 'id': TransId, 'cmd': 'sleep', 't': ''})
|
||
|
||
def GetWorkingFolder(self, TransId=0): # 6
|
||
"""Путь к info.exe, исполняющего скрипт без завершающего обратного слэша"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getWorkingFolder', 't': ''})
|
||
|
||
def PrintDbgStr(self, Message, TransId=0): # 7
|
||
"""Вывод отладочной информации. Можно посмотреть с помощью DebugView"""
|
||
return self.ProcessRequest({'data': Message, 'id': TransId, 'cmd': 'PrintDbgStr', 't': ''})
|
||
|
||
# sysdate - 8. Системные дата и время
|
||
# isDarkTheme - 9. Тема оформления. true - тёмная, false - светлая
|
||
|
||
# Сервисные функции QuikSharp
|
||
|
||
def MessageInfo(self, Message, TransId=0): # В QUIK LUA message icon_type=1
|
||
"""Отправка информационного сообщения в терминал QUIK"""
|
||
return self.ProcessRequest({'data': Message, 'id': TransId, 'cmd': 'message', 't': ''})
|
||
|
||
def MessageWarning(self, Message, TransId=0): # В QUIK LUA message icon_type=2
|
||
"""Отправка сообщения с предупреждением в терминал QUIK"""
|
||
return self.ProcessRequest({'data': Message, 'id': TransId, 'cmd': 'warning_message', 't': ''})
|
||
|
||
def MessageError(self, Message, TransId=0): # В QUIK LUA message icon_type=3
|
||
"""Отправка сообщения об ошибке в терминал QUIK"""
|
||
return self.ProcessRequest({'data': Message, 'id': TransId, 'cmd': 'error_message', 't': ''})
|
||
|
||
# 3.1. Функции для обращения к строкам произвольных таблиц
|
||
|
||
# getItem - 1. Строка таблицы
|
||
# getOrderByNumber - 2. Заявка
|
||
# getNumberOf - 3. Кол-во записей в таблице
|
||
# SearchItems - 4. Быстрый поиск по таблице заданной функцией поиска
|
||
|
||
# Функции для обращения к строкам произвольных таблиц QuikSharp
|
||
|
||
def GetTradeAccounts(self, TransId=0):
|
||
"""Торговые счета, у которых указаны поддерживаемые классы инструментов"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getTradeAccounts', 't': ''})
|
||
|
||
def GetTradeAccount(self, ClassCode, TransId=0):
|
||
"""Торговый счет для запрашиваемого кода класса"""
|
||
return self.ProcessRequest({'data': ClassCode, 'id': TransId, 'cmd': 'getTradeAccount', 't': ''})
|
||
|
||
def GetAllOrders(self, TransId=0):
|
||
"""Таблица заявок (вся)"""
|
||
return self.ProcessRequest({'data': f'', 'id': TransId, 'cmd': 'get_orders', 't': ''})
|
||
|
||
def GetOrders(self, ClassCode, SecCode, TransId=0):
|
||
"""Таблица заявок (по инструменту)"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'get_orders', 't': ''})
|
||
|
||
def GetOrderByNumber(self, OrderId, TransId=0):
|
||
"""Заявка по номеру"""
|
||
return self.ProcessRequest({'data': OrderId, 'id': TransId, 'cmd': 'getOrder_by_Number', 't': ''})
|
||
|
||
def GetOrderById(self, ClassCode, SecCode, OrderTransId, TransId=0):
|
||
"""Заявка по инструменту и Id транзакции"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{OrderTransId}', 'id': TransId, 'cmd': 'getOrder_by_ID', 't': ''})
|
||
|
||
def GetOrderByClassNumber(self, ClassCode, OrderId, TransId=0):
|
||
"""Заявка по классу инструмента и номеру"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{OrderId}', 'id': TransId, 'cmd': 'getOrder_by_Number', 't': ''})
|
||
|
||
def GetMoneyLimits(self, TransId=0):
|
||
"""Все денежные лимиты"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getMoneyLimits', 't': ''})
|
||
|
||
def GetClientCode(self, TransId=0):
|
||
"""Основной (первый) код клиента"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getClientCode', 't': ''})
|
||
|
||
def GetClientCodes(self, TransId=0):
|
||
"""Все коды клиента"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getClientCode', 't': ''})
|
||
|
||
def GetAllDepoLimits(self, TransId=0):
|
||
"""Лимиты по бумагам (всем)"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'get_depo_limits', 't': ''})
|
||
|
||
def GetDepoLimits(self, SecCode, TransId=0):
|
||
"""Лимиты по бумагам (по инструменту)"""
|
||
return self.ProcessRequest({'data': SecCode, 'id': TransId, 'cmd': 'get_depo_limits', 't': ''})
|
||
|
||
def GetAllTrades(self, TransId=0):
|
||
"""Таблица сделок (вся)"""
|
||
return self.ProcessRequest({'data': f'', 'id': TransId, 'cmd': 'get_trades', 't': ''})
|
||
|
||
def GetTrades(self, ClassCode, SecCode, TransId=0):
|
||
"""Таблица сделок (по инструменту)"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'get_trades', 't': ''})
|
||
|
||
def GetTradesByOrderNumber(self, OrderNum, TransId=0):
|
||
"""Таблица сделок по номеру заявки"""
|
||
return self.ProcessRequest({'data': OrderNum, 'id': TransId, 'cmd': 'get_Trades_by_OrderNumber', 't': ''})
|
||
|
||
def GetAllStopOrders(self, TransId=0):
|
||
"""Стоп заявки (все)"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'get_stop_orders', 't': ''})
|
||
|
||
def GetStopOrders(self, ClassCode, SecCode, TransId=0):
|
||
"""Стоп заявки (по инструменту)"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'get_stop_orders', 't': ''})
|
||
|
||
def GetAllTrade(self, TransId=0):
|
||
"""Таблица обезличенных сделок (вся)"""
|
||
return self.ProcessRequest({'data': f'', 'id': TransId, 'cmd': 'get_all_trades', 't': ''})
|
||
|
||
def GetTrade(self, ClassCode, SecCode, TransId=0):
|
||
"""Таблица обезличенных сделок (по инструменту)"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'get_all_trades', 't': ''})
|
||
|
||
# 3.2 Функции для обращения к спискам доступных параметров
|
||
|
||
def GetClassesList(self, TransId=0): # 1
|
||
"""Список классов"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getClassesList', 't': ''})
|
||
|
||
def GetClassInfo(self, ClassCode, TransId=0): # 2
|
||
"""Информация о классе"""
|
||
return self.ProcessRequest({'data': ClassCode, 'id': TransId, 'cmd': 'getClassInfo', 't': ''})
|
||
|
||
def GetClassSecurities(self, ClassCode, TransId=0): # 3
|
||
"""Список инструментов класса"""
|
||
return self.ProcessRequest({'data': ClassCode, 'id': TransId, 'cmd': 'getClassSecurities', 't': ''})
|
||
|
||
# Функции для обращения к спискам доступных параметров QuikSharp
|
||
|
||
def GetOptionBoard(self, ClassCode, SecCode, TransId=0):
|
||
"""Доска опционов"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'getOptionBoard', 't': ''})
|
||
|
||
# 3.3 Функции для получения информации по денежным средствам
|
||
|
||
def GetMoney(self, ClientCode, FirmId, Tag, CurrCode, TransId=0): # 1
|
||
"""Денежные позиции"""
|
||
return self.ProcessRequest({'data': f'{ClientCode}|{FirmId}|{Tag}|{CurrCode}', 'id': TransId, 'cmd': 'getMoney', 't': ''})
|
||
|
||
def GetMoneyEx(self, FirmId, ClientCode, Tag, CurrCode, LimitKind, TransId=0): # 2
|
||
"""Денежные позиции указанного типа"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{ClientCode}|{Tag}|{CurrCode}|{LimitKind}', 'id': TransId, 'cmd': 'getMoneyEx', 't': ''})
|
||
|
||
# 3.4 Функции для получения позиций по инструментам
|
||
|
||
def GetDepo(self, ClientCode, FirmId, SecCode, Account, TransId=0): # 1
|
||
"""Позиции по инструментам"""
|
||
return self.ProcessRequest({'data': f'{ClientCode}|{FirmId}|{SecCode}|{Account}', 'id': TransId, 'cmd': 'getDepo', 't': ''})
|
||
|
||
def GetDepoEx(self, FirmId, ClientCode, SecCode, Account, LimitKind, TransId=0): # 2
|
||
"""Позиции по инструментам указанного типа"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{ClientCode}|{SecCode}|{Account}|{LimitKind}', 'id': TransId, 'cmd': 'getDepoEx', 't': ''})
|
||
|
||
# 3.5 Функция для получения информации по фьючерсным лимитам
|
||
|
||
def GetFuturesLimit(self, FirmId, AccountId, LimitType, CurrCode, TransId=0): # 1
|
||
"""Фьючерсные лимиты"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{AccountId}|{LimitType}|{CurrCode}', 'id': TransId, 'cmd': 'getFuturesLimit', 't': ''})
|
||
|
||
# Функция для получения информации по фьючерсным лимитам QuikSharp
|
||
|
||
def GetFuturesClientLimits(self, TransId=0):
|
||
"""Все фьючерсные лимиты"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getFuturesClientLimits', 't': ''})
|
||
|
||
# 3.6 Функция для получения информации по фьючерсным позициям
|
||
|
||
def GetFuturesHolding(self, FirmId, AccountId, SecCode, PositionType, TransId=0): # 1
|
||
"""Фьючерсные позиции"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{AccountId}|{SecCode}|{PositionType}', 'id': TransId, 'cmd': 'getFuturesHolding', 't': ''})
|
||
|
||
# Функция для получения информации по фьючерсным позициям QuikSharp
|
||
|
||
def GetFuturesHoldings(self, TransId=0):
|
||
"""Все фьючерсные позиции"""
|
||
return self.ProcessRequest({'data': '', 'id': TransId, 'cmd': 'getFuturesHolding', 't': ''})
|
||
|
||
# 3.7 Функция для получения информации по инструменту
|
||
|
||
def GetSecurityInfo(self, ClassCode, SecCode, TransId=0): # 1
|
||
"""Информация по инструменту"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'getSecurityInfo', 't': ''})
|
||
|
||
# Функция для получения информации по инструменту QuikSharp
|
||
|
||
def GetSecurityInfoBulk(self, ClassCodes, SecCodes, TransId=0):
|
||
"""Информация по инструментам"""
|
||
return self.ProcessRequest({'data': f'{ClassCodes}|{SecCodes}', 'id': TransId, 'cmd': 'getSecurityInfoBulk', 't': ''})
|
||
|
||
def GetSecurityClass(self, ClassesList, SecCode, TransId=0):
|
||
"""Класс по коду инструмента из заданных классов"""
|
||
return self.ProcessRequest({'data': f'{ClassesList}|{SecCode}', 'id': TransId, 'cmd': 'getSecurityClass', 't': ''})
|
||
|
||
# 3.8 Функция для получения даты торговой сессии
|
||
|
||
# getTradeDate - 1. Дата текущей торговой сессии
|
||
|
||
# 3.9 Функция для получения стакана по указанному классу и инструменту
|
||
|
||
def GetQuoteLevel2(self, ClassCode, SecCode, TransId=0): # 1
|
||
"""Стакан по классу и инструменту"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'GetQuoteLevel2', 't': ''})
|
||
|
||
# 3.10 Функции для работы с графиками
|
||
|
||
# getLinesCount - 1. Кол-во линий в графике
|
||
|
||
def GetNumCandles(self, Tag, TransId=0): # 2
|
||
"""Кол-во свечей по тэгу"""
|
||
return self.ProcessRequest({'data': Tag, 'id': TransId, 'cmd': 'getNumCandles', 't': ''})
|
||
|
||
# getCandlesByIndex - 3. Информация о свечках (реализовано в get_candles)
|
||
# CreateDataSource - 4. Создание источника данных c функциями: (реализовано в get_candles_from_data_source)
|
||
# - SetUpdateCallback - Привязка функции обратного вызова на изменение свечи
|
||
# - O, H, L, C, V, T - Функции получения цен, объемов и времени
|
||
# - Size - Функция кол-ва свечек в источнике данных
|
||
# - Close - Функция закрытия источника данных. Терминал прекращает получать данные с сервера
|
||
# - SetEmptyCallback - Функция сброса функции обратного вызова на изменение свечи
|
||
|
||
# Функции для работы с графиками QuikSharp
|
||
|
||
def GetCandles(self, Tag, Line, FirstCandle, Count, TransId=0):
|
||
"""Свечки по идентификатору графика"""
|
||
return self.ProcessRequest({'data': f'{Tag}|{Line}|{FirstCandle}|{Count}', 'id': TransId, 'cmd': 'get_candles', 't': ''})
|
||
|
||
def GetCandlesFromDataSource(self, ClassCode, SecCode, Interval, Count): # ichechet - Добавлен выход по таймауту
|
||
"""Свечки"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{Interval}|{Count}', 'id': '1', 'cmd': 'get_candles_from_data_source', 't': ''})
|
||
|
||
def SubscribeToCandles(self, ClassCode, SecCode, Interval, TransId=0):
|
||
"""Подписка на свечки"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{Interval}', 'id': TransId, 'cmd': 'subscribe_to_candles', 't': ''})
|
||
|
||
def IsSubscribed(self, ClassCode, SecCode, Interval, TransId=0):
|
||
"""Есть ли подписка на свечки"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{Interval}', 'id': TransId, 'cmd': 'is_subscribed', 't': ''})
|
||
|
||
def UnsubscribeFromCandles(self, ClassCode, SecCode, Interval, TransId=0):
|
||
"""Отмена подписки на свечки"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{Interval}', 'id': TransId, 'cmd': 'unsubscribe_from_candles', 't': ''})
|
||
|
||
# 3.11 Функции для работы с заявками
|
||
|
||
def SendTransaction(self, Transaction, TransId=0): # 1
|
||
"""Отправка транзакции в торговую систему"""
|
||
return self.ProcessRequest({'data': Transaction, 'id': TransId, 'cmd': 'sendTransaction', 't': ''})
|
||
|
||
# CalcBuySell - 2. Максимальное кол-во лотов в заявке
|
||
|
||
# 3.12 Функции для получения значений таблицы "Текущие торги"
|
||
|
||
def GetParamEx(self, ClassCode, SecCode, ParamName, TransId=0): # 1
|
||
"""Таблица текущих торгов"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{ParamName}', 'id': TransId, 'cmd': 'getParamEx', 't': ''})
|
||
|
||
def GetParamEx2(self, ClassCode, SecCode, ParamName, TransId=0): # 2
|
||
"""Таблица текущих торгов по инструменту с возможностью отказа от получения"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{ParamName}', 'id': TransId, 'cmd': 'getParamEx2', 't': ''})
|
||
|
||
# Функция для получения значений таблицы "Текущие торги" QuikSharp
|
||
|
||
def GetParamEx2Bulk(self, ClassCodes, SecCodes, ParamNames, TransId=0):
|
||
"""Таблица текущих торгов по инструментам с возможностью отказа от получения"""
|
||
return self.ProcessRequest({'data': f'{ClassCodes}|{SecCodes}|{ParamNames}', 'id': TransId, 'cmd': 'getParamEx2Bulk', 't': ''})
|
||
|
||
# 3.13 Функции для получения параметров таблицы "Клиентский портфель"
|
||
|
||
def GetPortfolioInfo(self, FirmId, ClientCode, TransId=0): # 1
|
||
"""Клиентский портфель"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{ClientCode}', 'id': TransId, 'cmd': 'getPortfolioInfo', 't': ''})
|
||
|
||
def GetPortfolioInfoEx(self, FirmId, ClientCode, LimitKind, TransId=0): # 2
|
||
"""Клиентский портфель по сроку расчетов"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{ClientCode}|{LimitKind}', 'id': TransId, 'cmd': 'getPortfolioInfoEx', 't': ''})
|
||
|
||
# 3.14 Функции для получения параметров таблицы "Купить/Продать"
|
||
|
||
# getBuySellInfo - 1. Параметры таблицы купить/продать
|
||
# getBuySellInfoEx - 2. Параметры таблицы купить/продать с дополнительными полями вывода
|
||
|
||
# 3.15 Функции для работы с таблицами Рабочего места QUIK
|
||
|
||
# AddColumn - 1. Добавление колонки в таблицу
|
||
# AllocTable - 2. Структура, описывающая таблицу
|
||
# Clear - 3. Удаление содержимого таблицы
|
||
# CreateWindow - 4. Создание окна таблицы
|
||
# DeleteRow - 5. Удаление строки из таблицы
|
||
# DestroyTable - 6. Закрытие окна таблицы
|
||
# InsertRow - 7. Добавление строки в таблицу
|
||
# IsWindowClosed - 8. Закрыто ли окно с таблицей
|
||
# GetCell - 9. Данные ячейки таблицы
|
||
# GetTableSize - 10. Кол-во строк и столбцов таблицы
|
||
# GetWindowCaption - 11. Заголовок окна таблицы
|
||
# GetWindowRect - 12. Координаты верхнего левого и правого нижнего углов таблицы
|
||
# SetCell - 13. Установка значения ячейки таблицы
|
||
# SetWindowCaption - 14. Установка заголовка окна таблицы
|
||
# SetWindowPos - 15. Установка верхнего левого угла, и размеры таблицы
|
||
# SetTableNotificationCallback - 16. Установка функции обратного вызова для обработки событий в таблице
|
||
# RGB - 17. Преобразование каждого цвета в одно число для функци SetColor
|
||
# SetColor - 18. Установка цвета ячейки, столбца или строки таблицы
|
||
# Highlight - 19. Подсветка диапазона ячеек цветом фона и цветом текста на заданное время с плавным затуханием
|
||
# SetSelectedRow - 20. Выделение строки таблицы
|
||
|
||
# 3.16 Функции для работы с метками
|
||
|
||
def AddLabel(self, Price, CurDate, CurTime, Qty, Path, LabelId, Alignment, Background, TransId=0): # 1
|
||
"""Добавление метки на график"""
|
||
return self.ProcessRequest({'data': f'{Price}|{CurDate}|{CurTime}|{Qty}|{Path}|{LabelId}|{Alignment}|{Background}', 'id': TransId, 'cmd': 'AddLabel', 't': ''})
|
||
|
||
def DelLabel(self, ChartTag, LabelId, TransId=0): # 2
|
||
"""Удаление метки с графика"""
|
||
return self.ProcessRequest({'data': f'{ChartTag}|{LabelId}', 'id': TransId, 'cmd': 'DelLabel', 't': ''})
|
||
|
||
def DelAllLabels(self, ChartTag, TransId=0): # 3
|
||
"""Удаление всех меток с графика"""
|
||
return self.ProcessRequest({'data': ChartTag, 'id': TransId, 'cmd': 'DelAllLabels', 't': ''})
|
||
|
||
def GetLabelParams(self, ChartTag, LabelId, TransId=0): # 4
|
||
"""Получение параметров метки"""
|
||
return self.ProcessRequest({'data': f'{ChartTag}|{LabelId}', 'id': TransId, 'cmd': 'GetLabelParams', 't': ''})
|
||
|
||
# SetLabelParams - 5. Установка параметров метки
|
||
|
||
# 3.17 Функции для заказа стакана котировок
|
||
|
||
def SubscribeLevel2Quotes(self, ClassCode, SecCode, TransId=0): # 1
|
||
"""Подписка на стакан по Классу|Коду бумаги"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'Subscribe_Level_II_Quotes', 't': ''})
|
||
|
||
def UnsubscribeLevel2Quotes(self, ClassCode, SecCode, TransId=0): # 2
|
||
"""Отмена подписки на стакан по Классу|Коду бумаги"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'Unsubscribe_Level_II_Quotes', 't': ''})
|
||
|
||
def IsSubscribedLevel2Quotes(self, ClassCode, SecCode, TransId=0): # 3
|
||
"""Есть ли подписка на стакан по Классу|Коду бумаги"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}', 'id': TransId, 'cmd': 'IsSubscribed_Level_II_Quotes', 't': ''})
|
||
|
||
# 3.18 Функции для заказа параметров Таблицы текущих торгов
|
||
|
||
def ParamRequest(self, ClassCode, SecCode, ParamName, TransId=0): # 1
|
||
"""Заказ получения таблицы текущих торгов по инструменту"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{ParamName}', 'id': TransId, 'cmd': 'paramRequest', 't': ''})
|
||
|
||
def CancelParamRequest(self, ClassCode, SecCode, ParamName, TransId=0): # 2
|
||
"""Отмена заказа получения таблицы текущих торгов по инструменту"""
|
||
return self.ProcessRequest({'data': f'{ClassCode}|{SecCode}|{ParamName}', 'id': TransId, 'cmd': 'cancelParamRequest', 't': ''})
|
||
|
||
# Функции для заказа параметров Таблицы текущих торгов QuikSharp
|
||
|
||
def ParamRequestBulk(self, ClassCodes, SecCodes, ParamNames, TransId=0):
|
||
"""Заказ получения таблицы текущих торгов по инструментам"""
|
||
return self.ProcessRequest({'data': f'{ClassCodes}|{SecCodes}|{ParamNames}', 'id': TransId, 'cmd': 'paramRequestBulk', 't': ''})
|
||
|
||
def CancelParamRequestBulk(self, ClassCodes, SecCodes, ParamNames, TransId=0):
|
||
"""Отмена заказа получения таблицы текущих торгов по инструментам"""
|
||
return self.ProcessRequest({'data': f'{ClassCodes}|{SecCodes}|{ParamNames}', 'id': TransId, 'cmd': 'cancelParamRequestBulk', 't': ''})
|
||
|
||
# 3.19 Функции для получения информации по единой денежной позиции
|
||
|
||
def GetTrdAccByClientCode(self, FirmId, ClientCode, TransId=0): # 1
|
||
"""Торговый счет срочного рынка по коду клиента фондового рынка"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{ClientCode}', 'id': TransId, 'cmd': 'getTrdAccByClientCode', 't': ''})
|
||
|
||
def GetClientCodeByTrdAcc(self, FirmId, TradeAccountId, TransId=0): # 2
|
||
"""Код клиента фондового рынка с единой денежной позицией по торговому счету срочного рынка"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{TradeAccountId}', 'id': TransId, 'cmd': 'getClientCodeByTrdAcc', 't': ''})
|
||
|
||
def IsUcpClient(self, FirmId, Client, TransId=0): # 3
|
||
"""Имеет ли клиент единую денежную позицию"""
|
||
return self.ProcessRequest({'data': f'{FirmId}|{Client}', 'id': TransId, 'cmd': 'IsUcpClient', 't': ''})
|
||
|
||
# Выход и закрытие
|
||
|
||
def CloseConnectionAndThread(self):
|
||
"""Закрытие соединения для запросов и потока обработки функций обратного вызова"""
|
||
self.socketRequests.close() # Закрываем соединение для запросов
|
||
self.callbackThread.process = False # Поток обработки функций обратного вызова больше не нужен
|
||
|
||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||
"""Выход из класса, например, с with"""
|
||
self.CloseConnectionAndThread() # Закрываем соединение для запросов и поток обработки функций обратного вызова
|
||
|
||
def __del__(self):
|
||
self.CloseConnectionAndThread() # Закрываем соединение для запросов и поток обработки функций обратного вызова
|