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

33
Examples/01 - Connect.py Normal file
View File

@@ -0,0 +1,33 @@
from QuikPy import QuikPy as qp # QuikPy = Работа с Quik из Python через LUA скрипты QuikSharp
def PrintCallback(data):
"""Пользовательский обработчик события"""
print(data) # Печатаем полученные данные
if __name__ == '__main__': # Точка входа при запуске этого скрипта
# qpProvider = qp.QuikPy() # Вызываем конструктор QuikPy с подключением к локальному компьютеру с QUIK
qpProvider = qp.QuikPy(Host='192.168.1.7') # Вызываем конструктор QuikPy с подключением к удаленному компьютеру с QUIK
print(f'Подключено к терминалу QUIK по адресу: {qpProvider.Host}:{qpProvider.RequestsPort},{qpProvider.CallbacksPort}')
# QuikPy - Singleton класс. Будет создан 1 экземпляр класса, на него будут все ссылки
# qpProvider2 = qp.QuikPy()
qpProvider2 = qp.QuikPy(Host='192.168.1.7') # QuikPy - это Singleton класс. При попытке создания нового экземпляра получим ссылку на уже имеющийся экземпляр
print(f'Экземпляры класса совпадают: {qpProvider2 == qpProvider}')
# Проверка соединения
print(f'Терминал QUIK подключен к серверу: {qpProvider.IsConnected()["data"] == 1}')
print(f'Отклик QUIK на команду Ping: {qpProvider.Ping()["data"]}')
# Сервисные функции
print(f'Дата на сервере: {qpProvider.GetInfoParam("TRADEDATE")["data"]}')
print(f'Время на сервере: {qpProvider.GetInfoParam("SERVERTIME")["data"]}')
msg = 'Hello from Python!'
print(f'Отправка сообщения в QUIK: {msg}{qpProvider.MessageInfo(msg)["data"]}')
# Просмотр изменений параметров
qpProvider.OnParam = PrintCallback # Текущие параметры изменяются постоянно. Будем их смотреть, пока не нажмем Enter в консоли
# Выход
input('Enter - выход')
qpProvider.CloseConnectionAndThread() # Перед выходом закрываем соединение и поток QuikPy из любого экземпляра

125
Examples/02 - Accounts.py Normal file
View File

