Блог им. TaurusGOLD
1.1. Структура листов:
📊 Котировки - текущие цены инструментов
🎯 Торговля - ручная отправка заявок
🤖 Автоторговля - автоматические стратегии
💼 Портфель - текущие позиции
⚙ Настройки - параметры подключения
📈 Графики - визуализация данных
A1: "НАСТРОЙКИ ПОДКЛЮЧЕНИЯ К QUIK" A3: "DDE Service:" B3: "QLUA" A4: "DDE Topic:" B4: "QuikTrans2" A5: "Торговый счет:" B5: "L01-00000F00" A6: "Клиентский код:" B6: "" A8: "СПИСОК ИНСТРУМЕНТОВ" A9: "Тикер" B9: "Название" C9: "Класс" D9: "Лот" A10: "GAZP" B10: "Газпром" C10: "TQBR" D10: "10" A11: "SBER" B11: "Сбербанк" C11: "TQBR" D11: "10" A12: "LKOH" B12: "Лукойл" C12: "TQBR" D12: "1" A13: "GMKN" B13: "Норникель" C13: "TQBR" D13: "1"
A1: "ТЕКУЩИЕ КОТИРОВКИ" A2: "Тикер" B2: "Послед." C2: "Бид" D2: "Оффер" E2: "Объем" F2: "Время" G2: "Изменение %"
A1: "РУЧНАЯ ТОРГОВЛЯ" A2: "Тикер" B2: "Операция" C2: "Кол-во лотов" D2: "Цена" E2: "Статус" F2: "ID заявки" G2: "Действие"
3.1. Откройте редактор VBA (ALT + F11)
3.2. Добавьте новый модуль и вставьте код:
' Модуль для торговли через QUIK DDE
Option Explicit
' Константы подключения
Private Const QUIK_DDE_SERVICE As String = "QLUA"
Private Const QUIK_DDE_TOPIC As String = "QuikTrans2"
Private Const TRANS2_TABLE As String = "TRANS2"
' Глобальные переменные
Private ddeChannel As Long
Private isConnected As Boolean
' ==================== ОСНОВНЫЕ ФУНКЦИИ ====================
' Инициализация подключения к QUIK
Public Sub InitializeQUIKConnection()
On Error GoTo ErrorHandler
' Завершаем предыдущее подключение
If ddeChannel > 0 Then
DDETerminate ddeChannel
End If
' Инициируем DDE канал
ddeChannel = DDEInitiate(QUIK_DDE_SERVICE, QUIK_DDE_TOPIC)
If ddeChannel > 0 Then
isConnected = True
UpdateStatus "✅ Подключено к QUIK"
ThisWorkbook.Sheets("Настройки").Range("B1").Value = "ПОДКЛЮЧЕНО"
Else
isConnected = False
UpdateStatus "❌ Ошибка подключения к QUIK"
ThisWorkbook.Sheets("Настройки").Range("B1").Value = "ОШИБКА"
End If
Exit Sub
ErrorHandler:
UpdateStatus "Ошибка инициализации: " & Err.Description
End Sub
' Отправка лимитной заявки
Public Sub SendLimitOrder()
On Error GoTo ErrorHandler
If Not isConnected Then
InitializeQUIKConnection
If Not isConnected Then Exit Sub
End If
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Торговля")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 3 To lastRow ' Начинаем с строки 3 (после заголовков)
' Проверяем кнопку отправки
If ws.Cells(i, "G").Value = "ОТПРАВИТЬ" Then
Dim ticker As String, operation As String
Dim quantity As Long, price As Double
Dim classCode As String, account As String
' Получаем данные из строки
ticker = Trim(ws.Cells(i, "A").Value)
operation = UCase(Trim(ws.Cells(i, "B").Value))
quantity = ws.Cells(i, "C").Value
price = ws.Cells(i, "D").Value
' Получаем дополнительные параметры из настроек
classCode = GetClassCode(ticker)
account = GetSetting("Торговый счет")
If ticker = "" Or quantity <= 0 Or price <= 0 Then
ws.Cells(i, "E").Value = "ОШИБКА: Неверные данные"
ws.Cells(i, "G").Value = "ПОВТОРИТЬ"
GoTo NextRow
End If
' Отправляем транзакцию
Dim transId As String
transId = SendTransaction(ticker, classCode, operation, quantity, price, account)
If transId <> "" Then
ws.Cells(i, "E").Value = "ОТПРАВЛЕНО"
ws.Cells(i, "F").Value = transId
ws.Cells(i, "G").Value = "✅ ОТПРАВЛЕНО"
UpdateStatus "Заявка отправлена: " & ticker & " " & operation & " " & quantity & " @ " & price
Else
ws.Cells(i, "E").Value = "ОШИБКА ОТПРАВКИ"
ws.Cells(i, "G").Value = "ПОВТОРИТЬ"
End If
End If
NextRow:
Next i
Exit Sub
ErrorHandler:
UpdateStatus "Ошибка отправки заявки: " & Err.Description
End Sub
' Функция отправки транзакции в QUIK
Private Function SendTransaction(ticker As String, classCode As String, _
operation As String, quantity As Long, _
price As Double, account As String) As String
If ddeChannel <= 0 Then
SendTransaction = ""
Exit Function
End If
' Генерируем уникальный ID транзакции
Dim transId As String
transId = "XL" & Format(Now, "yymmddhhnnss")
' Формируем строку транзакции для таблицы TRANS2
Dim transData As String
transData = "CLASSCODE=" & classCode & ";" & _
"SECCODE=" & ticker & ";" & _
"ACTION=NEW_ORDER;" & _
"ACCOUNT=" & account & ";" & _
"OPERATION=" & operation & ";" & _
"PRICE=" & Format(price, "0.00") & ";" & _
"QUANTITY=" & quantity & ";" & _
"TYPE=L;" & _
"TRANS_ID=" & transId & ";" & _
"BROKERREF=EXCEL_TRADE"
' Отправляем через DDE
DDEPoke ddeChannel, TRANS2_TABLE, transData
SendTransaction = transId
End Function
' ==================== ПОЛУЧЕНИЕ ДАННЫХ ИЗ QUIK ====================
' Обновление котировок
Public Sub UpdateQuotes()
On Error GoTo ErrorHandler
If Not isConnected Then Exit Sub
Dim wsSettings As Worksheet, wsQuotes As Worksheet
Set wsSettings = ThisWorkbook.Sheets("Настройки")
Set wsQuotes = ThisWorkbook.Sheets("Котировки")
' Очищаем старые данные (кроме заголовков)
If wsQuotes.Cells(2, 1).Value <> "" Then
wsQuotes.Range("A3:G100").ClearContents
End If
Dim i As Long, rowCount As Long
rowCount = 0
' Проходим по списку инструментов из настроек
Dim lastRow As Long
lastRow = wsSettings.Cells(wsSettings.Rows.Count, "A").End(xlUp).Row
For i = 10 To lastRow ' Начинаем с строки 10 где список инструментов
Dim ticker As String
ticker = Trim(wsSettings.Cells(i, "A").Value)
If ticker = "" Then Exit For
' Получаем данные по инструменту
Dim lastPrice As String, bidPrice As String, askPrice As String
Dim volume As String, timeStamp As String
lastPrice = GetDDEValue(ticker, "LAST")
bidPrice = GetDDEValue(ticker, "BID")
askPrice = GetDDEValue(ticker, "OFFER")
volume = GetDDEValue(ticker, "VOLUME")
timeStamp = Format(Now, "hh:nn:ss")
' Записываем в таблицу котировок
rowCount = rowCount + 1
wsQuotes.Cells(2 + rowCount, 1).Value = ticker
wsQuotes.Cells(2 + rowCount, 2).Value = lastPrice
wsQuotes.Cells(2 + rowCount, 3).Value = bidPrice
wsQuotes.Cells(2 + rowCount, 4).Value = askPrice
wsQuotes.Cells(2 + rowCount, 5).Value = volume
wsQuotes.Cells(2 + rowCount, 6).Value = timeStamp
' Расчет изменения цены
If IsNumeric(lastPrice) Then
If rowCount > 1 Then
Dim prevPrice As Double
On Error Resume Next
prevPrice = wsQuotes.Cells(1 + rowCount, 2).Value
If prevPrice > 0 Then
Dim changePct As Double
changePct = (lastPrice - prevPrice) / prevPrice * 100
wsQuotes.Cells(2 + rowCount, 7).Value = changePct
' Раскрашиваем ячейку
If changePct > 0 Then
wsQuotes.Cells(2 + rowCount, 7).Interior.Color = RGB(200, 255, 200)
ElseIf changePct < 0 Then
wsQuotes.Cells(2 + rowCount, 7).Interior.Color = RGB(255, 200, 200)
End If
End If
End If
End If
Next i
UpdateStatus "Котировки обновлены: " & rowCount & " инструментов"
Exit Sub
ErrorHandler:
UpdateStatus "Ошибка обновления котировок: " & Err.Description
End Sub
' Получение значения через DDE
Private Function GetDDEValue(ticker As String, param As String) As String
On Error Resume Next
Dim value As String
value = DDERequest(ddeChannel, ticker & "|" & param)
If Err.Number <> 0 Then
GetDDEValue = "N/A"
Else
GetDDEValue = value
End If
End Function
' ==================== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ====================
' Получение класса инструмента
Private Function GetClassCode(ticker As String) As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Настройки")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 10 To lastRow
If Trim(ws.Cells(i, "A").Value) = ticker Then
GetClassCode = ws.Cells(i, "C").Value
Exit Function
End If
Next i
GetClassCode = "TQBR" ' По умолчанию для акций
End Function
' Получение настройки
Private Function GetSetting(settingName As String) As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Настройки")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 3 To lastRow
If ws.Cells(i, "A").Value = settingName Then
GetSetting = ws.Cells(i, "B").Value
Exit Function
End If
Next i
GetSetting = ""
End Function
' Обновление статуса
Private Sub UpdateStatus(message As String)
ThisWorkbook.Sheets("Торговля").Range("H1").Value = message
Debug.Print Format(Now, "hh:nn:ss") & " - " & message
End Sub
' ==================== АВТОМАТИЗАЦИЯ ====================
' Запуск автоматического обновления
Public Sub StartAutoUpdate()
UpdateStatus "Запуск автоматического обновления..."
' Обновляем котировки сразу
UpdateQuotes
' Запускаем периодическое обновление (каждые 10 секунд)
Application.OnTime Now + TimeValue("00:00:10"), "ScheduledUpdate"
End Sub
' Плановое обновление
Public Sub ScheduledUpdate()
On Error GoTo ErrorHandler
If ThisWorkbook.Sheets("Настройки").Range("B2").Value = "ДА" Then
UpdateQuotes
UpdatePortfolio
End If
' Планируем следующее обновление
Application.OnTime Now + TimeValue("00:00:10"), "ScheduledUpdate"
Exit Sub
ErrorHandler:
UpdateStatus "Ошибка планового обновления: " & Err.Description
Application.OnTime Now + TimeValue("00:00:30"), "ScheduledUpdate"
End Sub
' Остановка автоматического обновления
Public Sub StopAutoUpdate()
On Error Resume Next
Application.OnTime EarliestTime:=Now + TimeValue("00:00:01"), _
Procedure:="ScheduledUpdate", Schedule:=False
UpdateStatus "Автообновление остановлено"
End Sub
' Обновление портфеля
Public Sub UpdatePortfolio()
' Здесь можно добавить логику обновления позиций
' через DDE запросы к таблицам QUIK (depo_limits, money_limits)
End Sub
' ==================== ОБРАБОТЧИКИ СОБЫТИЙ ====================
' Автозапуск при открытии файла
Private Sub Workbook_Open()
UpdateStatus "Файл открыт. Для подключения к QUIK нажмите 'Подключиться'"
' Инициализируем интерфейс
InitializeInterface
End Sub
' Инициализация интерфейса
Private Sub InitializeInterface()
' Добавляем кнопки на лист торговли
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Торговля")
' Создаем заголовки если их нет
If ws.Range("A1").Value = "" Then
ws.Range("A1:G1").Value = Array("Тикер", "Операция", "Кол-во лотов", "Цена", "Статус", "ID заявки", "Действие")
End If
UpdateStatus "Готов к работе"
End Sub4.1. На листе «Торговля» создаем кнопки:
' В редакторе VBA добавьте этот код в модуль листа "Торговля"
' Кнопка "Подключиться к QUIK"
Private Sub btnConnect_Click()
InitializeQUIKConnection
End Sub
' Кнопка "Обновить котировки"
Private Sub btnUpdateQuotes_Click()
UpdateQuotes
End Sub
' Кнопка "Отправить заявки"
Private Sub btnSendOrders_Click()
SendLimitOrder
End Sub
' Кнопка "Автообновление ВКЛ"
Private Sub btnAutoOn_Click()
ThisWorkbook.Sheets("Настройки").Range("B2").Value = "ДА"
StartAutoUpdate
End Sub
' Кнопка "Автообновление ВЫКЛ"
Private Sub btnAutoOff_Click()
ThisWorkbook.Sheets("Настройки").Range("B2").Value = "НЕТ"
StopAutoUpdate
End Sub5.1. Первый запуск:
Откройте QUIK и подключитесь к брокеру
Откройте Excel файл
Нажмите «Подключиться к QUIK»
Проверьте статус подключения
5.2. Ручная торговля:
На листе «Торговля» введите:
Тикер (GAZP, SBER и т.д.)
Операция (BUY/SELL)
Кол-во лотов
Цену
Нажмите «ОТПРАВИТЬ» в столбце G
Следите за статусом в столбце E
5.3. Автоматическое обновление:
Включите автообновление для получения котировок каждые 10 секунд
Файл → Параметры → Центр управления безопасностью
Параметры макросов → Включить все макросы
Надежные издатели → Доверять доступ к объектной модели VBA
Сохраните как «Торговля ММВБ.xlsm» (с поддержкой макросов)
🚀 Тестируйте на демо-счете перед реальной торговлей.
