From 5bd01e908073e0d7a1a27cf1ea38605cea312bb9 Mon Sep 17 00:00:00 2001 From: DBoyara Date: Mon, 3 Mar 2025 15:02:39 +0500 Subject: [PATCH] subscibe to order bokk & correct OnQuote --- internal/quik/models.go | 8 +++++- internal/quik/requests.go | 26 ++++++++++++++++++ quik/init.lua | 55 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/internal/quik/models.go b/internal/quik/models.go index 51f4e8b..548bc1e 100644 --- a/internal/quik/models.go +++ b/internal/quik/models.go @@ -34,10 +34,16 @@ type DataSourceRequest struct { Interval int `json:"interval"` } +// SubscribeOrderBookRequest — данные для работы с DataSource. +type SubscribeOrderBookRequest struct { + ClassCode string `json:"class_code"` + SecCode string `json:"sec_code"` +} + // CreateDataSourceRequest — данные для создания DataSource. type CreateDataSourceRequest struct { DataSourceRequest - Class string `json:"class_code"` + ClassCode string `json:"class_code"` } // GetPortfolioRequest — данные для создания DataSource. diff --git a/internal/quik/requests.go b/internal/quik/requests.go index 3f69373..f84a1b6 100644 --- a/internal/quik/requests.go +++ b/internal/quik/requests.go @@ -86,6 +86,32 @@ func (q *QuikClient) CloseDataSource(data DataSourceRequest, ctx context.Context return nil } +func (q *QuikClient) SubscribeOrderBook(data SubscribeOrderBookRequest, ctx context.Context) error { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + request := getRequest() + defer putRequest(request) + + request.Cmd = "subscribeOrderBook" + request.Data = data + + q.logger.Debug("subscribe OrderBook request", zap.String("classCode", data.ClassCode), zap.String("ticker", data.SecCode)) + + response, err := q.client.sendRequest(ctx, request) + if err != nil { + return errors.Wrap(err, "failed to subscribe OrderBook") + } + + if !response.Success { + return fmt.Errorf("failed to subscribe OrderBook with message: %s", response.Message) + } + + q.logger.Debug("subscribe to OrderBook", zap.Bool("success", response.Success)) + + return nil +} + // GetCandles возвращает свечи из источника данных. func (q *QuikClient) GetCandles(data GetCandlesRequest, ctx context.Context) ([]Candle, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) diff --git a/quik/init.lua b/quik/init.lua index ad1c403..67a3d85 100644 --- a/quik/init.lua +++ b/quik/init.lua @@ -17,6 +17,7 @@ local response_server local response_client local is_connected = false local is_subscribed = false +local INTERVAL_TICKS = 1 -- Хранилище DataSource local data_sources = {} @@ -379,7 +380,17 @@ function OnTransReply(trans_reply) end function OnQuote(class_code, sec_code) - send_event("OnQuote", { class_code = class_code, sec_code = sec_code }) + local msg = {} + local status, ql2 = pcall(getQuoteLevel2, class_code, sec_code) + if status then + msg.data = ql2 + msg.data.class_code = class_code + msg.data.sec_code = sec_code + + send_event("OnQuote", msg) + else + log("Ошибка при получении стакана для " .. sec_code, 3) + end end function OnConnected() @@ -447,6 +458,46 @@ function OnInit(script_path) log("QUIK# is initialized from "..script_path, 0) end +-- Функция для подписки на обновления стакана котировок +function subscribe_to_order_book(class_code, sec_code) + local key = sec_code .. "|ORDERBOOK" + if data_sources[key] then + log("Подписка на стакан для " .. sec_code .. " уже существует.", 2) + return + end + + -- Создаем DataSource для стакана котировок + local ds, err = create_data_source(class_code, sec_code, INTERVAL_TICKS) + if not ds then + log("Ошибка при создании DataSource для стакана " .. sec_code .. ": " .. err, 3) + return + end + + -- Сохраняем DataSource в таблицу + data_sources[key] = ds + + -- Callback-функция для обработки обновлений стакана + function OnData(ds) + local msg = {} + local status, ql2 = pcall(getQuoteLevel2, class_code, sec_code) + if status then + msg.data = ql2 + msg.data.class_code = class_code + msg.data.sec_code = sec_code + + -- Отправляем данные клиенту + send_event("OrderBookUpdate", msg) + else + log("Ошибка при получении стакана для " .. sec_code, 3) + end + end + + -- Подписываемся на обновления + ds:SetUpdateCallback(OnData) + + log("Подписка на стакан для " .. sec_code .. " успешно создана.", 1) +end + -- Функция отправки событий function send_event(event_name, event_data) if not event_client then @@ -473,6 +524,8 @@ function process_request(request) return handle_create_data_source(request.data) elseif request.cmd == "closeDataSource" then return handle_close_data_source(request.data) + elseif request.cmd == "subscribeOrderBook" then + return subscribe_to_order_book(request.data.class_code, request.data.sec_code) elseif request.cmd == "getСandles" then return handle_get_candles(request.data) elseif request.cmd == "getTradeAccounts" then