@@ -0,0 +1,125 @@
from QuikPy import QuikPy as qp # QuikPy = Работа с Quik из Python через LUA скрипты QuikSharp
def GetAllAccounts():
"""Получение всех торговых счетов"""
classCodes = qpProvider.GetClassesList()['data'] # Список классов
classCodesList = classCodes[:-1].split(',') # Удаляем последнюю запятую, разбиваем значения по запятой
tradeAccounts = qpProvider.GetTradeAccounts()['data'] # Все торговые счета
moneyLimits = qpProvider.GetMoneyLimits()['data'] # Все денежные лимиты (остатки на счетах)
depoLimits = qpProvider.GetAllDepoLimits()['data'] # Все лимиты по бумагам (позиции по инструментам)
orders = qpProvider.GetAllOrders()['data'] # Все заявки
stopOrders = qpProvider.GetAllStopOrders()['data'] # Все стоп заявки
# Коды клиента / Фирмы / Счета
for tradeAccount in tradeAccounts: # Пробегаемся по всем счетам
firmId = tradeAccount['firmid'] # Фирма
tradeAccountId = tradeAccount['trdaccid'] # Счет
distinctClientCode = list(set([moneyLimit['client_code'] for moneyLimit in moneyLimits if moneyLimit['firmid'] == firmId])) # Уникальные коды клиента по фирме
print(f'Код клиента {distinctClientCode[0] if distinctClientCode else "не задан"}, Фирма {firmId}, Счет {tradeAccountId} ({tradeAccount["description"]})')
tradeAccountClassCodes = tradeAccount['class_codes'][1:-1].split('|') # Классы торгового счета. Удаляем последнюю вертикальную черту, разбиваем значения по вертикальной черте
intersectionClassCodes = list(set(tradeAccountClassCodes).intersection(classCodesList)) # Классы, которые есть и в списке и в торговом счете
# Классы
for classCode in intersectionClassCodes: # Пробегаемся по всем общим классам
classInfo = qpProvider.GetClassInfo(classCode)['data'] # Информация о классе
print(f'- Класс {classCode} ({classInfo["name"]}), Тикеров {classInfo["nsecs"]}')
# Инструменты. Если выводить на экран, то занимают много места. Поэтому, закомментировали
# classSecurities = qpProvider.GetClassSecurities(classCode)['data'][:-1].split(',') # Список инструментов класса. Удаляем последнюю запятую, разбиваем значения по запятой
# print(f' - Тикеры ({classSecurities})')
if firmId == 'SPBFUT': # Для фьючерсов свои расчеты
# Лимиты
print(f'- Фьючерсный лимит {qpProvider.GetFuturesLimit(firmId, tradeAccountId, 0, "SUR")["data"]["cbplimit"]} SUR')
# Позиции
futuresHoldings = qpProvider.GetFuturesHoldings()['data'] # Все фьючерсные позиции
activeFuturesHoldings = [futuresHolding for futuresHolding in futuresHoldings if futuresHolding['totalnet'] != 0] # Активные фьючерсные позиции
for activeFuturesHolding in activeFuturesHoldings:
print(f' - Фьючерсная позиция {activeFuturesHolding["sec_code"]} {activeFuturesHolding["totalnet"]} @ {activeFuturesHolding["cbplused"]}')
else: # Для остальных фирм
# Лимиты
firmMoneyLimits = [moneyLimit for moneyLimit in moneyLimits if moneyLimit['firmid'] == firmId] # Денежные лимиты по фирме
for firmMoneyLimit in firmMoneyLimits: # Пробегаемся по всем денежным лимитам
limitKind = firmMoneyLimit['limit_kind'] # День лимита
print(f'- Денежный лимит {firmMoneyLimit["tag"]} на T{limitKind}: {firmMoneyLimit["currentbal"]} {firmMoneyLimit["currcode"]}')
# Позиции
firmKindDepoLimits = [depoLimit for depoLimit in depoLimits if depoLimit['firmid'] == firmId and depoLimit['limit_kind'] == limitKind and depoLimit['currentbal'] != 0] # Берем только открытые позиции по фирме и дню
for firmKindDepoLimit in firmKindDepoLimits: # Пробегаемся по всем позициям
secCode = firmKindDepoLimit["sec_code"] # Код тикера
classCode = qpProvider.GetSecurityClass(classCodes, secCode)['data']
entryPrice = float(firmKindDepoLimit["wa_position_price"])
lastPrice = float(qpProvider.GetParamEx(classCode, secCode, 'LAST')['data']['param_value']) # Последняя цена сделки
if classCode == 'TQOB': # Для рынка облигаций
lastPrice *= 10 # Умножаем на 10
print(f' - Позиция {classCode}.{secCode} {firmKindDepoLimit["currentbal"]} @ {entryPrice:.2f}/{lastPrice:.2f}')
# Заявки
firmOrders = [order for order in orders if order['firmid'] == firmId and order['flags'] & 0b1 == 0b1] # Активные заявки по фирме
for firmOrder in firmOrders: # Пробегаемся по всем заявка
isBuy = firmOrder['flags'] & 0b100 != 0b100 # Заявка на покупку
print(f'- Заявка номер {firmOrder["order_num"]} {"Покупка" if isBuy else "Продажа"} {firmOrder["class_code"]}.{firmOrder["sec_code"]} {firmOrder["qty"]} @ {firmOrder["price"]}')
# Стоп заявки
firmStopOrders = [stopOrder for stopOrder in stopOrders if stopOrder['firmid'] == firmId and stopOrder['flags'] & 0b1 == 0b1] # Активные стоп заявки по фирме
for firmStopOrder in firmStopOrders: # Пробегаемся по всем стоп заявкам
isBuy = firmStopOrder['flags'] & 0b100 != 0b100 # Заявка на покупку
print(f'- Стоп заявка номер {firmStopOrder["order_num"]} {"Покупка" if isBuy else "Продажа"} {firmStopOrder["class_code"]}.{firmStopOrder["sec_code"]} {firmStopOrder["qty"]} @ {firmStopOrder["price"]}')
def GetAccount(ClientCode='', FirmId='SPBFUT', TradeAccountId='SPBFUT00PST', LimitKind=0, CurrencyCode='SUR'):
"""Получение торгового счета. По умолчанию, выдается счет срочного рынка"""
classCodes = qpProvider.GetClassesList()['data'] # Список классов
moneyLimits = qpProvider.GetMoneyLimits()['data'] # Все денежные лимиты (остатки на счетах)
depoLimits = qpProvider.GetAllDepoLimits()['data'] # Все лимиты по бумагам (позиции по инструментам)
orders = qpProvider.GetAllOrders()['data'] # Все заявки
stopOrders = qpProvider.GetAllStopOrders()['data'] # Все стоп заявки
print(f'Код клиента {ClientCode}, Фирма {FirmId}, Счет {TradeAccountId}, T{LimitKind}, {CurrencyCode}')
if FirmId == 'SPBFUT': # Для фьючерсов свои расчеты
print(f'- Фьючерсный лимит {qpProvider.GetFuturesLimit(FirmId, TradeAccountId, 0, "SUR")["data"]["cbplimit"]} SUR')
futuresHoldings = qpProvider.GetFuturesHoldings()['data'] # Все фьючерсные позиции
activeFuturesHoldings = [futuresHolding for futuresHolding in futuresHoldings if futuresHolding['totalnet'] != 0] # Активные фьючерсные позиции
for activeFuturesHolding in activeFuturesHoldings:
print(f'- Фьючерсная позиция {activeFuturesHolding["sec_code"]} {activeFuturesHolding["totalnet"]} @ {activeFuturesHolding["cbplused"]}')
else: # Для остальных фирм
accountMoneyLimit = [moneyLimit for moneyLimit in moneyLimits # Денежный лимит
if moneyLimit['client_code'] == ClientCode and # Выбираем по коду клиента
moneyLimit['firmid'] == FirmId and # Фирме
moneyLimit['limit_kind'] == LimitKind and # Дню лимита
moneyLimit["currcode"] == CurrencyCode][0] # Валюте
print(f'- Денежный лимит {accountMoneyLimit["currentbal"]}')
accountDepoLimits = [depoLimit for depoLimit in depoLimits # Бумажный лимит
if depoLimit['client_code'] == ClientCode and # Выбираем по коду клиента
depoLimit['firmid'] == FirmId and # Фирме
depoLimit['limit_kind'] == LimitKind and # Дню лимита
depoLimit['currentbal'] != 0] # Берем только открытые позиции по фирме и дню
for firmKindDepoLimit in accountDepoLimits: # Пробегаемся по всем позициям
secCode = firmKindDepoLimit["sec_code"] # Код тикера
entryPrice = float(firmKindDepoLimit["wa_position_price"])
classCode = qpProvider.GetSecurityClass(classCodes, secCode)['data']
lastPrice = float(qpProvider.GetParamEx(classCode, secCode, 'LAST')['data']['param_value']) # Последняя цена сделки
if classCode == 'TQOB': # Для рынка облигаций
lastPrice *= 10 # Умножаем на 10
print(f'- Позиция {classCode}.{secCode} {firmKindDepoLimit["currentbal"]} @ {entryPrice:.2f}/{lastPrice:.2f}')
accountOrders = [order for order in orders # Заявки
if (order['client_code'] == ClientCode or ClientCode == '') and # Выбираем по коду клиента
order['firmid'] == FirmId and # Фирме
order['account'] == TradeAccountId and # Счету
order['flags'] & 0b1 == 0b1] # Активные заявки
for accountOrder in accountOrders: # Пробегаемся по всем заявка
isBuy = accountOrder['flags'] & 0b100 != 0b100 # Заявка на покупку
print(f'- Заявка номер {accountOrder["order_num"]} {"Покупка" if isBuy else "Продажа"} {accountOrder["class_code"]}.{accountOrder["sec_code"]} {accountOrder["qty"]} @ {accountOrder["price"]}')
accountStopOrders = [stopOrder for stopOrder in stopOrders # Стоп заявки
if (stopOrder['client_code'] == ClientCode or ClientCode == '') and # Выбираем по коду клиента
stopOrder['firmid'] == FirmId and # Фирме
stopOrder['account'] == TradeAccountId and # Счету
stopOrder['flags'] & 0b1 == 0b1] # Активные стоп заявки
for accountStopOrder in accountStopOrders: # Пробегаемся по всем стоп заявкам
isBuy = accountStopOrder['flags'] & 0b100 != 0b100 # Заявка на покупку
print(f'- Стоп заявка номер {accountStopOrder["order_num"]} {"Покупка" if isBuy else "Продажа"} {accountStopOrder["class_code"]}.{accountStopOrder["sec_code"]} {accountStopOrder["qty"]} @ {accountStopOrder["price"]}')
if __name__ == '__main__': # Точка входа при запуске этого скрипта
# qpProvider = qp.QuikPy() # Вызываем конструктор QuikPy с подключением к локальному компьютеру с QUIK
qpProvider = qp.QuikPy(Host='192.168.1.7') # Вызываем конструктор QuikPy с подключением к удаленному компьютеру с QUIK
GetAllAccounts() # Получаем все счета. По ним можно будет сформировать список счетов для торговли
print()
GetAccount() # Российские фьючерсы и опционы (счет по умолчанию)
# Выход
qpProvider.CloseConnectionAndThread() # Перед выходом закрываем соединение и поток QuikPy из любого экземпляра

