/
CountZero
/
quik-cscalp-lua
Обзор
Документация
Войти
/
CountZero
/
quik-cscalp-lua
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
qsfunctions.lua
1 295 строк
47 KB
CountZero
Update
05 авг 2026, 20:59
05 авг 2026, 20:59
500bdaf
Код
Авторство
О чём код?
--~ // Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information. local json = require("dkjson") local BridgeModule = require("qsbridge") local qsfunctions = {} local bridge = BridgeModule.instance() local function traceback(error_value) if debug and type(debug.traceback) == "function" then return debug.traceback(tostring(error_value), 2) end return tostring(error_value) end local function error_response(msg, error_text, command) msg.cmd = command or "lua_error" msg.lua_error = "Lua error: " .. tostring(error_text) return msg end local function split_request(value, expected) if type(value) ~= "string" then return nil, "request data must be a string" end local parts = split(value, "|") if expected and #parts < expected then return nil, "expected at least " .. tostring(expected) .. " pipe-delimited fields" end return parts end local function require_class_ready(msg, class_code, operation) local ready, ready_error = bridge:require_ready(operation) if not ready then return nil, error_response(msg, ready_error) end if not bridge.adapter:is_supported_class(class_code) then return nil, error_response(msg, "unsupported class: " .. tostring(class_code)) end return true end local function route_for_security(sec_code) local class_code = bridge:get_security_class(sec_code) if not class_code or class_code == "" then return nil, "cannot determine configured class for security " .. tostring(sec_code) end return bridge.adapter:route_for_class(class_code), nil, class_code end local function futures_route() local route = bridge.adapter:route_for_class("SPBFUT") if route then return route end for i = 1, #bridge.config.classes do local candidate = bridge.adapter:route_for_class(bridge.config.classes[i]) if candidate.class_code ~= bridge.config.cash_class then return candidate end end return nil end function qsfunctions.bridge() return bridge end function qsfunctions.dispatch_and_process(msg) if type(msg) ~= "table" or type(msg.cmd) ~= "string" then return error_response(type(msg) == "table" and msg or {}, "request must contain a string cmd") end local handler = qsfunctions[msg.cmd] if type(handler) ~= "function" then return error_response(msg, "command not implemented in Lua qsfunctions module: " .. msg.cmd) end bridge:housekeeping() local started_msec = timemsec() local status, result = xpcall(function() return handler(msg) end, traceback) local elapsed_msec = timemsec() - started_msec if elapsed_msec >= 5000 then log("Very slow request " .. tostring(msg.cmd) .. "; elapsed_msec=" .. tostring(elapsed_msec), "error") elseif elapsed_msec >= 1500 then log("Slow request " .. tostring(msg.cmd) .. "; elapsed_msec=" .. tostring(elapsed_msec), "warn") end if not status then log("Request handler failed for " .. tostring(msg.cmd) .. ": " .. tostring(result), "error") return error_response(msg, result) end return result end --------------------- -- Debug functions -- --------------------- --- Returns Pong to Ping -- @param msg message table -- @return same msg table function qsfunctions.ping(msg) -- need to know data structure the caller gives msg.t = 0 -- avoid time generation. Could also leave original if msg.data == "Ping" then msg.data = "Pong" return msg else msg.data = msg.data .. " is not Ping" return msg end end --- Echoes its message function qsfunctions.echo(msg) return msg end --- Test error handling function qsfunctions.divide_string_by_zero(msg) msg.data = "asd" / 0 return msg end --- Is running inside quik function qsfunctions.is_quik(msg) if getScriptPath then msg.data = 1 else msg.data = 0 end return msg end ----------------------- -- Service functions -- ----------------------- --- Функция предназначена для определения состояния подключения клиентского места к -- серверу. Возвращает «1», если клиентское место подключено и «0», если не подключено. function qsfunctions.isConnected(msg) msg.t = timemsec() msg.data = bridge.state == "READY" and 1 or 0 return msg end --#fsr (restored prev ver function) -- Функция предназначена для оповещения скрипта о том, что клиент собирается отсоединяться function qsfunctions.prepareToDisconnect(msg) bridge:on_local_disconnected("CScalp prepareToDisconnect") msg.data = true return msg end --- Функция возвращает путь, по которому находится файл info.exe, исполняющий данный -- скрипт, без завершающего обратного слэша («\»). Например, C:\QuikFront. function qsfunctions.getWorkingFolder(msg) -- set time when function was called msg.t = timemsec() msg.data = getWorkingFolder() return msg end --- Функция возвращает путь, по которому находится запускаемый скрипт, без завершающего -- обратного слэша («\»). Например, C:\QuikFront\Scripts. function qsfunctions.getScriptPath(msg) -- set time when function was called msg.t = timemsec() msg.data = getScriptPath() return msg end --- Функция возвращает значения параметров информационного окна (пункт меню -- Связь / Информационное окно…). function qsfunctions.getInfoParam(msg) -- set time when function was called msg.t = timemsec() msg.data = getInfoParam(msg.data) return msg end function qsfunctions.get_bridge_health(msg) msg.data = bridge:health() return msg end function qsfunctions.clear_reference_cache(msg) bridge:clear_reference_cache("CScalp command") msg.data = true return msg end function qsfunctions.refresh_reference_cache(msg) bridge:clear_reference_cache("CScalp refresh command") msg.data = true return msg end function qsfunctions.get_reference_cache_stats(msg) local health = bridge:health() msg.data = health.reference_cache or {} return msg end --- Функция отображает сообщения в терминале QUIK. function qsfunctions.message(msg) log(msg.data, 1) msg.data = "" return msg end function qsfunctions.warning_message(msg) log(msg.data, 2) msg.data = "" return msg end function qsfunctions.error_message(msg) log(msg.data, 3) msg.data = "" return msg end --- Функция приостанавливает выполнение скрипта. function qsfunctions.sleep(msg) delay(msg.data) msg.data = "" return msg end --- Функция для вывода отладочной информации. function qsfunctions.PrintDbgStr(msg) log(msg.data, 0) msg.data = "" return msg end -- Выводит на график метку function qsfunctions.addLabel(msg) local spl = split(msg.data, "|") local price, curdate, curtime, qty, path, id, algmnt, bgnd = spl[1], spl[2], spl[3], spl[4], spl[5], spl[6], spl[7], spl[8] local label = { TEXT = "", IMAGE_PATH = path, ALIGNMENT = algmnt, YVALUE = tostring(price), DATE = tostring(curdate), TIME = tostring(curtime), R = 255, G = 255, B = 255, TRANSPARENCY = 0, TRANSPARENT_BACKGROUND = bgnd, FONT_FACE_NAME = "Arial", FONT_HEIGHT = "15", HINT = " " .. tostring(price) .. " " .. tostring(qty) } local res = AddLabel(id, label) msg.data = res return msg end -- Удаляем выбранную метку function qsfunctions.delLabel(msg) local spl = split(msg.data, "|") local tag, id = spl[1], spl[2] DelLabel(tag, tonumber(id)) msg.data = "" return msg end -- Удаляем все метки с графика function qsfunctions.delAllLabels(msg) local spl = split(msg.data, "|") local id = spl[1] DelAllLabels(id) msg.data = "" return msg end --------------------- -- Class functions -- --------------------- --- Функция предназначена для получения списка кодов классов, переданных с сервера в ходе сеанса связи. function qsfunctions.getClassesList(msg) local value, value_error = bridge:get_classes_list() if value == nil then return error_response(msg, value_error) end msg.data = value return msg end --- Функция предназначена для получения информации о классе. function qsfunctions.getClassInfo(msg) local value, value_error = bridge:get_class_info(msg.data) if value == nil then return error_response(msg, value_error) end msg.data = value return msg end --- Функция предназначена для получения списка кодов бумаг для списка классов, заданного списком кодов. function qsfunctions.getClassSecurities(msg) local value, value_error = bridge:get_class_securities(msg.data) if value == nil then return error_response(msg, value_error) end msg.data = value return msg end --- Функция получает информацию по указанному классу и бумаге. function qsfunctions.getSecurityInfo(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local value, value_error = bridge:get_security_info(parts[1], parts[2]) if value == nil then return error_response(msg, value_error) end msg.data = value return msg end --- Функция берет на вход список из элементов в формате class_code|sec_code и возвращает список ответов функции getSecurityInfo. -- Если какая-то из бумаг не будет найдена, вместо ее значения придет null function qsfunctions.getSecurityInfoBulk(msg) if type(msg.data) ~= "table" then return error_response(msg, "bulk request data must be an array") end local result = {} for i = 1, #msg.data do local parts = split_request(msg.data[i], 2) local security = parts and bridge:get_security_info(parts[1], parts[2]) or nil result[#result + 1] = security or json.null end msg.data = result return msg end --- Функция предназначена для определения класса по коду инструмента из заданного списка классов. function qsfunctions.getSecurityClass(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local class_code, class_error = bridge:get_security_class(parts[2], parts[1]) if class_code == nil then return error_response(msg, class_error) end msg.data = class_code return msg end --- Функция возвращает код клиента function qsfunctions.getClientCode(msg) local ready, ready_error = bridge:require_ready("getClientCode") if not ready then return error_response(msg, ready_error) end msg.data = bridge.config.visible_account return msg end --#fsr (new function) -- Функция возвращает все коды клиента function qsfunctions.getClientCodes(msg) local ready, ready_error = bridge:require_ready("getClientCodes") if not ready then return error_response(msg, ready_error) end msg.data = bridge.adapter:virtual_client_codes() return msg end --- Функция возвращает торговый счет для запрашиваемого кода класса function qsfunctions.getTradeAccount(msg) local ready, ready_error = bridge:require_ready("getTradeAccount") if not ready then return error_response(msg, ready_error) end local account = bridge.adapter:trade_account_for_class(msg.data) if not account then return error_response(msg, "unsupported class: " .. tostring(msg.data)) end msg.data = account return msg end --- Функция возвращает торговые счета в системе, у которых указаны поддерживаемые классы инструментов. function qsfunctions.getTradeAccounts(msg) local ready, ready_error = bridge:require_ready("getTradeAccounts") if not ready then return error_response(msg, ready_error) end local real_accounts = {} local count = tonumber(getNumberOf("trade_accounts")) or 0 for i = 0, count - 1 do local account = getItem("trade_accounts", i) if type(account) == "table" then real_accounts[#real_accounts + 1] = account end end msg.data = bridge.adapter:build_virtual_trade_accounts(real_accounts) return msg end --------------------------------------------------------------------- -- Order Book functions (Функции для работы СЃРѕ стаканом котировок) -- --------------------------------------------------------------------- --- Функция заказывает на сервер получение стакана по указанному классу и бумаге. function qsfunctions.Subscribe_Level_II_Quotes(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local result, subscribe_error = bridge.market:subscribe_book(parts[1], parts[2], parts[3]) if not result then return error_response(msg, subscribe_error) end msg.data = true return msg end --- Функция отменяет заказ на получение с сервера стакана по указанному классу и бумаге. function qsfunctions.Unsubscribe_Level_II_Quotes(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end msg.data = bridge.market:unsubscribe_book( parts[1], parts[2], parts[3]) return msg end --- Функция позволяет узнать, заказан ли с сервера стакан по указанному классу и бумаге. function qsfunctions.IsSubscribed_Level_II_Quotes(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end msg.data = bridge.market:is_subscribed_book( parts[1], parts[2], parts[3]) return msg end --- Функция предназначена для получения стакана по указанному классу и инструменту. function qsfunctions.GetQuoteLevel2(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local quote, quote_error = bridge.market:get_quote(parts[1], parts[2]) if not quote then return error_response(msg, quote_error) end msg.data = quote return msg end ----------------------- -- Trading functions -- ----------------------- --- отправляет транзакцию на сервер и возвращает пустое сообщение, которое -- будет проигноировано. Вместо него, отправитель будет ждать события -- OnTransReply, из которого по TRANS_ID он получит результат отправленной транзакции function qsfunctions.sendTransaction(msg) local sent, send_error = bridge:send_transaction(msg.data) if not sent then msg.cmd = "lua_transaction_error" msg.lua_error = tostring(send_error) msg.data = false return msg end msg.data = true return msg end --- Функция заказывает получение параметров Таблицы текущих торгов. В случае успешного завершения функция возвращает «true», иначе – «false» function qsfunctions.paramRequest(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end local ok, blocked = require_class_ready(msg, parts[1], "paramRequest") if not ok then return blocked end msg.data = ParamRequest(parts[1], parts[2], parts[3]) return msg end --- Функция принимает список строк (JSON Array) в формате class_code|sec_code|param_name, вызывает функцию paramRequest для каждой строки. -- Возвращает список ответов в том же порядке function qsfunctions.paramRequestBulk(msg) if type(msg.data) ~= "table" then return error_response(msg, "bulk request data must be an array") end local result = {} for i = 1, #msg.data do local parts, parse_error = split_request(msg.data[i], 3) if not parts then return error_response(msg, parse_error) end local ok, blocked = require_class_ready(msg, parts[1], "paramRequestBulk") if not ok then return blocked end result[#result + 1] = ParamRequest(parts[1], parts[2], parts[3]) end msg.data = result return msg end --- Функция отменяет заказ на получение параметров Таблицы текущих торгов. В случае успешного завершения функция возвращает «true», иначе – «false» function qsfunctions.cancelParamRequest(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end if not bridge.adapter:is_supported_class(parts[1]) then return error_response(msg, "unsupported class: " .. tostring(parts[1])) end msg.data = CancelParamRequest(parts[1], parts[2], parts[3]) return msg end --- Функция принимает список строк (JSON Array) в формате class_code|sec_code|param_name, вызывает функцию CancelParamRequest для каждой строки. -- Возвращает список ответов в том же порядке function qsfunctions.cancelParamRequestBulk(msg) if type(msg.data) ~= "table" then return error_response(msg, "bulk request data must be an array") end local result = {} for i = 1, #msg.data do local parts, parse_error = split_request(msg.data[i], 3) if not parts then return error_response(msg, parse_error) end if not bridge.adapter:is_supported_class(parts[1]) then return error_response(msg, "unsupported class: " .. tostring(parts[1])) end result[#result + 1] = CancelParamRequest(parts[1], parts[2], parts[3]) end msg.data = result return msg end --- Функция предназначена для получения значений всех параметров биржевой информации из Таблицы текущих значений параметров. -- С помощью этой функции можно получить любое из значений Таблицы текущих значений параметров для заданных кодов класса и бумаги. function qsfunctions.getParamEx(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end local ok, blocked = require_class_ready(msg, parts[1], "getParamEx") if not ok then return blocked end msg.data = getParamEx(parts[1], parts[2], parts[3]) return msg end --- Функция предназначена для получения значении? всех параметров биржевои? информации из Таблицы текущих торгов -- с возможностью в дальнеи?шем отказаться от получения определенных параметров, заказанных с помощью функции ParamRequest. -- Для отказа от получения какого-либо параметра воспользуи?тесь функциеи? CancelParamRequest. -- Функция возвращает таблицу Lua с параметрами, аналогичными параметрам, возвращаемым функциеи? getParamEx function qsfunctions.getParamEx2(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end local ok, blocked = require_class_ready(msg, parts[1], "getParamEx2") if not ok then return blocked end msg.data = getParamEx2(parts[1], parts[2], parts[3]) return msg end --- Функция принимает список строк (JSON Array) в формате class_code|sec_code|param_name и возвращает результаты вызова -- функции getParamEx2 для каждой строки запроса в виде списка в таком же порядке, как в запросе function qsfunctions.getParamEx2Bulk(msg) if type(msg.data) ~= "table" then return error_response(msg, "bulk request data must be an array") end local result = {} for i = 1, #msg.data do local parts, parse_error = split_request(msg.data[i], 3) if not parts then return error_response(msg, parse_error) end local ok, blocked = require_class_ready(msg, parts[1], "getParamEx2Bulk") if not ok then return blocked end result[#result + 1] = getParamEx2(parts[1], parts[2], parts[3]) end msg.data = result return msg end -- Функция предназначена для получения информации по бумажным лимитам. function qsfunctions.getDepo(msg) local parts, parse_error = split_request(msg.data, 4) if not parts then return error_response(msg, parse_error) end local route, route_error = route_for_security(parts[3]) if not route then return error_response(msg, route_error) end local value = getDepo( route.client_code, parts[2], parts[3], route.trade_account) msg.data = value and bridge.adapter:virtualize_record_for_route( value, route, "getDepo") return msg end -- Функция предназначена для получения информации по бумажным лимитам. function qsfunctions.getDepoEx(msg) local parts, parse_error = split_request(msg.data, 5) if not parts then return error_response(msg, parse_error) end local route, route_error = route_for_security(parts[3]) if not route then return error_response(msg, route_error) end local value = getDepoEx( parts[1], route.client_code, parts[3], route.trade_account, tonumber(parts[5])) msg.data = value and bridge.adapter:virtualize_record_for_route( value, route, "getDepoEx") return msg end -- Функция для получения информации по денежным лимитам. function qsfunctions.getMoney(msg) local parts, parse_error = split_request(msg.data, 4) if not parts then return error_response(msg, parse_error) end local ready, ready_error = bridge:require_ready("getMoney") if not ready then return error_response(msg, ready_error) end local route = bridge.adapter:route_for_class(bridge.config.cash_class) if not route then return error_response(msg, "cash route is not configured: no route " .. "trade_account equals visible_account") end local value = getMoney(route.client_code, parts[2], parts[3], parts[4]) msg.data = value and bridge.adapter:virtualize_record_for_route( value, route, "getMoney") return msg end -- Функция для получения информации по денежным лимитам указанного типа. function qsfunctions.getMoneyEx(msg) local parts, parse_error = split_request(msg.data, 5) if not parts then return error_response(msg, parse_error) end local ready, ready_error = bridge:require_ready("getMoneyEx") if not ready then return error_response(msg, ready_error) end local route = bridge.adapter:route_for_class(bridge.config.cash_class) if not route then return error_response(msg, "cash route is not configured: no route " .. "trade_account equals visible_account") end local value = getMoneyEx( parts[1], route.client_code, parts[3], parts[4], tonumber(parts[5])) msg.data = value and bridge.adapter:virtualize_record_for_route( value, route, "getMoneyEx") return msg end -- Функция возвращает информацию по всем денежным лимитам. function qsfunctions.getMoneyLimits(msg) local ready, ready_error = bridge:require_ready("getMoneyLimits") if not ready then return error_response(msg, ready_error) end local limits = {} local count = tonumber(getNumberOf("money_limits")) or 0 for i = 0, count - 1 do local limit = getItem("money_limits", i) if type(limit) == "table" then limits[#limits + 1] = limit end end msg.data = bridge.adapter:virtualize_money_limits( limits, "getMoneyLimits") return msg end -- Функция предназначена для получения информации по фьючерсным лимитам. function qsfunctions.getFuturesLimit(msg) local parts, parse_error = split_request(msg.data, 4) if not parts then return error_response(msg, parse_error) end local ready, ready_error = bridge:require_ready("getFuturesLimit") if not ready then return error_response(msg, ready_error) end local route = futures_route() if not route then return error_response(msg, "no derivatives route is configured") end local result, result_error = getFuturesLimit( parts[1], route.trade_account, tonumber(parts[3]), parts[4]) if not result then return error_response(msg, result_error or "getFuturesLimit returned nil") end msg.data = bridge.adapter:virtualize_record_for_route( result, route, "getFuturesLimit") return msg end -- Функция возвращает информацию по фьючерсным лимитам для всех торговых счетов. function qsfunctions.getFuturesClientLimits(msg) local ready, ready_error = bridge:require_ready("getFuturesClientLimits") if not ready then return error_response(msg, ready_error) end local limits = {} local count = tonumber(getNumberOf("futures_client_limits")) or 0 for i = 0, count - 1 do local limit = getItem("futures_client_limits", i) if type(limit) == "table" and bridge.adapter:should_forward_record(limit) then limits[#limits + 1] = bridge.adapter:virtualize_record( limit, "getFuturesClientLimits") end end msg.data = limits return msg end function qsfunctions.getFuturesHolding(msg) local parts, parse_error = split_request(msg.data, 4) if not parts then return error_response(msg, parse_error) end local ready, ready_error = bridge:require_ready("getFuturesHolding") if not ready then return error_response(msg, ready_error) end local route = futures_route() if not route then return error_response(msg, "no derivatives route is configured") end local result = getFuturesHolding( parts[1], route.trade_account, parts[3], tonumber(parts[4])) msg.data = result and bridge.adapter:virtualize_record_for_route( result, route, "getFuturesHolding") return msg end --#fsr (new function) function qsfunctions.getFuturesHoldingsNotZero(msg) local ready, ready_error = bridge:require_ready("getFuturesHoldingsNotZero") if not ready then return error_response(msg, ready_error) end local count = tonumber(getNumberOf("FUTURES_CLIENT_HOLDING")) or 0 local holdings = {} for i = 0, count - 1 do local holding = getItem("FUTURES_CLIENT_HOLDING", i) if type(holding) == "table" and tonumber(holding.totalnet) ~= 0 and bridge.adapter:should_forward_record(holding) then holdings[#holdings + 1] = bridge.adapter:virtualize_record( holding, "getFuturesHoldingsNotZero") end end msg.data = holdings return msg end --#fsr (new function) function qsfunctions.getFuturesHoldings(msg) local ready, ready_error = bridge:require_ready("getFuturesHoldings") if not ready then return error_response(msg, ready_error) end local count = tonumber(getNumberOf("FUTURES_CLIENT_HOLDING")) or 0 local holdings = {} for i = 0, count - 1 do local holding = getItem("FUTURES_CLIENT_HOLDING", i) if type(holding) == "table" and bridge.adapter:should_forward_record(holding) then holdings[#holdings + 1] = bridge.adapter:virtualize_record( holding, "getFuturesHoldings") end end msg.data = holdings return msg end -- Функция возвращает таблицу заявок (всю или по заданному инструменту) function qsfunctions.get_orders(msg) local ready, ready_error = bridge:require_ready("get_orders") if not ready then return error_response(msg, ready_error) end local class_code, sec_code = nil, nil if msg.data ~= "" then local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end class_code, sec_code = parts[1], parts[2] if not bridge.adapter:is_supported_class(class_code) then return error_response(msg, "unsupported class: " .. tostring(class_code)) end end local orders = {} local count = tonumber(getNumberOf("orders")) or 0 for i = 0, count - 1 do local order = getItem("orders", i) if type(order) == "table" and (msg.data == "" or (order.class_code == class_code and order.sec_code == sec_code)) and bridge.adapter:should_forward_record(order) then orders[#orders + 1] = bridge.adapter:virtualize_record(order, "get_orders") end end msg.data = orders return msg end -- Функция возвращает заявку по заданному инструменту и ID-транзакции function qsfunctions.getOrder_by_ID(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end local ready, blocked = require_class_ready(msg, parts[1], "getOrder_by_ID") if not ready then return blocked end local best_order_num = 0 local result = nil local count = tonumber(getNumberOf("orders")) or 0 for i = 0, count - 1 do local order = getItem("orders", i) local numeric_order_num = type(order) == "table" and tonumber(order.order_num) or nil if type(order) == "table" and order.class_code == parts[1] and order.sec_code == parts[2] and tonumber(order.trans_id) == tonumber(parts[3]) and numeric_order_num and numeric_order_num > best_order_num then best_order_num = numeric_order_num result = order end end msg.data = result and bridge.adapter:virtualize_record( result, "getOrder_by_ID") return msg end ---- Функция возвращает заявку по номеру function qsfunctions.getOrder_by_Number(msg) local ready, ready_error = bridge:require_ready("getOrder_by_Number") if not ready then return error_response(msg, ready_error) end local requested = tonumber(msg.data) local count = tonumber(getNumberOf("orders")) or 0 for i = 0, count - 1 do local order = getItem("orders", i) if type(order) == "table" and tonumber(order.order_num) == requested and bridge.adapter:should_forward_record(order) then msg.data = bridge.adapter:virtualize_record( order, "getOrder_by_Number") return msg end end msg.data = nil return msg end --- Возвращает заявку по её номеру и классу инструмента --- --- На основе http://help.qlua.org/ch4_5_1_1.htm --- function qsfunctions.get_order_by_number(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local ready, blocked = require_class_ready(msg, parts[1], "get_order_by_number") if not ready then return blocked end local order = getOrderByNumber(parts[1], tonumber(parts[2])) msg.data = order and bridge.adapter:virtualize_record( order, "get_order_by_number") return msg end --- Возвращает список записей из таблицы 'Лимиты по бумагам' --- На основе http://help.qlua.org/ch4_6_11.htm и http://help.qlua.org/ch4_5_3.htm function qsfunctions.get_depo_limits(msg) local ready, ready_error = bridge:require_ready("get_depo_limits") if not ready then return error_response(msg, ready_error) end local sec_code = msg.data local count = tonumber(getNumberOf("depo_limits")) or 0 local limits = {} for i = 0, count - 1 do local limit = getItem("depo_limits", i) if type(limit) == "table" and (msg.data == "" or limit.sec_code == sec_code) and bridge.adapter:should_forward_record(limit) then limits[#limits + 1] = bridge.adapter:virtualize_record(limit, "get_depo_limits") end end msg.data = limits return msg end -- Функция возвращает таблицу сделок (всю или по заданному инструменту) function qsfunctions.get_trades(msg) local ready, ready_error = bridge:require_ready("get_trades") if not ready then return error_response(msg, ready_error) end local class_code, sec_code = nil, nil if msg.data ~= "" then local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end class_code, sec_code = parts[1], parts[2] if not bridge.adapter:is_supported_class(class_code) then return error_response(msg, "unsupported class: " .. tostring(class_code)) end end local trades = {} local count = tonumber(getNumberOf("trades")) or 0 for i = 0, count - 1 do local trade = getItem("trades", i) if type(trade) == "table" and (msg.data == "" or (trade.class_code == class_code and trade.sec_code == sec_code)) and bridge.adapter:should_forward_record(trade) then trades[#trades + 1] = bridge.adapter:virtualize_record(trade, "get_trades") end end msg.data = trades return msg end -- Функция возвращает таблицу сделок по номеру заявки function qsfunctions.get_Trades_by_OrderNumber(msg) local ready, ready_error = bridge:require_ready("get_Trades_by_OrderNumber") if not ready then return error_response(msg, ready_error) end local order_num = tonumber(msg.data) local trades = {} local count = tonumber(getNumberOf("trades")) or 0 for i = 0, count - 1 do local trade = getItem("trades", i) if type(trade) == "table" and tonumber(trade.order_num) == order_num and bridge.adapter:should_forward_record(trade) then trades[#trades + 1] = bridge.adapter:virtualize_record( trade, "get_Trades_by_OrderNumber") end end msg.data = trades return msg end -- Функция предназначена для получения значений параметров таблицы «Клиентский портфель», соответствующих идентификатору участника торгов «firmid» и коду клиента «client_code». function qsfunctions.getPortfolioInfo(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local ready, ready_error = bridge:require_ready("getPortfolioInfo") if not ready then return error_response(msg, ready_error) end local route = bridge.adapter:route_for_class(bridge.config.cash_class) if not route then return error_response(msg, "cash route is not configured: no route " .. "trade_account equals visible_account") end local result = getPortfolioInfo(parts[1], route.client_code) msg.data = result and bridge.adapter:virtualize_record_for_route( result, route, "getPortfolioInfo") return msg end -- Функция предназначена для получения значений параметров таблицы «Клиентский портфель», соответствующих идентификатору участника торгов «firmid», коду клиента «client_code» и виду лимита «limit_kind». function qsfunctions.getPortfolioInfoEx(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end local ready, ready_error = bridge:require_ready("getPortfolioInfoEx") if not ready then return error_response(msg, ready_error) end local route = bridge.adapter:route_for_class(bridge.config.cash_class) if not route then return error_response(msg, "cash route is not configured: no route " .. "trade_account equals visible_account") end local result = getPortfolioInfoEx( parts[1], route.client_code, tonumber(parts[3])) msg.data = result and bridge.adapter:virtualize_record_for_route( result, route, "getPortfolioInfoEx") return msg end -------------------------- -- OptionBoard functions -- -------------------------- local get_options function qsfunctions.getOptionBoard(msg) local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end local ready, blocked = require_class_ready(msg, parts[1], "getOptionBoard") if not ready then return blocked end local result = get_options(parts[1], parts[2]) msg.data = result return msg end get_options = function(classCode,secCode) --classCode = "SPBOPT" --BaseSecList="RIZ6" local SecList = getClassSecurities(classCode) --все сразу local t={} local p={} for sec in string.gmatch(SecList, "([^,]+)") do --перебираем опционы по очереди. local Optionbase=getParamEx(classCode,sec,"optionbase").param_image local Optiontype=getParamEx(classCode,sec,"optiontype").param_image if (string.find(secCode,Optionbase)~=nil) then p={ ["code"]=getParamEx(classCode,sec,"code").param_image, ["Name"]=getSecurityInfo(classCode,sec).name, ["DAYS_TO_MAT_DATE"]=getParamEx(classCode,sec,"DAYS_TO_MAT_DATE").param_value+0, ["BID"]=getParamEx(classCode,sec,"BID").param_value+0, ["OFFER"]=getParamEx(classCode,sec,"OFFER").param_value+0, ["OPTIONBASE"]=getParamEx(classCode,sec,"optionbase").param_image, ["OPTIONTYPE"]=getParamEx(classCode,sec,"optiontype").param_image, ["Longname"]=getParamEx(classCode,sec,"longname").param_image, ["shortname"]=getParamEx(classCode,sec,"shortname").param_image, ["Volatility"]=getParamEx(classCode,sec,"volatility").param_value+0, ["Strike"]=getParamEx(classCode,sec,"strike").param_value+0 } table.insert( t, p ) end end return t end -------------------------- -- Stop order functions -- -------------------------- --- Возвращает список стоп-заявок function qsfunctions.get_stop_orders(msg) local ready, ready_error = bridge:require_ready("get_stop_orders") if not ready then return error_response(msg, ready_error) end local class_code, sec_code = nil, nil if msg.data ~= "" then local parts, parse_error = split_request(msg.data, 2) if not parts then return error_response(msg, parse_error) end class_code, sec_code = parts[1], parts[2] if not bridge.adapter:is_supported_class(class_code) then return error_response(msg, "unsupported class: " .. tostring(class_code)) end end local count = tonumber(getNumberOf("stop_orders")) or 0 local stop_orders = {} for i = 0, count - 1 do local stop_order = getItem("stop_orders", i) if type(stop_order) == "table" and (msg.data == "" or (stop_order.class_code == class_code and stop_order.sec_code == sec_code)) and bridge.adapter:should_forward_record(stop_order) then stop_orders[#stop_orders + 1] = bridge.adapter:virtualize_record( stop_order, "get_stop_orders") end end msg.data = stop_orders return msg end ------------------------- --- Candles functions --- ------------------------- --- Возвращаем количество свечей по тегу function qsfunctions.get_num_candles(msg) local parts, parse_error = split_request(msg.data, 1) if not parts then return error_response(msg, parse_error) end msg.data = (tonumber(getNumCandles(parts[1])) or 0) return msg end --#fsr (minus log) --- Возвращаем все свечи по идентификатору графика. График должен быть открыт function qsfunctions.get_candles(msg) local parts, parse_error = split_request(msg.data, 4) if not parts then return error_response(msg, parse_error) end local tag = parts[1] local line = tonumber(parts[2]) local first_candle = tonumber(parts[3]) local count = tonumber(parts[4]) if not line or not first_candle or not count or count < 0 or count ~= math.floor(count) then return error_response(msg, "line, first candle and count must be valid numbers") end if count == 0 then count = tonumber(getNumCandles(tag)) or 0 end local source, returned_count = getCandlesByIndex( tag, line, first_candle, count) if type(source) ~= "table" then return error_response(msg, "getCandlesByIndex returned no table") end local candles = {} local available = math.min(count, tonumber(returned_count) or count) for i = 0, available - 1 do if source[i] ~= nil then candles[#candles + 1] = source[i] end end msg.data = candles return msg end --- Возвращаем все свечи по заданному инструменту и интервалу function qsfunctions.get_candles_from_data_source(msg) local parts, parse_error = split_request(msg.data, 4) if not parts then return error_response(msg, parse_error) end local candles, candle_error = bridge.market:get_candles_snapshot( parts[1], parts[2], tonumber(parts[3]), tonumber(parts[4]), 7000) if not candles then msg.cmd = "lua_create_data_source_error" msg.lua_error = tostring(candle_error) return msg end msg.data = candles return msg end function qsfunctions.subscribe_to_candles(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end local subscribed, subscribe_error = bridge.market:subscribe_candles( parts[1], parts[2], tonumber(parts[3]), parts[4]) if not subscribed then msg.cmd = "lua_create_data_source_error" msg.lua_error = tostring(subscribe_error) return msg end msg.data = true return msg end function qsfunctions.unsubscribe_from_candles(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end msg.data = bridge.market:unsubscribe_candles( parts[1], parts[2], tonumber(parts[3]), parts[4]) return msg end function qsfunctions.is_subscribed(msg) local parts, parse_error = split_request(msg.data, 3) if not parts then return error_response(msg, parse_error) end msg.data = bridge.market:is_subscribed_candles( parts[1], parts[2], tonumber(parts[3]), parts[4]) return msg end ------------------------- --- UCP functions --- ------------------------- --- Функция возвращает торговый счет срочного рынка, соответствующий коду клиента фондового рынка с единой денежной позицией function qsfunctions.GetTrdAccByClientCode(msg) local ready, ready_error = bridge:require_ready("GetTrdAccByClientCode") if not ready then return error_response(msg, ready_error) end msg.data = bridge.config.visible_account return msg end --- Функция возвращает код клиента фондового рынка с единой денежной позицией, соответствующий торговому счету срочного рынка function qsfunctions.GetClientCodeByTrdAcc(msg) local ready, ready_error = bridge:require_ready("GetClientCodeByTrdAcc") if not ready then return error_response(msg, ready_error) end msg.data = bridge.config.visible_account return msg end --- Функция предназначена для получения признака, указывающего имеет ли клиент единую денежную позицию function qsfunctions.IsUcpClient(msg) local ready, ready_error = bridge:require_ready("IsUcpClient") if not ready then return error_response(msg, ready_error) end local parts = split(msg.data or "", "|") msg.data = parts[2] == bridge.config.visible_account return msg end return qsfunctions