Initial commit

This commit is contained in:
Игорь Чечет
2021-02-14 15:47:51 +05:00
commit 87425dfe9c
16 changed files with 3512 additions and 0 deletions

588
QuikPy.py Normal file
View File

@@ -0,0 +1,588 @@
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() # Закрываем соединение для запросов и поток обработки функций обратного вызова