38
Examples/03 - Ticker.py Normal file
View File

@@ -0,0 +1,38 @@
from datetime import datetime
from QuikPy import QuikPy as qp # QuikPy = Работа с Quik из Python через LUA скрипты QuikSharp
if __name__ == '__main__': # Точка входа при запуске этого скрипта
# qpProvider = qp.QuikPy() # Вызываем конструктор QuikPy с подключением к локальному компьютеру с QUIK
qpProvider = qp.QuikPy(Host='192.168.1.7') # Вызываем конструктор QuikPy с подключением к удаленному компьютеру с QUIK
firmId = 'MC0063100000' # Фирма
classCode = 'TQBR' # Класс тикера
secCode = 'GAZP' # Тикер
# firmId = 'SPBFUT' # Фирма
# classCode = 'SPBFUT' # Класс тикера
# secCode = 'SiH1' # Для фьючерсов: <Код тикера><Месяц экспирации: 3-H, 6-M, 9-U, 12-Z><Последняя цифра года>
# Данные тикера и его торговый счет
securityInfo = qpProvider.GetSecurityInfo(classCode, secCode)["data"]
print(f'Информация о тикере {classCode}.{secCode} ({securityInfo["short_name"]}):')
print(f'Валюта: {securityInfo["face_unit"]}')
print(f'Кол-во десятичных знаков: {securityInfo["scale"]}')
print(f'Лот: {securityInfo["lot_size"]}')
print(f'Шаг цены: {securityInfo["min_price_step"]}')
print(f'Торговый счет для тикера класса {classCode}: {qpProvider.GetTradeAccount(classCode)["data"]}')
# Свечки
print(f'5-и минутные свечки {classCode}.{secCode}:')
bars = qpProvider.GetCandlesFromDataSource(classCode, secCode, 5, 0)["data"] # 5 минут, 0 = все свечки
print(bars)
# print(f'Дневные свечки {classCode}.{secCode}:')
# bars = qpProvider.GetCandlesFromDataSource(classCode, secCode, 1440, 0)['data'] # 1440 минут = 1 день, 0 = все свечки
# dtjs = [row['datetime'] for row in bars] # Получаем исходники даты и времени начала свчки (List comprehensions)
# dts = [datetime(dtj['year'], dtj['month'], dtj['day'], dtj['hour'], dtj['min']) for dtj in dtjs] # Получаем дату и время
# print(dts)
# Выход
qpProvider.CloseConnectionAndThread() # Перед выходом закрываем соединение и поток QuikPy из любого экземпляра

