Files
QuikPy/QUIK/lua/qsfunctions.lua

1082 lines
40 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
--~ Copyright (c) 2014-2020 QUIKSharp Authors https://github.com/finsight/QUIKSharp/blob/master/AUTHORS.md. All rights reserved.
--~ Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
local json = require ("dkjson")
local qsfunctions = {}
function qsfunctions.dispatch_and_process(msg)
if qsfunctions[msg.cmd] then
-- dispatch a command simply by a table lookup
-- in qsfunctions method names must match commands
local status, result = pcall(qsfunctions[msg.cmd], msg)
if status then
return result
else
msg.cmd = "lua_error"
msg.lua_error = "Lua error: " .. result
return msg
end
else
log(to_json(msg), 3)
msg.lua_error = "Command not implemented in Lua qsfunctions module: " .. msg.cmd
msg.cmd = "lua_error"
return msg
end
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)
-- set time when function was called
msg.t = timemsec()
msg.data = isConnected()
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
--- Функция отображает сообщения в терминале 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]
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
-- Выводит на график метку
-- Функция возвращает числовой идентификатор метки. В случае неуспешного завершения функция возвращает «nil».
function qsfunctions.addLabel2(msg)
local spl = split2(msg.data, "|");
local chartTag, yValue, strDate, strTime, text, imagePath, alignment, hint, r, g, b, transparency, tranBackgrnd, fontName, fontHeight =
spl[1], spl[2], spl[3], spl[4], spl[5], spl[6], spl[7], spl[8], spl[9], spl[10], spl[11], spl[12], spl[13], spl[14], spl[15];
-- значения по умолчанию
if text == "" then text = nil else r = 255 end
if imagePath == "" then imagePath = nil end
if alignment == "" then alignment = nil end
if hint == "" then hint = nil end
if r == "-1" then r = nil end
if g == "-1" then g = nil end
if b == "-1" then b = nil end
if transparency == "-1" then transparency = nil end
if tranBackgrnd == "-1" then tranBackgrnd = nil end
if fontName == "" then fontName = nil end
if fontHeight == "-1" then fontHeight = nil end
local labelParams = {
YVALUE = yValue:gsub(",", "."),
DATE = strDate,
TIME = strTime,
TEXT = text,
IMAGE_PATH = imagePath,
ALIGNMENT = alignment,
HINT = hint,
R = r,
G = g,
B = b,
TRANSPARENCY = transparency,
TRANSPARENT_BACKGROUND = tranBackgrnd,
FONT_FACE_NAME = fontName,
FONT_HEIGHT = fontHeight,
}
local res = AddLabel(chartTag, labelParams);
msg.data = res;
return msg;
end
-- Функция задает параметры для метки с указанным идентификатором.
-- В случае успешного завершения функция возвращает «true», иначе «false».
function qsfunctions.setLabelParams(msg)
local spl = split2(msg.data, "|");
local chartTag, labelId, yValue, strDate, strTime, text, imagePath, alignment, hint, r, g, b, transparency, tranBackgrnd, fontName, fontHeight =
spl[1], spl[2], spl[3], spl[4], spl[5], spl[6], spl[7], spl[8], spl[9], spl[10], spl[11], spl[12], spl[13], spl[14], spl[15], spl[16];
-- значения по умолчанию
if text == "" then text = nil else r = 255 end
if imagePath == "" then imagePath = nil end
if alignment == "" then alignment = nil end
if hint == "" then hint = nil end
if r == "-1" then r = nil end
if g == "-1" then g = nil end
if b == "-1" then b = nil end
if transparency == "-1" then transparency = nil end
if tranBackgrnd == "-1" then tranBackgrnd = nil end
if fontName == "" then fontName = nil end
if fontHeight == "-1" then fontHeight = nil end
local labelParams = {
YVALUE = yValue,
DATE = strDate,
TIME = strTime,
TEXT = text,
IMAGE_PATH = imagePath,
ALIGNMENT = alignment,
HINT = hint,
R = r,
G = g,
B = b,
TRANSPARENCY = transparency,
TRANSPARENT_BACKGROUND = tranBackgrnd,
FONT_FACE_NAME = fontName,
FONT_HEIGHT = fontHeight,
}
local res = SetLabelParams(chartTag, tonumber(labelId), labelParams);
msg.data = tostring(res);
return msg;
end
-- позволяет получить параметры метки
-- Функция возвращает таблицу с параметрами метки. В случае неуспешного завершения функция возвращает «nil».
function qsfunctions.getLabelParams(msg)
local spl = split2(msg.data, "|");
local chartTag, labelId = spl[1], spl[2];
local res = GetLabelParams(chartTag, tonumber(labelId));
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)
msg.data = getClassesList()
-- if msg.data then log(msg.data) else log("getClassesList returned nil") end
return msg
end
--- Функция предназначена для получения информации о классе.
function qsfunctions.getClassInfo(msg)
msg.data = getClassInfo(msg.data)
-- if msg.data then log(msg.data.name) else log("getClassInfo returned nil") end
return msg
end
--- Функция предназначена для получения списка кодов бумаг для списка классов, заданного списком кодов.
function qsfunctions.getClassSecurities(msg)
msg.data = getClassSecurities(msg.data)
-- if msg.data then log(msg.data) else log("getClassSecurities returned nil") end
return msg
end
--- Функция получает информацию по указанному классу и бумаге.
function qsfunctions.getSecurityInfo(msg)
local spl = split(msg.data, "|")
local class_code, sec_code = spl[1], spl[2]
msg.data = getSecurityInfo(class_code, sec_code)
return msg
end
--- Функция берет на вход список из элементов в формате class_code|sec_code и возвращает список ответов функции getSecurityInfo.
-- Если какая-то из бумаг не будет найдена, вместо ее значения придет null
function qsfunctions.getSecurityInfoBulk(msg)
local result = {}
for i=1,#msg.data do
local spl = split(msg.data[i], "|")
local class_code, sec_code = spl[1], spl[2]
local status, security = pcall(getSecurityInfo, class_code, sec_code)
if status and security then
table.insert(result, security)
else
if not status then
log("Error happened while calling getSecurityInfoBulk with ".. class_code .. "|".. sec_code .. ": ".. security)
end
table.insert(result, json.null)
end
end
msg.data = result
return msg
end
--- Функция предназначена для определения класса по коду инструмента из заданного списка классов.
function qsfunctions.getSecurityClass(msg)
local spl = split(msg.data, "|")
local classes_list, sec_code = spl[1], spl[2]
for class_code in string.gmatch(classes_list,"([^,]+)") do
if getSecurityInfo(class_code,sec_code) then
msg.data = class_code
return msg
end
end
msg.data = ""
return msg
end
--- Функция возвращает код клиента
function qsfunctions.getClientCode(msg)
for i=0,getNumberOf("MONEY_LIMITS")-1 do
local clientcode = getItem("MONEY_LIMITS",i).client_code
if clientcode ~= nil then
msg.data = clientcode
return msg
end
end
return msg
end
--- Функция возвращает все коды клиента
function qsfunctions.getClientCodes(msg)
local client_codes = {}
for i=0,getNumberOf("MONEY_LIMITS")-1 do
local clientcode = getItem("MONEY_LIMITS",i).client_code
if clientcode ~= nil then
fnd = false
for index, value in ipairs(client_codes) do
if value == clientcode then
fnd = true
end
end
if fnd == false then
table.insert(client_codes, clientcode)
end
end
end
msg.data = client_codes
return msg
end
--- Функция возвращает торговый счет для запрашиваемого кода класса
function qsfunctions.getTradeAccount(msg)
for i=0,getNumberOf("trade_accounts")-1 do
local trade_account = getItem("trade_accounts",i)
if string.find(trade_account.class_codes,'|' .. msg.data .. '|',1,1) then
msg.data = trade_account.trdaccid
return msg
end
end
return msg
end
--- Функция возвращает торговые счета в системе, у которых указаны поддерживаемые классы инструментов.
function qsfunctions.getTradeAccounts(msg)
local trade_accounts = {}
for i=0,getNumberOf("trade_accounts")-1 do
local trade_account = getItem("trade_accounts",i)
if trade_account.class_codes ~= "" then
table.insert(trade_accounts, trade_account)
end
end
msg.data = trade_accounts
return msg
end
---------------------------------------------------------------------
-- Order Book functions (Функции для работы со стаканом котировок) --
---------------------------------------------------------------------
--- Функция заказывает на сервер получение стакана по указанному классу и бумаге.
function qsfunctions.Subscribe_Level_II_Quotes(msg)
local spl = split(msg.data, "|")
local class_code, sec_code = spl[1], spl[2]
msg.data = Subscribe_Level_II_Quotes(class_code, sec_code)
return msg
end
--- Функция отменяет заказ на получение с сервера стакана по указанному классу и бумаге.
function qsfunctions.Unsubscribe_Level_II_Quotes(msg)
local spl = split(msg.data, "|")
local class_code, sec_code = spl[1], spl[2]
msg.data = Unsubscribe_Level_II_Quotes(class_code, sec_code)
return msg
end
--- Функция позволяет узнать, заказан ли с сервера стакан по указанному классу и бумаге.
function qsfunctions.IsSubscribed_Level_II_Quotes(msg)
local spl = split(msg.data, "|")
local class_code, sec_code = spl[1], spl[2]
msg.data = IsSubscribed_Level_II_Quotes(class_code, sec_code)
return msg
end
--- Функция предназначена для получения стакана по указанному классу и инструменту.
function qsfunctions.GetQuoteLevel2(msg)
local spl = split(msg.data, "|")
local class_code, sec_code = spl[1], spl[2]
local server_time = getInfoParam("SERVERTIME")
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
msg.data.server_time = server_time
else
OnError(ql2)
end
return msg
end
-----------------------
-- Trading functions --
-----------------------
--- Функция предназначена для расчета максимально возможного количества лотов в заявке.
-- При заданном параметре is_market=true, необходимо передать параметр price=0, иначе будет рассчитано максимально возможное количество лотов в заявке по цене price.
function qsfunctions.calc_buy_sell(msg)
local bs = CalcBuySell
local spl = split(msg.data, "|")
local class_code, sec_code, clientCode, account, price, is_buy, is_market = spl[1], spl[2], spl[3], spl[4], spl[5], spl[6], spl[7]
if is_buy == "True" then
is_buy = true
else
is_buy = false
end
if is_market == "True" then
is_market = true
else
is_market = false
end
local qty, comiss = bs(class_code, sec_code, clientCode, account, tonumber(price), is_buy, is_market)
if qty ~= "" then
msg.data = {}
msg.data.qty = qty
msg.data.comission = comiss
else
message("Ошибка функции CalcBuySell", 1)
end
return msg
end
--- отправляет транзакцию на сервер и возвращает пустое сообщение, которое
-- будет проигноировано. Вместо него, отправитель будет ждать события
-- OnTransReply, из которого по TRANS_ID он получит результат отправленной транзакции
function qsfunctions.sendTransaction(msg)
local res = sendTransaction(msg.data)
if res~="" then
-- error handling
msg.cmd = "lua_transaction_error"
msg.lua_error = res
return msg
else
-- transaction sent
msg.data = true
return msg
end
end
--- Функция заказывает получение параметров Таблицы текущих торгов. В случае успешного завершения функция возвращает «true», иначе «false»
function qsfunctions.paramRequest(msg)
local spl = split(msg.data, "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
msg.data = ParamRequest(class_code, sec_code, param_name)
return msg
end
--- Функция принимает список строк (JSON Array) в формате class_code|sec_code|param_name, вызывает функцию paramRequest для каждой строки.
-- Возвращает список ответов в том же порядке
function qsfunctions.paramRequestBulk(msg)
local result = {}
for i=1,#msg.data do
local spl = split(msg.data[i], "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
table.insert(result, ParamRequest(class_code, sec_code, param_name))
end
msg.data = result
return msg
end
--- Функция отменяет заказ на получение параметров Таблицы текущих торгов. В случае успешного завершения функция возвращает «true», иначе «false»
function qsfunctions.cancelParamRequest(msg)
local spl = split(msg.data, "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
msg.data = CancelParamRequest(class_code, sec_code, param_name)
return msg
end
--- Функция принимает список строк (JSON Array) в формате class_code|sec_code|param_name, вызывает функцию CancelParamRequest для каждой строки.
-- Возвращает список ответов в том же порядке
function qsfunctions.cancelParamRequestBulk(msg)
local result = {}
for i=1,#msg.data do
local spl = split(msg.data[i], "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
table.insert(result, CancelParamRequest(class_code, sec_code, param_name))
end
msg.data = result
return msg
end
--- Функция предназначена для получения значений всех параметров биржевой информации из Таблицы текущих значений параметров.
-- С помощью этой функции можно получить любое из значений Таблицы текущих значений параметров для заданных кодов класса и бумаги.
function qsfunctions.getParamEx(msg)
local spl = split(msg.data, "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
msg.data = getParamEx(class_code, sec_code, param_name)
return msg
end
--- Функция предназначена для получения значении? всех параметров биржевои? информации из Таблицы текущих торгов
-- с возможностью в дальнеи?шем отказаться от получения определенных параметров, заказанных с помощью функции ParamRequest.
-- Для отказа от получения какого-либо параметра воспользуи?тесь функциеи? CancelParamRequest.
-- Функция возвращает таблицу Lua с параметрами, аналогичными параметрам, возвращаемым функциеи? getParamEx
function qsfunctions.getParamEx2(msg)
local spl = split(msg.data, "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
msg.data = getParamEx2(class_code, sec_code, param_name)
return msg
end
--- Функция принимает список строк (JSON Array) в формате class_code|sec_code|param_name и возвращает результаты вызова
-- функции getParamEx2 для каждой строки запроса в виде списка в таком же порядке, как в запросе
function qsfunctions.getParamEx2Bulk(msg)
local result = {}
for i=1,#msg.data do
local spl = split(msg.data[i], "|")
local class_code, sec_code, param_name = spl[1], spl[2], spl[3]
table.insert(result, getParamEx2(class_code, sec_code, param_name))
end
msg.data = result
return msg
end
-- Функция предназначена для получения информации по бумажным лимитам.
function qsfunctions.getDepo(msg)
local spl = split(msg.data, "|")
local clientCode, firmId, secCode, account = spl[1], spl[2], spl[3], spl[4]
msg.data = getDepo(clientCode, firmId, secCode, account)
return msg
end
-- Функция предназначена для получения информации по бумажным лимитам.
function qsfunctions.getDepoEx(msg)
local spl = split(msg.data, "|")
local firmId, clientCode, secCode, account, limit_kind = spl[1], spl[2], spl[3], spl[4], spl[5]
msg.data = getDepoEx(firmId, clientCode, secCode, account, tonumber(limit_kind))
return msg
end
-- Функция для получения информации по денежным лимитам.
function qsfunctions.getMoney(msg)
local spl = split(msg.data, "|")
local client_code, firm_id, tag, curr_code = spl[1], spl[2], spl[3], spl[4]
msg.data = getMoney(client_code, firm_id, tag, curr_code)
return msg
end
-- Функция для получения информации по денежным лимитам указанного типа.
function qsfunctions.getMoneyEx(msg)
local spl = split(msg.data, "|")
local firm_id, client_code, tag, curr_code, limit_kind = spl[1], spl[2], spl[3], spl[4], spl[5]
msg.data = getMoneyEx(firm_id, client_code, tag, curr_code, tonumber(limit_kind))
return msg
end
-- Функция возвращает информацию по всем денежным лимитам.
function qsfunctions.getMoneyLimits(msg)
local limits = {}
for i=0,getNumberOf("money_limits")-1 do
local limit = getItem("money_limits",i)
table.insert(limits, limit)
end
msg.data = limits
return msg
end
-- Функция предназначена для получения информации по фьючерсным лимитам.
function qsfunctions.getFuturesLimit(msg)
local spl = split(msg.data, "|")
local firmId, accId, limitType, currCode = spl[1], spl[2], spl[3], spl[4]
local result, err = getFuturesLimit(firmId, accId, limitType*1, currCode)
if result then
msg.data = result
else
log("Futures limit returns nil", 3)
msg.data = nil
end
return msg
end
-- Функция возвращает информацию по фьючерсным лимитам для всех торговых счетов.
function qsfunctions.getFuturesClientLimits(msg)
local limits = {}
for i=0,getNumberOf("futures_client_limits")-1 do
local limit = getItem("futures_client_limits",i)
table.insert(limits, limit)
end
msg.data = limits
return msg
end
--- (ichechet) Через getFuturesHolding позиции не приходили. Пришлось сделать обработку таблицы futures_client_holding
function qsfunctions.getFuturesHolding(msg)
if msg.data ~= "" then
local spl = split(msg.data, "|")
local firmId, accId, secCode, posType = spl[1], spl[2], spl[3], spl[4]
end
local fchs = {}
for i = 0, getNumberOf("futures_client_holding") - 1 do
local fch = getItem("futures_client_holding", i)
if msg.data == "" or (fch.firmid == firmId and fch.trdaccid == accId and fch.sec_code == secCode and fch.type == posType*1) then
table.insert(fchs, fch)
end
end
msg.data = fchs
return msg
end
-- Функция для получения информации по всем фьючерсным позициям
function qsfunctions.getFuturesClientHoldings(msg)
local holdings = {}
for i=0,getNumberOf("futures_client_holding")-1 do
local holding = getItem("futures_client_holding",i)
table.insert(holdings, holding)
end
msg.data = holdings
return msg
end
-- Функция возвращает таблицу заявок (всю или по заданному инструменту)
function qsfunctions.get_orders(msg)
if msg.data ~= "" then
local spl = split(msg.data, "|")
class_code, sec_code = spl[1], spl[2]
end
local orders = {}
for i = 0, getNumberOf("orders") - 1 do
local order = getItem("orders", i)
if msg.data == "" or (order.class_code == class_code and order.sec_code == sec_code) then
table.insert(orders, order)
end
end
msg.data = orders
return msg
end
-- Функция возвращает заявку по заданному инструменту и ID-транзакции
function qsfunctions.getOrder_by_ID(msg)
if msg.data ~= "" then
local spl = split(msg.data, "|")
class_code, sec_code, trans_id = spl[1], spl[2], spl[3]
end
local order_num = 0
local res
for i = 0, getNumberOf("orders") - 1 do
local order = getItem("orders", i)
if order.class_code == class_code and order.sec_code == sec_code and order.trans_id == tonumber(trans_id) and order.order_num > order_num then
order_num = order.order_num
res = order
end
end
msg.data = res
return msg
end
---- Функция возвращает заявку по номеру
function qsfunctions.getOrder_by_Number(msg)
for i=0,getNumberOf("orders")-1 do
local order = getItem("orders",i)
if order.order_num == tonumber(msg.data) then
msg.data = order
return msg
end
end
return msg
end
--- Возвращает заявку по её номеру и классу инструмента ---
--- На основе http://help.qlua.org/ch4_5_1_1.htm ---
function qsfunctions.get_order_by_number(msg)
local spl = split(msg.data, "|")
local class_code = spl[1]
local order_id = tonumber(spl[2])
msg.data = getOrderByNumber(class_code, order_id)
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 sec_code = msg.data
local count = getNumberOf("depo_limits")
local depo_limits = {}
for i = 0, count - 1 do
local depo_limit = getItem("depo_limits", i)
if msg.data == "" or depo_limit.sec_code == sec_code then
table.insert(depo_limits, depo_limit)
end
end
msg.data = depo_limits
return msg
end
-- Функция возвращает таблицу сделок (всю или по заданному инструменту)
function qsfunctions.get_trades(msg)
if msg.data ~= "" then
local spl = split(msg.data, "|")
class_code, sec_code = spl[1], spl[2]
end
local trades = {}
for i = 0, getNumberOf("trades") - 1 do
local trade = getItem("trades", i)
if msg.data == "" or (trade.class_code == class_code and trade.sec_code == sec_code) then
table.insert(trades, trade)
end
end
msg.data = trades
return msg
end
-- Функция возвращает таблицу сделок по номеру заявки
function qsfunctions.get_Trades_by_OrderNumber(msg)
local order_num = tonumber(msg.data)
local trades = {}
for i = 0, getNumberOf("trades") - 1 do
local trade = getItem("trades", i)
if trade.order_num == order_num then
table.insert(trades, trade)
end
end
msg.data = trades
return msg
end
-- Функция предназначена для получения значений параметров таблицы «Клиентский портфель», соответствующих идентификатору участника торгов «firmid» и коду клиента «client_code».
function qsfunctions.getPortfolioInfo(msg)
local spl = split(msg.data, "|")
local firmId, clientCode = spl[1], spl[2]
msg.data = getPortfolioInfo(firmId, clientCode)
return msg
end
-- Функция предназначена для получения значений параметров таблицы «Клиентский портфель», соответствующих идентификатору участника торгов «firmid», коду клиента «client_code» и виду лимита «limit_kind».
function qsfunctions.getPortfolioInfoEx(msg)
local spl = split(msg.data, "|")
local firmId, clientCode, limit_kind = spl[1], spl[2], spl[3]
msg.data = getPortfolioInfoEx(firmId, clientCode, tonumber(limit_kind))
return msg
end
-- Функция предназначена для получения таблицы обезличенных сделок по выбранному инструменту или всю целиком.
function qsfunctions.get_all_trades(msg)
if msg.data ~= "" then
local spl = split(msg.data, "|")
class_code, sec_code = spl[1], spl[2]
end
local trades = {}
for i = 0, getNumberOf("all_trades") - 1 do
local trade = getItem("all_trades", i)
if msg.data == "" or (trade.class_code == class_code and trade.sec_code == sec_code) then
table.insert(trades, trade)
end
end
msg.data = trades
return msg
end
--------------------------
-- OptionBoard functions --
--------------------------
function qsfunctions.getOptionBoard(msg)
local spl = split(msg.data, "|")
local classCode, secCode = spl[1], spl[2]
local result, err = getOptions(classCode, secCode)
if result then
msg.data = result
else
log("Option board returns nil", 3)
msg.data = nil
end
return msg
end
function getOptions(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)
if msg.data ~= "" then
local spl = split(msg.data, "|")
class_code, sec_code = spl[1], spl[2]
end
local count = getNumberOf("stop_orders")
local stop_orders = {}
for i = 0, count - 1 do
local stop_order = getItem("stop_orders", i)
if msg.data == "" or (stop_order.class_code == class_code and stop_order.sec_code == sec_code) then
table.insert(stop_orders, stop_order)
end
end
msg.data = stop_orders
return msg
end
-------------------------
--- Candles functions ---
-------------------------
--- Возвращаем количество свечей по тегу
function qsfunctions.get_num_candles(msg)
log("Called get_num_candles" .. msg.data, 2)
local spl = split(msg.data, "|")
local tag = spl[1]
msg.data = getNumCandles(tag) * 1
return msg
end
--- Возвращаем все свечи по идентификатору графика. График должен быть открыт
function qsfunctions.get_candles(msg)
log("Called get_candles" .. msg.data, 2)
local spl = split(msg.data, "|")
local tag = spl[1]
local line = tonumber(spl[2])
local first_candle = tonumber(spl[3])
local count = tonumber(spl[4])
if count == 0 then
count = getNumCandles(tag) * 1
end
log("Count: " .. count, 2)
local t,n,l = getCandlesByIndex(tag, line, first_candle, count)
log("Candles table size: " .. n, 2)
log("Label: " .. l, 2)
local candles = {}
for i = 0, count - 1 do
table.insert(candles, t[i])
end
msg.data = candles
return msg
end
--- Возвращаем все свечи по заданному инструменту и интервалу
-- (ichechet) Если исторические данные по тикеру не приходят, то QUIK блокируется. Чтобы это не происходило, вводим таймаут
function qsfunctions.get_candles_from_data_source(msg)
local ds, is_error = create_data_source(msg)
if not is_error then
-- Источник данных изначально приходит пустым. Нужно подождать пока он заполнится данными. Бесконечно ждать тоже нельзя. Вводим таймаут
local s = 0 -- Будем ждать 5 секунд, прежде чем вернем таймаут
repeat -- Ждем
sleep(100) -- 100 миллисекунд
s = s + 100 -- Запоминаем кол-во прошедших миллисекунд
until (ds:Size() > 0 or s > 5000) -- До тех пор, пока не придут данные или пока не наступит таймаут
local count = tonumber(split(msg.data, "|")[4]) -- возвращаем последние count свечей. Если равен 0, то возвращаем все доступные свечи.
local class, sec, interval = get_candles_param(msg)
local candles = {}
local start_i = count == 0 and 1 or math.max(1, ds:Size() - count + 1)
for i = start_i, ds:Size() do
local candle = fetch_candle(ds, i)
candle.sec = sec
candle.class = class
candle.interval = interval
table.insert(candles, candle)
end
ds:Close()
msg.data = candles
end
return msg
end
function create_data_source(msg)
local class, sec, interval = get_candles_param(msg)
local ds, error_descr = CreateDataSource(class, sec, interval)
local is_error = false
if(error_descr ~= nil) then
msg.cmd = "lua_create_data_source_error"
msg.lua_error = error_descr
is_error = true
elseif ds == nil then
msg.cmd = "lua_create_data_source_error"
msg.lua_error = "Can't create data source for " .. class .. ", " .. sec .. ", " .. tostring(interval)
is_error = true
end
return ds, is_error
end
function fetch_candle(data_source, index)
local candle = {}
candle.low = data_source:L(index)
candle.close = data_source:C(index)
candle.high = data_source:H(index)
candle.open = data_source:O(index)
candle.volume = data_source:V(index)
candle.datetime = data_source:T(index)
return candle
end
--- Словарь открытых подписок (datasources) на свечи
data_sources = {}
last_indexes = {}
--- Подписаться на получения свечей по заданному инструмент и интервалу
function qsfunctions.subscribe_to_candles(msg)
local ds, is_error = create_data_source(msg)
if not is_error then
local class, sec, interval = get_candles_param(msg)
local key = get_key(class, sec, interval)
data_sources[key] = ds
last_indexes[key] = ds:Size()
ds:SetUpdateCallback(
function(index)
data_source_callback(index, class, sec, interval)
end)
end
return msg
end
function data_source_callback(index, class, sec, interval)
local key = get_key(class, sec, interval)
if index ~= last_indexes[key] then
last_indexes[key] = index
local candle = fetch_candle(data_sources[key], index - 1)
candle.sec = sec
candle.class = class
candle.interval = interval
local msg = {}
msg.t = timemsec()
msg.cmd = "NewCandle"
msg.data = candle
sendCallback(msg)
end
end
--- Отписать от получения свечей по заданному инструменту и интервалу
function qsfunctions.unsubscribe_from_candles(msg)
local class, sec, interval = get_candles_param(msg)
local key = get_key(class, sec, interval)
data_sources[key]:Close()
data_sources[key] = nil
last_indexes[key] = nil
return msg
end
--- Проверить открыта ли подписка на заданный инструмент и интервал
function qsfunctions.is_subscribed(msg)
local class, sec, interval = get_candles_param(msg)
local key = get_key(class, sec, interval)
for k, v in pairs(data_sources) do
if key == k then
msg.data = true;
return msg
end
end
msg.data = false
return msg
end
--- Возвращает из msg информацию о инструменте на который подписываемся и интервале
function get_candles_param(msg)
local spl = split(msg.data, "|")
return spl[1], spl[2], tonumber(spl[3])
end
--- Возвращает уникальный ключ для инструмента на который подписываемся и инетрвала
function get_key(class, sec, interval)
return class .. "|" .. sec .. "|" .. tostring(interval)
end
-------------------------
--- UCP functions ---
-------------------------
--- Функция возвращает торговый счет срочного рынка, соответствующий коду клиента фондового рынка с единой денежной позицией
function qsfunctions.GetTrdAccByClientCode(msg)
local spl = split(msg.data, "|")
local firmId, clientCode = spl[1], spl[2]
msg.data = getTrdAccByClientCode(firmId, clientCode)
return msg
end
--- Функция возвращает код клиента фондового рынка с единой денежной позицией, соответствующий торговому счету срочного рынка
function qsfunctions.GetClientCodeByTrdAcc(msg)
local spl = split(msg.data, "|")
local firmId, trdAccId = spl[1], spl[2]
msg.data = getClientCodeByTrdAcc(firmId, trdAccId)
return msg
end
--- Функция предназначена для получения признака, указывающего имеет ли клиент единую денежную позицию
function qsfunctions.IsUcpClient(msg)
local spl = split(msg.data, "|")
local firmId, client = spl[1], spl[2]
msg.data = isUcpClient(firmId, client)
return msg
end
return qsfunctions