51
Examples/04 - Stream.py Normal file
View File

@@ -0,0 +1,51 @@
import time # Подписка на события по времени
from QuikPy import QuikPy as qp # QuikPy = Работа с Quik из Python через LUA скрипты QuikSharp
def PrintCallback(data):
"""Пользовательский обработчик событий:
- Изменение стакана котировок
- Получение обезличенной сделки
- Получение новой свечки
"""
print(data['data']) # Печатаем полученные данные
if __name__ == '__main__': # Точка входа при запуске этого скрипта
# qpProvider = qp.QuikPy() # Вызываем конструктор QuikPy с подключением к локальному компьютеру с QUIK
qpProvider = qp.QuikPy(Host='192.168.1.7') # Вызываем конструктор QuikPy с подключением к удаленному компьютеру с QUIK
firmId = 'MC0063100000' # Фирма
classCode = 'TQBR' # Класс тикера
secCode = 'GAZP' # Тикер
# firmId = 'SPBFUT' # Фирма
# classCode = 'SPBFUT' # Класс тикера
# secCode = 'SiH1' # Для фьючерсов: <Код тикера><Месяц экспирации: 3-H, 6-M, 9-U, 12-Z><Последняя цифра года>
# Стакан
print(f'Текущий стакан {classCode}.{secCode}: {qpProvider.GetQuoteLevel2(classCode, secCode)}')
qpProvider.OnQuote = PrintCallback # Обработчик изменения стакана котировок
print(f'Подписка на стакан {classCode}.{secCode}: {qpProvider.SubscribeLevel2Quotes(classCode, secCode)["data"]}')
sleepSec = 1 # Кол-во секунд получения котировок
print(f'{sleepSec} секунд котировок')
time.sleep(sleepSec) # Ждем кол-во секунд получения котировок
print(f'Отмена подписки на стакан: {qpProvider.UnsubscribeLevel2Quotes(classCode, secCode)["data"]}')
print(f'Статус подписки: {qpProvider.IsSubscribedLevel2Quotes(classCode, secCode)["data"]}')
qpProvider.OnQuote = qpProvider.DefaultHandler # Возвращаем обработчик по умолчанию
# Обезличенные сделки. Чтобы получать, в QUIK открыть Таблицу обезличенных сделок, указать тикер
qpProvider.OnAllTrade = PrintCallback # Обработчик получения обезличенной сделки
sleepSec = 3 # Кол-во секунд получения обезличенных сделок
print(f'{sleepSec} секунд обезличенных сделок')
time.sleep(sleepSec) # Ждем кол-во секунд получения обезличенных сделок
qpProvider.OnAllTrade = qpProvider.DefaultHandler # Возвращаем обработчик по умолчанию
# Подписка на новые свечки
qpProvider.OnNewCandle = PrintCallback # Обработчик получения новой свечки - В первый раз получим все свечки с начала прошлой сессии
print(f'Подписка на минутные свечки {qpProvider.SubscribeToCandles(classCode, secCode, 1)["data"]}')
input('Enter - отмена')
print(f'Отмена подписки на минутные свечки {qpProvider.UnsubscribeFromCandles(classCode, secCode, 1)["data"]}')
qpProvider.OnNewCandle = qpProvider.DefaultHandler # Возвращаем обработчик по умолчанию
# Выход
qpProvider.CloseConnectionAndThread() # Перед выходом закрываем соединение и поток QuikPy из любого экземпляра

View File

@@ -0,0 +1,90 @@
from QuikPy import QuikPy as qp # QuikPy = Работа с Quik из Python через LUA скрипты QuikSharp
def OnTransReply(data):
"""Обработчик события ответа на транзакцию пользователя"""
print('OnTransReply')
print(data['data']) # Печатаем полученные данные
def OnOrder(data):
"""Обработчик события получения новой / изменения существующей заявки"""
print('OnOrder')
print(data['data']) # Печатаем полученные данные
def OnTrade(data):
"""Обработчик события получения новой / изменения существующей сделки
Не вызывается при закрытии сделки
"""
print('OnTrade')
print(data['data']) # Печатаем полученные данные
def OnFuturesClientHolding(data):
"""Обработчик события изменения позиции по срочному рынку"""
print('OnFuturesClientHolding')
print(data['data']) # Печатаем полученные данные
def OnDepoLimit(data):
"""Обработчик события изменения позиции по инструментам"""
print('OnDepoLimit')
print(data['data']) # Печатаем полученные данные
def OnDepoLimitDelete(data):
"""Обработчик события удаления позиции по инструментам"""
print('OnDepoLimitDelete')
print(data['data']) # Печатаем полученные данные
if __name__ == '__main__': # Точка входа при запуске этого скрипта
# qpProvider = qp.QuikPy() # Вызываем конструктор QuikPy с подключением к локальному компьютеру с QUIK
qpProvider = qp.QuikPy(Host='192.168.1.7') # Вызываем конструктор QuikPy с подключением к удаленному компьютеру с QUIK
qpProvider.OnTransReply = OnTransReply # Ответ на транзакцию пользователя. Если транзакция выполняется из QUIK, то не вызывается
qpProvider.OnOrder = OnOrder # Получение новой / изменение существующей заявки
qpProvider.OnTrade = OnTrade # Получение новой / изменение существующей сделки
qpProvider.OnFuturesClientHolding = OnFuturesClientHolding # Изменение позиции по срочному рынку
qpProvider.OnDepoLimit = OnDepoLimit # Изменение позиции по инструментам
qpProvider.OnDepoLimitDelete = OnDepoLimitDelete # Удаление позиции по инструментам
TransId = 12345 # Номер транзакции
price = 74550 # Цена входа/выхода
quantity = 1 # Кол-во в лотах
# Новая лимитная/рыночная заявка
transaction = { # Все значения должны передаваться в виде строк
'TRANS_ID': str(TransId), # Номер транзакции задается клиентом
'CLIENT_CODE': '', # Код клиента. Для фьючерсов его нет
'ACCOUNT': 'SPBFUT00PST', # Счет
'ACTION': 'NEW_ORDER', # Тип заявки: Новая лимитная/рыночная заявка
'CLASSCODE': 'SPBFUT', # Код площадки
'SECCODE': 'SiH1', # Код тикера
'OPERATION': 'S', # B = покупка, S = продажа
'PRICE': str(price), # Цена исполнения. Для рыночных фьючерсных заявок наихудшая цена в зависимости от направления. Для остальных рыночных заявок цена = 0
'QUANTITY': str(quantity), # Кол-во в лотах
'TYPE': 'L'} # L = лимитная заявка (по умолчанию), M = рыночная заявка
print(f'Новая лимитная/рыночная заявка отправлена на рынок: {qpProvider.SendTransaction(transaction)["data"]}')
# Новая стоп заявка
# transaction = { # Все значения должны передаваться в виде строк
# 'TRANS_ID': str(TransId), # Номер транзакции задается клиентом
# 'CLIENT_CODE': '', # Код клиента. Для фьючерсов его нет
# 'ACCOUNT': 'SPBFUT00PST', # Счет
# 'ACTION': 'NEW_STOP_ORDER', # Тип заявки: Новая стоп заявка
# 'CLASSCODE': 'SPBFUT', # Код площадки
# 'SECCODE': 'SiH1', # Код тикера
# 'OPERATION': 'B', # B = покупка, S = продажа
# 'PRICE': str(price), # Цена исполнения
# 'QUANTITY': str(quantity), # Кол-во в лотах
# 'STOPPRICE': str(price), # Стоп цена исполнения
# 'EXPIRY_DATE': 'GTC'} # Срок действия до отмены
# print(f'Новая стоп заявка отправлена на рынок: {qpProvider.SendTransaction(transaction)["data"]}')
# Удаление существующей заявки
# orderNum = 1234567890123456789 # 19-и значный номер заявки
# transaction = {
# 'TRANS_ID': str(TransId), # Номер транзакции задается клиентом
# 'ACTION': 'KILL_ORDER', # Тип заявки: Удаление существующей заявки
# 'CLASSCODE': 'SPBFUT', # Код площадки
# 'SECCODE': 'SiH1', # Код тикера
# 'ORDER_KEY': str(orderNum)} # Номер заявки
# print(f'Удаление заявки отправлено на рынок: {qpProvider.SendTransaction(transaction)["data"]}')
input('Enter - отмена') # Ждем исполнение заявки
qpProvider.CloseConnectionAndThread() # Перед выходом закрываем соединение и поток QuikPy из любого экземпляра