Здесь буду выкладывать функции, которые могут пригодиться:
1 2 3 4 5 | -- Округляет число до указанной точности math_round = function(num, idp) local mult = 10^(idp or 0) return math.floor(num * mult + 0.5) / mult end |
-- Округляет число до указанной точности math_round = function(num, idp) local mult = 10^(idp or 0) return math.floor(num * mult + 0.5) / mult end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -- Возвращает среднее значение из переданных чисел math_average = function(...) local arg = {...} local sum = 0 local count = 0 for i=1,#arg do if type(arg[i]) == 'number' then sum = sum + arg[i] count = count + 1 end end if count == 0 then return 0 else return sum / count end end |
-- Возвращает среднее значение из переданных чисел math_average = function(...) local arg = {...} local sum = 0 local count = 0 for i=1,#arg do if type(arg[i]) == 'number' then sum = sum + arg[i] count = count + 1 end end if count == 0 then return 0 else return sum / count end end
1 2 3 4 5 6 7 8 | -- Возвращает код класса по коду бумаги GetClassBySec = function(sec_code) for class_code in string.gmatch ('QJSIM,TQBR,SPBFUT,SPBOPT,CETS,', '(%P*),') do for sec in string.gmatch (getClassSecurities(class_code), '(%P*_*%P*_*%P*),') do if sec == sec_code then return class_code end end end end |
-- Возвращает код класса по коду бумаги GetClassBySec = function(sec_code) for class_code in string.gmatch ('QJSIM,TQBR,SPBFUT,SPBOPT,CETS,', '(%P*),') do for sec in string.gmatch (getClassSecurities(class_code), '(%P*_*%P*_*%P*),') do if sec == sec_code then return class_code end end end end
1 2 | RUN = true -- Флаг поддерживающий работу скрипта UpdateDataSecQty = 10 -- Количество секунд ожидания подгрузки данных с сервера после возобновления подключения |
RUN = true -- Флаг поддерживающий работу скрипта UpdateDataSecQty = 10 -- Количество секунд ожидания подгрузки данных с сервера после возобновления подключения
1 2 3 4 5 6 7 | -- Ждет подключения к серверу, после чего ждет еще UpdateDataSecQty секунд подгрузки пропущенных данных с сервера WaitUpdateDataAfterReconnect = function() while RUN and isConnected() == 0 do sleep(100) end if RUN then sleep(UpdateDataSecQty * 1000) end -- Повторяет операцию если соединение снова оказалось разорвано if RUN and isConnected() == 0 then WaitUpdateDataAfterReconnect() end end |
-- Ждет подключения к серверу, после чего ждет еще UpdateDataSecQty секунд подгрузки пропущенных данных с сервера WaitUpdateDataAfterReconnect = function() while RUN and isConnected() == 0 do sleep(100) end if RUN then sleep(UpdateDataSecQty * 1000) end -- Повторяет операцию если соединение снова оказалось разорвано if RUN and isConnected() == 0 then WaitUpdateDataAfterReconnect() end end
1 2 3 4 5 | -- Возвращает количество миллисекунд GetMilliseconds = function() local dt = os.sysdate() return os.time(dt) * 1000 + dt.ms end |
-- Возвращает количество миллисекунд GetMilliseconds = function() local dt = os.sysdate() return os.time(dt) * 1000 + dt.ms end
1 | RUN = true -- Флаг поддерживающий работу скрипта |
RUN = true -- Флаг поддерживающий работу скрипта
Для работы функции в скрипте должна присутствовать функция:
WaitUpdateDataAfterReconnect()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | -- Возвращает текущую дату/время сервера в виде таблицы datetime GetServerDateTime = function() local dt = {} -- Пытается получить дату/время сервера while RUN and dt.day == nil do dt.day,dt.month,dt.year,dt.hour,dt.min,dt.sec = string.match(getInfoParam('TRADEDATE')..' '..getInfoParam('SERVERTIME'),"(%d*).(%d*).(%d*) (%d*):(%d*):(%d*)") -- Если не удалось получить, или разрыв связи, ждет подключения и подгрузки с сервера актуальных данных if dt.day == nil or isConnected() == 0 then WaitUpdateDataAfterReconnect() end end -- Если во время ожидания скрипт был остановлен пользователем, возвращает таблицу datetime даты/времени компьютера, чтобы не вернуть пустую таблицу и не вызвать ошибку в алгоритме if not RUN then return os.date('*t', os.time()) end -- Приводит полученные значения к типу number for key,value in pairs(dt) do dt[key] = tonumber(value) end -- Возвращает итоговую таблицу return dt end |
-- Возвращает текущую дату/время сервера в виде таблицы datetime GetServerDateTime = function() local dt = {} -- Пытается получить дату/время сервера while RUN and dt.day == nil do dt.day,dt.month,dt.year,dt.hour,dt.min,dt.sec = string.match(getInfoParam('TRADEDATE')..' '..getInfoParam('SERVERTIME'),"(%d*).(%d*).(%d*) (%d*):(%d*):(%d*)") -- Если не удалось получить, или разрыв связи, ждет подключения и подгрузки с сервера актуальных данных if dt.day == nil or isConnected() == 0 then WaitUpdateDataAfterReconnect() end end -- Если во время ожидания скрипт был остановлен пользователем, возвращает таблицу datetime даты/времени компьютера, чтобы не вернуть пустую таблицу и не вызвать ошибку в алгоритме if not RUN then return os.date('*t', os.time()) end -- Приводит полученные значения к типу number for key,value in pairs(dt) do dt[key] = tonumber(value) end -- Возвращает итоговую таблицу return dt end
1 | RUN = true -- Флаг поддерживающий работу скрипта |
RUN = true -- Флаг поддерживающий работу скрипта
Для работы функции в скрипте должна присутствовать функция:
GetServerDateTime()
Так же, должна присутствовать переменная RUN, которая поддерживает работу основного цикла while в функции main.
1 2 3 4 5 6 7 8 9 10 11 | -- Приводит время из строкового формата ЧЧ:ММ:СС к формату datetime StrToTime = function(str_time) while RUN and GetServerDateTime().day == nil do sleep(100) end if not RUN then return os.date('*t', os.time()) end local dt = GetServerDateTime() local h,m,s = string.match( str_time, "(%d%d):(%d%d):(%d%d)") dt.hour = tonumber(h) dt.min = tonumber(m) dt.sec = tonumber(s) return dt end |
-- Приводит время из строкового формата ЧЧ:ММ:СС к формату datetime StrToTime = function(str_time) while RUN and GetServerDateTime().day == nil do sleep(100) end if not RUN then return os.date('*t', os.time()) end local dt = GetServerDateTime() local h,m,s = string.match( str_time, "(%d%d):(%d%d):(%d%d)") dt.hour = tonumber(h) dt.min = tonumber(m) dt.sec = tonumber(s) return dt end
1 2 3 4 5 6 7 8 9 10 11 12 | function main() if CheckDemo() then message('DEMO') else message('REAL') end end -- Функция возвращает true, если это демо от компании Arqa, или брокера Открытие, иначе false CheckDemo = function() if getClassInfo('QJSIM') ~= nil or getClassInfo('SPBFUT').name:find('Фьючерсы') ~= nil then return true else return false end end |
function main() if CheckDemo() then message('DEMO') else message('REAL') end end -- Функция возвращает true, если это демо от компании Arqa, или брокера Открытие, иначе false CheckDemo = function() if getClassInfo('QJSIM') ~= nil or getClassInfo('SPBFUT').name:find('Фьючерсы') ~= nil then return true else return false end end
1 2 3 4 5 6 7 8 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента LIMIT_KIND = 0 -- Тип лимита (акции), для демо счета должно быть 0, для реального 2 CLIENT_CODE = '' -- Код клиента, нужен для получения позиции по валюте BALANCE_TYPE = 1 -- Тип отображения баланса в таблице "Таблица лимитов по денежным средствам" (1 - в лотах, 2 - с учетом количества в лоте) -- Например, при покупке 1 лота USDRUB одни брокеры в поле "Баланс" транслируют 1, другие 1000 -- 1 лот акций Сбербанка может отображаться в таблице "Позиции по инструментов" в поле "Текущий остаток" как 1, или 10 |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента LIMIT_KIND = 0 -- Тип лимита (акции), для демо счета должно быть 0, для реального 2 CLIENT_CODE = '' -- Код клиента, нужен для получения позиции по валюте BALANCE_TYPE = 1 -- Тип отображения баланса в таблице "Таблица лимитов по денежным средствам" (1 - в лотах, 2 - с учетом количества в лоте) -- Например, при покупке 1 лота USDRUB одни брокеры в поле "Баланс" транслируют 1, другие 1000 -- 1 лот акций Сбербанка может отображаться в таблице "Позиции по инструментов" в поле "Текущий остаток" как 1, или 10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | -- Получает текущую чистую позицию по инструменту GetTotalnet = function() -- ФЬЮЧЕРСЫ, ОПЦИОНЫ if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then local num = getNumberOf('futures_client_holding') if num > 0 then -- Находит размер лота local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) if num > 1 then for i = 0, num - 1 do local futures_client_holding = getItem('futures_client_holding',i) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then if BALANCE_TYPE == 1 then return math.floor(futures_client_holding.totalnet) else return math.floor(futures_client_holding.totalnet/lot) end end end else local futures_client_holding = getItem('futures_client_holding',0) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then if BALANCE_TYPE == 1 then return math.floor(futures_client_holding.totalnet) else return math.floor(futures_client_holding.totalnet/lot) end end end end -- АКЦИИ elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' then local num = getNumberOf('depo_limits') if num > 0 then local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) if num > 1 then for i = 0, num - 1 do local depo_limit = getItem('depo_limits', i) if depo_limit.sec_code == SEC_CODE and depo_limit.trdaccid == ACCOUNT and depo_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(depo_limit.currentbal) else return math.floor(depo_limit.currentbal/lot) end end end else local depo_limit = getItem('depo_limits', 0) if depo_limit.sec_code == SEC_CODE and depo_limit.trdaccid == ACCOUNT and depo_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(depo_limit.currentbal) else return math.floor(depo_limit.currentbal/lot) end end end end -- ВАЛЮТА elseif CLASS_CODE == 'CETS' then local num = getNumberOf('money_limits') if num > 0 then -- Находит валюту local cur = string.sub(SEC_CODE, 1, 3) local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) if num > 1 then for i = 0, num - 1 do local money_limit = getItem('money_limits', i) if money_limit.currcode == cur and money_limit.client_code == CLIENT_CODE and money_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(money_limit.currentbal) else return math.floor(money_limit.currentbal/lot) end end end else local money_limit = getItem('money_limits', 0) if money_limit.currcode == cur and money_limit.client_code == CLIENT_CODE and money_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(money_limit.currentbal) else return math.floor(money_limit.currentbal/lot) end end end end end -- Если позиция по инструменту в таблице не найдена, возвращает 0 return 0 end |
-- Получает текущую чистую позицию по инструменту GetTotalnet = function() -- ФЬЮЧЕРСЫ, ОПЦИОНЫ if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then local num = getNumberOf('futures_client_holding') if num > 0 then -- Находит размер лота local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) if num > 1 then for i = 0, num - 1 do local futures_client_holding = getItem('futures_client_holding',i) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then if BALANCE_TYPE == 1 then return math.floor(futures_client_holding.totalnet) else return math.floor(futures_client_holding.totalnet/lot) end end end else local futures_client_holding = getItem('futures_client_holding',0) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then if BALANCE_TYPE == 1 then return math.floor(futures_client_holding.totalnet) else return math.floor(futures_client_holding.totalnet/lot) end end end end -- АКЦИИ elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' then local num = getNumberOf('depo_limits') if num > 0 then local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) if num > 1 then for i = 0, num - 1 do local depo_limit = getItem('depo_limits', i) if depo_limit.sec_code == SEC_CODE and depo_limit.trdaccid == ACCOUNT and depo_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(depo_limit.currentbal) else return math.floor(depo_limit.currentbal/lot) end end end else local depo_limit = getItem('depo_limits', 0) if depo_limit.sec_code == SEC_CODE and depo_limit.trdaccid == ACCOUNT and depo_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(depo_limit.currentbal) else return math.floor(depo_limit.currentbal/lot) end end end end -- ВАЛЮТА elseif CLASS_CODE == 'CETS' then local num = getNumberOf('money_limits') if num > 0 then -- Находит валюту local cur = string.sub(SEC_CODE, 1, 3) local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) if num > 1 then for i = 0, num - 1 do local money_limit = getItem('money_limits', i) if money_limit.currcode == cur and money_limit.client_code == CLIENT_CODE and money_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(money_limit.currentbal) else return math.floor(money_limit.currentbal/lot) end end end else local money_limit = getItem('money_limits', 0) if money_limit.currcode == cur and money_limit.client_code == CLIENT_CODE and money_limit.limit_kind == LIMIT_KIND then if BALANCE_TYPE == 1 then return math.floor(money_limit.currentbal) else return math.floor(money_limit.currentbal/lot) end end end end end -- Если позиция по инструменту в таблице не найдена, возвращает 0 return 0 end
1 2 3 4 5 6 7 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента LIMIT_KIND = 0 -- Тип лимита (акции), для демо счета должно быть 0, для реального 2 BALANCE_TYPE = 1 -- Тип отображения баланса в таблице "Таблица лимитов по денежным средствам" (1 - в лотах, 2 - с учетом количества в лоте) -- Например, при покупке 1 лота USDRUB одни брокеры в поле "Баланс" транслируют 1, другие 1000 -- 1 лот акций Сбербанка может отображаться в таблице "Позиции по инструментов" в поле "Текущий остаток" как 1, или 10 |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента LIMIT_KIND = 0 -- Тип лимита (акции), для демо счета должно быть 0, для реального 2 BALANCE_TYPE = 1 -- Тип отображения баланса в таблице "Таблица лимитов по денежным средствам" (1 - в лотах, 2 - с учетом количества в лоте) -- Например, при покупке 1 лота USDRUB одни брокеры в поле "Баланс" транслируют 1, другие 1000 -- 1 лот акций Сбербанка может отображаться в таблице "Позиции по инструментов" в поле "Текущий остаток" как 1, или 10
Так же, для работы функции в скрипте должна присутствовать функция:
GetTotalnet()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | -- Получает цену текущей позиции по инструменту GetPosPrice = function() -- Акции if CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' then -- Перебирает таблицу "Позиции по инструментам" local num = getNumberOf('depo_limits') local depo_limit = nil for i=0,num-1 do depo_limit = getItem('depo_limits', i) if depo_limit.sec_code == SEC_CODE and depo_limit.trdaccid == ACCOUNT and depo_limit.limit_kind == LIMIT_KIND then return depo_limit.awg_position_price end end -- Фьючерсы, опционы elseif CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then local totalnet = GetTotalnet() -- Если позиция есть if totalnet ~= 0 then local abs_totalnet = math.abs(totalnet) local sum = 0 local sum_lots = 0 local trade = nil -- Перебирает сделки local num = getNumberOf('trades') for i=num-1,0,-1 do trade = getItem('trades', i) if trade.sec_code == SEC_CODE then if (totalnet < 0 and bit.test(trade.flags, 2)) or (totalnet > 0 and not bit.test(trade.flags, 2)) or totalnet == 0 then sum = sum + trade.price*trade.qty sum_lots = sum_lots + trade.qty -- Если найдены все сделки набора позиции if sum_lots >= abs_totalnet then -- Возвращает среднюю цену return sum/sum_lots end end end end -- Не удалось найти все сделки набора позиции -- Если найдены хоть какие-то сделки набора if sum_lots > 0 then -- Возвращает среднюю цену найденных return sum/sum_lots -- Сделок набора не найдено else -- Возвращает эффективную цену позиции local num = getNumberOf('futures_client_holding') if num > 0 then -- Находит размер лота local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) local futures_client_holding = nil if num > 1 then for i = 0, num - 1 do futures_client_holding = getItem('futures_client_holding', i) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then return futures_client_holding.avrposnprice end end else futures_client_holding = getItem('futures_client_holding', 0) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then return futures_client_holding.avrposnprice end end end end end end -- Если не удалось получить значение, возвращает цену последней сделки по инструменту return tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value) end |
-- Получает цену текущей позиции по инструменту GetPosPrice = function() -- Акции if CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' then -- Перебирает таблицу "Позиции по инструментам" local num = getNumberOf('depo_limits') local depo_limit = nil for i=0,num-1 do depo_limit = getItem('depo_limits', i) if depo_limit.sec_code == SEC_CODE and depo_limit.trdaccid == ACCOUNT and depo_limit.limit_kind == LIMIT_KIND then return depo_limit.awg_position_price end end -- Фьючерсы, опционы elseif CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then local totalnet = GetTotalnet() -- Если позиция есть if totalnet ~= 0 then local abs_totalnet = math.abs(totalnet) local sum = 0 local sum_lots = 0 local trade = nil -- Перебирает сделки local num = getNumberOf('trades') for i=num-1,0,-1 do trade = getItem('trades', i) if trade.sec_code == SEC_CODE then if (totalnet < 0 and bit.test(trade.flags, 2)) or (totalnet > 0 and not bit.test(trade.flags, 2)) or totalnet == 0 then sum = sum + trade.price*trade.qty sum_lots = sum_lots + trade.qty -- Если найдены все сделки набора позиции if sum_lots >= abs_totalnet then -- Возвращает среднюю цену return sum/sum_lots end end end end -- Не удалось найти все сделки набора позиции -- Если найдены хоть какие-то сделки набора if sum_lots > 0 then -- Возвращает среднюю цену найденных return sum/sum_lots -- Сделок набора не найдено else -- Возвращает эффективную цену позиции local num = getNumberOf('futures_client_holding') if num > 0 then -- Находит размер лота local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value) local futures_client_holding = nil if num > 1 then for i = 0, num - 1 do futures_client_holding = getItem('futures_client_holding', i) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then return futures_client_holding.avrposnprice end end else futures_client_holding = getItem('futures_client_holding', 0) if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then return futures_client_holding.avrposnprice end end end end end end -- Если не удалось получить значение, возвращает цену последней сделки по инструменту return tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value) end
1 2 3 | ACCOUNT = 'SPBFUT00010' -- Код счета FIRM_ID = 'NC0011100000' -- Фирма CLIENT_CODE = '10814' -- Код клиента |
ACCOUNT = 'SPBFUT00010' -- Код счета FIRM_ID = 'NC0011100000' -- Фирма CLIENT_CODE = '10814' -- Код клиента
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | -- Возвращает доступные средства GetFreeMoney = function() if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then local num = getNumberOf('futures_client_limits') if num > 0 then if num > 1 then for i = 0, num - 1 do local limit = getItem('futures_client_limits', i) if limit.firmid == FIRM_ID and limit.trdaccid == ACCOUNT and limit.limit_type == 0 then return limit.cbplplanned end end else local limit = getItem('futures_client_limits', 0) if limit.firmid == FIRM_ID and limit.trdaccid == ACCOUNT and limit.limit_type == 0 then return limit.cbplplanned end end end elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' or CLASS_CODE == 'CETS' then local num = getNumberOf('money_limits') if num > 0 then if num > 1 then for i = 0, num - 1 do local limit = getItem('money_limits', i) if limit.currcode == 'SUR' and limit.firmid == FIRM_ID and limit.client_code == CLIENT_CODE and limit.limit_kind == 0 then return limit.currentbal end end else local limit = getItem('money_limits', 0) if limit.currcode == 'SUR' and limit.firmid == FIRM_ID and limit.client_code == CLIENT_CODE and limit.limit_kind == 0 then return limit.currentbal end end end end return 0 end |
-- Возвращает доступные средства GetFreeMoney = function() if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then local num = getNumberOf('futures_client_limits') if num > 0 then if num > 1 then for i = 0, num - 1 do local limit = getItem('futures_client_limits', i) if limit.firmid == FIRM_ID and limit.trdaccid == ACCOUNT and limit.limit_type == 0 then return limit.cbplplanned end end else local limit = getItem('futures_client_limits', 0) if limit.firmid == FIRM_ID and limit.trdaccid == ACCOUNT and limit.limit_type == 0 then return limit.cbplplanned end end end elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' or CLASS_CODE == 'CETS' then local num = getNumberOf('money_limits') if num > 0 then if num > 1 then for i = 0, num - 1 do local limit = getItem('money_limits', i) if limit.currcode == 'SUR' and limit.firmid == FIRM_ID and limit.client_code == CLIENT_CODE and limit.limit_kind == 0 then return limit.currentbal end end else local limit = getItem('money_limits', 0) if limit.currcode == 'SUR' and limit.firmid == FIRM_ID and limit.client_code == CLIENT_CODE and limit.limit_kind == 0 then return limit.currentbal end end end end return 0 end
1 2 | CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента |
CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента
Так же, для работы функции в скрипте должна присутствовать функция:
math_round()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | -- Приводит переданную цену к требуемому для транзакции по инструменту виду GetCorrectPrice = function(price) -- STRING -- Получает точность цены по инструменту local scale = getSecurityInfo(CLASS_CODE, SEC_CODE).scale -- Получает минимальный шаг цены инструмента local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- Если после запятой должны быть цифры if scale > 0 then price = tostring(price) -- Ищет в числе позицию запятой, или точки local dot_pos = price:find('.') local comma_pos = price:find(',') -- Если передано целое число if dot_pos == nil and comma_pos == nil then -- Добавляет к числу ',' и необходимое количество нулей и возвращает результат price = price..',' for i=1,scale do price = price..'0' end return price else -- передано вещественное число -- Если нужно, заменяет запятую на точку if comma_pos ~= nil then price:gsub(',', '.') end -- Округляет число до необходимого количества знаков после запятой price = math_round(tonumber(price), scale) -- Корректирует на соответствие шагу цены price = math_round(price/PriceStep)*PriceStep price = string.gsub(tostring(price),'[%.]+', ',') return price end else -- После запятой не должно быть цифр -- Корректирует на соответствие шагу цены price = math_round(price/PriceStep)*PriceStep return tostring(math.floor(price)) end end |
-- Приводит переданную цену к требуемому для транзакции по инструменту виду GetCorrectPrice = function(price) -- STRING -- Получает точность цены по инструменту local scale = getSecurityInfo(CLASS_CODE, SEC_CODE).scale -- Получает минимальный шаг цены инструмента local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- Если после запятой должны быть цифры if scale > 0 then price = tostring(price) -- Ищет в числе позицию запятой, или точки local dot_pos = price:find('.') local comma_pos = price:find(',') -- Если передано целое число if dot_pos == nil and comma_pos == nil then -- Добавляет к числу ',' и необходимое количество нулей и возвращает результат price = price..',' for i=1,scale do price = price..'0' end return price else -- передано вещественное число -- Если нужно, заменяет запятую на точку if comma_pos ~= nil then price:gsub(',', '.') end -- Округляет число до необходимого количества знаков после запятой price = math_round(tonumber(price), scale) -- Корректирует на соответствие шагу цены price = math_round(price/PriceStep)*PriceStep price = string.gsub(tostring(price),'[%.]+', ',') return price end else -- После запятой не должно быть цифр -- Корректирует на соответствие шагу цены price = math_round(price/PriceStep)*PriceStep return tostring(math.floor(price)) end end
1 2 | CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента |
CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента
Так же, для работы функции в скрипте должна присутствовать функция:
GetCorrectPrice()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | -- Возвращает корректную цену для рыночной заявки по текущему инструменту (принимает 'S',или 'B') GetPriceForMarketOrder = function(operation) -- STRING -- Получает минимальный шаг цены инструмента local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- В зависимости от направления if operation == 'B' then -- BUY -- Пытается получить максимально возможную цену для инструмента local PriceMax = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMAX').param_value) -- Если максимально возможная цена получена if PriceMax ~= nil and PriceMax ~= 0 then -- Возвращает ее в нужном для транзакции формате return GetCorrectPrice(PriceMax) -- Иначе, максимально возможная цена не получена else -- Получает цену последней сделки local Last = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value) -- Возвращает ее в нужном для транзакции формате, увеличив перед этим на 50 шагов цены return GetCorrectPrice(Last + 50*PriceStep) end else -- SELL -- Пытается получить минимально возможную цену для инструмента local PriceMin = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMIN').param_value) -- Если минимально возможная цена получена if PriceMin ~= nil and PriceMin ~= 0 then -- Возвращает ее в нужном для транзакции формате return GetCorrectPrice(PriceMin) -- Иначе, минимально возможная цена не получена else -- Получает цену последней сделки local Last = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value) -- Возвращает ее в нужном для транзакции формате, уменьшив перед этим на 50 шагов цены return GetCorrectPrice(Last - 50*PriceStep) end end end |
-- Возвращает корректную цену для рыночной заявки по текущему инструменту (принимает 'S',или 'B') GetPriceForMarketOrder = function(operation) -- STRING -- Получает минимальный шаг цены инструмента local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- В зависимости от направления if operation == 'B' then -- BUY -- Пытается получить максимально возможную цену для инструмента local PriceMax = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMAX').param_value) -- Если максимально возможная цена получена if PriceMax ~= nil and PriceMax ~= 0 then -- Возвращает ее в нужном для транзакции формате return GetCorrectPrice(PriceMax) -- Иначе, максимально возможная цена не получена else -- Получает цену последней сделки local Last = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value) -- Возвращает ее в нужном для транзакции формате, увеличив перед этим на 50 шагов цены return GetCorrectPrice(Last + 50*PriceStep) end else -- SELL -- Пытается получить минимально возможную цену для инструмента local PriceMin = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMIN').param_value) -- Если минимально возможная цена получена if PriceMin ~= nil and PriceMin ~= 0 then -- Возвращает ее в нужном для транзакции формате return GetCorrectPrice(PriceMin) -- Иначе, минимально возможная цена не получена else -- Получает цену последней сделки local Last = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value) -- Возвращает ее в нужном для транзакции формате, уменьшив перед этим на 50 шагов цены return GetCorrectPrice(Last - 50*PriceStep) end end end
1 2 3 4 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента trans_id = os.time() -- ID транзакции |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента trans_id = os.time() -- ID транзакции
Так же, для работы функции в скрипте должны присутствовать функции:
GetCorrectPrice()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | -- Выставляет заявку SetOrder = function( price, -- Цена заявки operation, -- Операция ('B' - buy, 'S' - sell) qty -- Количество ) -- Выставляет заявку -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local T = {} T['TRANS_ID'] = tostring(trans_id) -- Номер транзакции T['ACCOUNT'] = ACCOUNT -- Код счета T['CLASSCODE'] = CLASS_CODE -- Код класса T['SECCODE'] = SEC_CODE -- Код инструмента T['ACTION'] = 'NEW_ORDER' -- Тип транзакции ('NEW_ORDER' - новая заявка) T['TYPE'] = 'L' -- Тип ('L' - лимитированная, 'M' - рыночная) T['OPERATION'] = operation -- Операция ('B' - buy, или 'S' - sell) T['PRICE'] = GetCorrectPrice(price) -- Цена T['QUANTITY'] = tostring(qty) -- Количество -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит сообщение об ошибке message('Ошибка транзакции открытия/закрытия: '..Res) end end |
-- Выставляет заявку SetOrder = function( price, -- Цена заявки operation, -- Операция ('B' - buy, 'S' - sell) qty -- Количество ) -- Выставляет заявку -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local T = {} T['TRANS_ID'] = tostring(trans_id) -- Номер транзакции T['ACCOUNT'] = ACCOUNT -- Код счета T['CLASSCODE'] = CLASS_CODE -- Код класса T['SECCODE'] = SEC_CODE -- Код инструмента T['ACTION'] = 'NEW_ORDER' -- Тип транзакции ('NEW_ORDER' - новая заявка) T['TYPE'] = 'L' -- Тип ('L' - лимитированная, 'M' - рыночная) T['OPERATION'] = operation -- Операция ('B' - buy, или 'S' - sell) T['PRICE'] = GetCorrectPrice(price) -- Цена T['QUANTITY'] = tostring(qty) -- Количество -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит сообщение об ошибке message('Ошибка транзакции открытия/закрытия: '..Res) end end
1 2 3 4 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента trans_id = os.time() -- ID транзакции |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента trans_id = os.time() -- ID транзакции
Так же, для работы функции в скрипте должны присутствовать функции:
GetPriceForMarketOrder()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | -- Выставляет рыночную (по сути) заявку SetMarketOrder = function( operation, -- Операция ('B' - buy, 'S' - sell) qty -- Количество ) -- Выставляет рыночную заявку -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local T = {} T['TRANS_ID'] = tostring(trans_id) -- Номер транзакции T['ACCOUNT'] = ACCOUNT -- Код счета T['CLASSCODE'] = CLASS_CODE -- Код класса T['SECCODE'] = SEC_CODE -- Код инструмента T['ACTION'] = 'NEW_ORDER' -- Тип транзакции ('NEW_ORDER' - новая заявка) T['TYPE'] = 'L' -- Тип ('L' - лимитированная, 'M' - рыночная) T['OPERATION'] = operation -- Операция ('B' - buy, или 'S' - sell) T['PRICE'] = GetPriceForMarketOrder(operation) -- Цена T['QUANTITY'] = tostring(qty) -- Количество -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит сообщение об ошибке message('Ошибка транзакции открытия/закрытия по рынку: '..Res) end end |
-- Выставляет рыночную (по сути) заявку SetMarketOrder = function( operation, -- Операция ('B' - buy, 'S' - sell) qty -- Количество ) -- Выставляет рыночную заявку -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local T = {} T['TRANS_ID'] = tostring(trans_id) -- Номер транзакции T['ACCOUNT'] = ACCOUNT -- Код счета T['CLASSCODE'] = CLASS_CODE -- Код класса T['SECCODE'] = SEC_CODE -- Код инструмента T['ACTION'] = 'NEW_ORDER' -- Тип транзакции ('NEW_ORDER' - новая заявка) T['TYPE'] = 'L' -- Тип ('L' - лимитированная, 'M' - рыночная) T['OPERATION'] = operation -- Операция ('B' - buy, или 'S' - sell) T['PRICE'] = GetPriceForMarketOrder(operation) -- Цена T['QUANTITY'] = tostring(qty) -- Количество -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит сообщение об ошибке message('Ошибка транзакции открытия/закрытия по рынку: '..Res) end end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | -- Возвращает среднюю цену сделок по заявке GetOrderAverTradesPrice = function(order_num) -- Находит кол-во исполненных лотов в заявке local num = getNumberOf('orders') local order = nil local order_qty = 0 for i=num-1,0,-1 do order = getItem('orders', i) if order.order_num == order_num then order_qty = order.qty - order.balance break end end -- Находит среднюю цену local sum = 0 local find_lots = 0 local trade = nil num = getNumberOf('trades') for i=num-1,0,-1 do trade = getItem('trades', i) if trade.order_num == order_num then sum = sum + trade.qty * trade.price find_lots = find_lots + trade.qty if find_lots == order_qty then break end end end return sum/order_qty end |
-- Возвращает среднюю цену сделок по заявке GetOrderAverTradesPrice = function(order_num) -- Находит кол-во исполненных лотов в заявке local num = getNumberOf('orders') local order = nil local order_qty = 0 for i=num-1,0,-1 do order = getItem('orders', i) if order.order_num == order_num then order_qty = order.qty - order.balance break end end -- Находит среднюю цену local sum = 0 local find_lots = 0 local trade = nil num = getNumberOf('trades') for i=num-1,0,-1 do trade = getItem('trades', i) if trade.order_num == order_num then sum = sum + trade.qty * trade.price find_lots = find_lots + trade.qty if find_lots == order_qty then break end end end return sum/order_qty end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -- Проверяет наличие в системе заявки с определенным ID транзакции CheckOrder = function(id) -- Перебирает таблицу заявок от последней к первой for i=getNumberOf('orders') - 1, 0, -1 do -- Получает заявку из строки таблицы с индексом i local order = getItem('orders', i) -- Если ID транзакции совпадает if order.trans_id == id then return true end end -- Заявка с нужным ID транзакции не найдена return false end |
-- Проверяет наличие в системе заявки с определенным ID транзакции CheckOrder = function(id) -- Перебирает таблицу заявок от последней к первой for i=getNumberOf('orders') - 1, 0, -1 do -- Получает заявку из строки таблицы с индексом i local order = getItem('orders', i) -- Если ID транзакции совпадает if order.trans_id == id then return true end end -- Заявка с нужным ID транзакции не найдена return false end
1 2 3 4 5 6 7 8 9 10 11 12 13 | -- Возвращает номер заявки по ее ID транзакции GetOrderNum = function(id) -- Перебирает таблицу заявок от последней к первой for i=getNumberOf('orders') - 1, 0, -1 do -- Получает заявку из строки таблицы с индексом i local order = getItem('orders', i) -- Если ID транзакции совпадает if order.trans_id == id then -- Возвращает номер заявки return order.order_num end end end |
-- Возвращает номер заявки по ее ID транзакции GetOrderNum = function(id) -- Перебирает таблицу заявок от последней к первой for i=getNumberOf('orders') - 1, 0, -1 do -- Получает заявку из строки таблицы с индексом i local order = getItem('orders', i) -- Если ID транзакции совпадает if order.trans_id == id then -- Возвращает номер заявки return order.order_num end end end
1 | SEC_CODE = 'RIM7' -- Код инструмента |
SEC_CODE = 'RIM7' -- Код инструмента
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | -- Ожидает исполнения заявки по trans_id WaitOrderComplete = function(trans_id) -- Находит заявку по trans_id local order_line_idx = -1 while RUN and order_line_idx == -1 do sleep(100) -- Перебирает таблицу заявок с последней строки к первой local number = getNumberOf('orders') if number > 0 then if number > 1 then for i = number-1,0,-1 do -- Получает строку таблицы local order_line = getItem('orders', i) if order_line.trans_id == trans_id and order_line.sec_code == SEC_CODE then order_line_idx = i break end end else -- Получает строку таблицы local order_line = getItem('orders', 0) if order_line.trans_id == trans_id and order_line.sec_code == SEC_CODE then order_line_idx = 0 end end end end -- Ждет когда заявка будет полностью исполнена while RUN and getItem('orders', order_line_idx).balance ~= 0 do sleep(100) end -- Ждет появления всех сделок заявки в таблице сделок (для исключения ошибок дальнейшей обработки события) -- Узнает количество лотов в заявке local qty = getItem('orders', order_line_idx).qty -- Счетчик найденных лотов local lots_counter = 0 -- Индекс строки последней обработанной сделки local last_complete_index = -1 while RUN and lots_counter ~= qty do -- Перебирает еще не обработанные строки таблицы сделок local last_index = getNumberOf('trades')-1 local tmp_index = 0 if last_complete_index + 1 <= last_index then for i = last_complete_index + 1, last_index do -- Получает строку таблицы local trade_line = getItem('trades', i) -- Если сделка с нужным ID, и сделка по нужному инструменту if trade_line.trans_id == trans_id and trade_line.sec_code == SEC_CODE then -- Увеличивает счетчик lots_counter = lots_counter + trade_line.qty -- Если найдены все сделки if lots_counter == qty then break end end tmp_index = i end last_complete_index = tmp_index end sleep(100) end end |
-- Ожидает исполнения заявки по trans_id WaitOrderComplete = function(trans_id) -- Находит заявку по trans_id local order_line_idx = -1 while RUN and order_line_idx == -1 do sleep(100) -- Перебирает таблицу заявок с последней строки к первой local number = getNumberOf('orders') if number > 0 then if number > 1 then for i = number-1,0,-1 do -- Получает строку таблицы local order_line = getItem('orders', i) if order_line.trans_id == trans_id and order_line.sec_code == SEC_CODE then order_line_idx = i break end end else -- Получает строку таблицы local order_line = getItem('orders', 0) if order_line.trans_id == trans_id and order_line.sec_code == SEC_CODE then order_line_idx = 0 end end end end -- Ждет когда заявка будет полностью исполнена while RUN and getItem('orders', order_line_idx).balance ~= 0 do sleep(100) end -- Ждет появления всех сделок заявки в таблице сделок (для исключения ошибок дальнейшей обработки события) -- Узнает количество лотов в заявке local qty = getItem('orders', order_line_idx).qty -- Счетчик найденных лотов local lots_counter = 0 -- Индекс строки последней обработанной сделки local last_complete_index = -1 while RUN and lots_counter ~= qty do -- Перебирает еще не обработанные строки таблицы сделок local last_index = getNumberOf('trades')-1 local tmp_index = 0 if last_complete_index + 1 <= last_index then for i = last_complete_index + 1, last_index do -- Получает строку таблицы local trade_line = getItem('trades', i) -- Если сделка с нужным ID, и сделка по нужному инструменту if trade_line.trans_id == trans_id and trade_line.sec_code == SEC_CODE then -- Увеличивает счетчик lots_counter = lots_counter + trade_line.qty -- Если найдены все сделки if lots_counter == qty then break end end tmp_index = i end last_complete_index = tmp_index end sleep(100) end end
1 2 3 4 5 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента EXPIRY_DATE = 'TODAY' -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД' trans_id = os.time() -- ID транзакции |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента EXPIRY_DATE = 'TODAY' -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД' trans_id = os.time() -- ID транзакции
Так же, для работы функции в скрипте должны присутствовать функции:
GetCorrectPrice()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | -- Выставляет стоп-лимит заявку Set_SL = function( operation, -- Операция ('B' - buy, 'S' - sell) stop_price, -- Цена Стоп-Лосса qty -- Количество в лотах ) -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Вычисляет цену, по которой выставится заявка при срабатывании стопа local price = stop_price - 50*PriceStep if operation == 'B' then price = stop_price + 50*PriceStep end -- Заполняет структуру для отправки транзакции на Стоп-лосс local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACCOUNT'] = ACCOUNT T['ACTION'] = 'NEW_STOP_ORDER' -- Тип заявки T['OPERATION'] = operation -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL)) T['QUANTITY'] = tostring(qty) -- Количество в лотах T['STOPPRICE'] = GetCorrectPrice(stop_price) -- Цена Стоп-Лосса T['PRICE'] = GetCorrectPrice(price) -- Цена, по которой выставится заявка при срабатывании Стоп-Лосса (для рыночной заявки по акциям должна быть 0) T['EXPIRY_DATE'] = EXPIRY_DATE -- 'TODAY', 'GTC', или время -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит ошибку message('Ошибка транзакции стоп-лимит: '..Res) end end |
-- Выставляет стоп-лимит заявку Set_SL = function( operation, -- Операция ('B' - buy, 'S' - sell) stop_price, -- Цена Стоп-Лосса qty -- Количество в лотах ) -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Вычисляет цену, по которой выставится заявка при срабатывании стопа local price = stop_price - 50*PriceStep if operation == 'B' then price = stop_price + 50*PriceStep end -- Заполняет структуру для отправки транзакции на Стоп-лосс local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACCOUNT'] = ACCOUNT T['ACTION'] = 'NEW_STOP_ORDER' -- Тип заявки T['OPERATION'] = operation -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL)) T['QUANTITY'] = tostring(qty) -- Количество в лотах T['STOPPRICE'] = GetCorrectPrice(stop_price) -- Цена Стоп-Лосса T['PRICE'] = GetCorrectPrice(price) -- Цена, по которой выставится заявка при срабатывании Стоп-Лосса (для рыночной заявки по акциям должна быть 0) T['EXPIRY_DATE'] = EXPIRY_DATE -- 'TODAY', 'GTC', или время -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит ошибку message('Ошибка транзакции стоп-лимит: '..Res) end end
1 2 3 4 5 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента EXPIRY_DATE = 'TODAY' -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД' trans_id = os.time() -- ID транзакции |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента EXPIRY_DATE = 'TODAY' -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД' trans_id = os.time() -- ID транзакции
Так же, для работы функции в скрипте должна присутствовать функция:
GetCorrectPrice()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | -- Выставляет "Тейк профит" заявку SetTP = function( operation, -- Операция ('B', или 'S') pos_price, -- Цена позиции, на которую выставляется стоп-заявка qty, -- Количество лотов profit_size -- Размер профита в шагах цены ) -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Получает минимальный шаг цены local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- Получает максимально возможную цену заявки local PriceMax = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMAX').param_value) -- Получает минимально возможную цену заявки local PriceMin = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMIN').param_value) -- Заполняет структуру для отправки транзакции на Стоп-лосс и Тэйк-профит local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACCOUNT'] = ACCOUNT T['ACTION'] = 'NEW_STOP_ORDER' -- Тип заявки T['STOP_ORDER_KIND'] = 'TAKE_PROFIT_STOP_ORDER' -- Тип стоп-заявки T['OPERATION'] = operation -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL)) T['QUANTITY'] = tostring(qty) -- Количество в лотах -- Вычисляет цену профита local stopprice = 0 if operation == 'B' then stopprice = pos_price - profit_size*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and stopprice < PriceMin then stopprice = PriceMin end elseif operation == 'S' then stopprice = pos_price + profit_size*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and stopprice > PriceMax then stopprice = PriceMax end end T['STOPPRICE'] = GetCorrectPrice(stopprice) -- Цена Тэйк-Профита T['OFFSET'] = '0' -- отступ T['OFFSET_UNITS'] = 'PRICE_UNITS' -- в шагах цены local spread = 50*PriceStep if operation == 'B' then if PriceMax ~= nil and PriceMax ~= 0 and stopprice + spread > PriceMax then spread = PriceMax - stopprice - 1*PriceStep end elseif operation == 'S' then if PriceMin ~= nil and PriceMin ~= 0 and stopprice - spread < PriceMin then spread = stopprice - PriceMin - 1*PriceStep end end T['SPREAD'] = GetCorrectPrice(spread) -- Защитный спред T['SPREAD_UNITS'] = 'PRICE_UNITS' -- в шагах цены T['EXPIRY_DATE'] = EXPIRY_DATE -- 'TODAY', 'GTC', или время -- Отправляет транзакцию local Res = sendTransaction(T) if Res ~= '' then message('Ошибка выставления стоп-заявки: '..Res) end end |
-- Выставляет "Тейк профит" заявку SetTP = function( operation, -- Операция ('B', или 'S') pos_price, -- Цена позиции, на которую выставляется стоп-заявка qty, -- Количество лотов profit_size -- Размер профита в шагах цены ) -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Получает минимальный шаг цены local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- Получает максимально возможную цену заявки local PriceMax = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMAX').param_value) -- Получает минимально возможную цену заявки local PriceMin = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMIN').param_value) -- Заполняет структуру для отправки транзакции на Стоп-лосс и Тэйк-профит local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACCOUNT'] = ACCOUNT T['ACTION'] = 'NEW_STOP_ORDER' -- Тип заявки T['STOP_ORDER_KIND'] = 'TAKE_PROFIT_STOP_ORDER' -- Тип стоп-заявки T['OPERATION'] = operation -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL)) T['QUANTITY'] = tostring(qty) -- Количество в лотах -- Вычисляет цену профита local stopprice = 0 if operation == 'B' then stopprice = pos_price - profit_size*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and stopprice < PriceMin then stopprice = PriceMin end elseif operation == 'S' then stopprice = pos_price + profit_size*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and stopprice > PriceMax then stopprice = PriceMax end end T['STOPPRICE'] = GetCorrectPrice(stopprice) -- Цена Тэйк-Профита T['OFFSET'] = '0' -- отступ T['OFFSET_UNITS'] = 'PRICE_UNITS' -- в шагах цены local spread = 50*PriceStep if operation == 'B' then if PriceMax ~= nil and PriceMax ~= 0 and stopprice + spread > PriceMax then spread = PriceMax - stopprice - 1*PriceStep end elseif operation == 'S' then if PriceMin ~= nil and PriceMin ~= 0 and stopprice - spread < PriceMin then spread = stopprice - PriceMin - 1*PriceStep end end T['SPREAD'] = GetCorrectPrice(spread) -- Защитный спред T['SPREAD_UNITS'] = 'PRICE_UNITS' -- в шагах цены T['EXPIRY_DATE'] = EXPIRY_DATE -- 'TODAY', 'GTC', или время -- Отправляет транзакцию local Res = sendTransaction(T) if Res ~= '' then message('Ошибка выставления стоп-заявки: '..Res) end end
1 2 3 4 5 | ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента EXPIRY_DATE = 'TODAY' -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД' trans_id = os.time() -- ID транзакции |
ACCOUNT = 'SPBFUT00c41' -- Код счета CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента EXPIRY_DATE = 'TODAY' -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД' trans_id = os.time() -- ID транзакции
Так же, для работы функции в скрипте должна присутствовать функция:
GetCorrectPrice()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | -- Выставляет "Тейк профит и Стоп лимит" заявку SetTP_SL = function( operation, -- Операция ('B', или 'S') pos_price, -- Цена позиции, на которую выставляется стоп-заявка qty, -- Количество лотов profit_size, -- Размер профита в шагах цены stop_size -- Размер стопа в шагах цены ) -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Получает минимальный шаг цены local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- Получает максимально возможную цену заявки local PriceMax = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMAX').param_value) -- Получает минимально возможную цену заявки local PriceMin = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMIN').param_value) -- Заполняет структуру для отправки транзакции на Стоп-лосс и Тэйк-профит local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACCOUNT'] = ACCOUNT T['ACTION'] = 'NEW_STOP_ORDER' -- Тип заявки T['STOP_ORDER_KIND'] = 'TAKE_PROFIT_AND_STOP_LIMIT_ORDER' -- Тип стоп-заявки T['OPERATION'] = operation -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL)) T['QUANTITY'] = tostring(qty) -- Количество в лотах -- Вычисляет цену профита local stopprice = 0 if operation == 'B' then stopprice = pos_price - profit_size*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and stopprice < PriceMin then stopprice = PriceMin end elseif operation == 'S' then stopprice = pos_price + profit_size*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and stopprice > PriceMax then stopprice = PriceMax end end T['STOPPRICE'] = GetCorrectPrice(stopprice) -- Цена Тэйк-Профита T['OFFSET'] = '0' -- отступ T['OFFSET_UNITS'] = 'PRICE_UNITS' -- в шагах цены local spread = 50*PriceStep if operation == 'B' then if PriceMax ~= nil and PriceMax ~= 0 and stopprice + spread > PriceMax then spread = PriceMax - stopprice - 1*PriceStep end elseif operation == 'S' then if PriceMin ~= nil and PriceMin ~= 0 and stopprice - spread < PriceMin then spread = stopprice - PriceMin - 1*PriceStep end end T['SPREAD'] = GetCorrectPrice(spread) -- Защитный спред T['SPREAD_UNITS'] = 'PRICE_UNITS' -- в шагах цены T['MARKET_TAKE_PROFIT'] = 'NO' -- 'YES', или 'NO' -- Вычисляет цену стопа local stopprice2 = 0 if operation == 'B' then stopprice2 = pos_price + stop_size*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and stopprice2 > PriceMax then stopprice2 = PriceMax end elseif operation == 'S' then stopprice2 = pos_price - stop_size*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and stopprice2 < PriceMin then stopprice2 = PriceMin end end T['STOPPRICE2'] = GetCorrectPrice(stopprice2) -- Цена Стоп-Лосса -- Вычисляет цену, по которой выставится заявка при срабатывании стопа local price = 0 if operation == 'B' then price = stopprice2 + 50*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and price > PriceMax then price = PriceMax end elseif operation == 'S' then price = stopprice2 - 50*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and price < PriceMin then price = PriceMin end end T['PRICE'] = GetCorrectPrice(price) -- Цена, по которой выставится заявка при срабатывании Стоп-Лосса (для рыночной заявки по акциям должна быть 0) T['MARKET_STOP_LIMIT'] = 'NO' -- 'YES', или 'NO' T['EXPIRY_DATE'] = EXPIRY_DATE -- 'TODAY', 'GTC', или время T['IS_ACTIVE_IN_TIME'] = 'NO' -- Признак действия заявки типа «Тэйк-профит и стоп-лимит» в течение определенного интервала времени. Значения «YES» или «NO» -- Отправляет транзакцию local Res = sendTransaction(T) if Res ~= '' then message('Ошибка выставления стоп-заявки: '..Res) end end |
-- Выставляет "Тейк профит и Стоп лимит" заявку SetTP_SL = function( operation, -- Операция ('B', или 'S') pos_price, -- Цена позиции, на которую выставляется стоп-заявка qty, -- Количество лотов profit_size, -- Размер профита в шагах цены stop_size -- Размер стопа в шагах цены ) -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Получает минимальный шаг цены local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value) -- Получает максимально возможную цену заявки local PriceMax = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMAX').param_value) -- Получает минимально возможную цену заявки local PriceMin = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'PRICEMIN').param_value) -- Заполняет структуру для отправки транзакции на Стоп-лосс и Тэйк-профит local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACCOUNT'] = ACCOUNT T['ACTION'] = 'NEW_STOP_ORDER' -- Тип заявки T['STOP_ORDER_KIND'] = 'TAKE_PROFIT_AND_STOP_LIMIT_ORDER' -- Тип стоп-заявки T['OPERATION'] = operation -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL)) T['QUANTITY'] = tostring(qty) -- Количество в лотах -- Вычисляет цену профита local stopprice = 0 if operation == 'B' then stopprice = pos_price - profit_size*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and stopprice < PriceMin then stopprice = PriceMin end elseif operation == 'S' then stopprice = pos_price + profit_size*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and stopprice > PriceMax then stopprice = PriceMax end end T['STOPPRICE'] = GetCorrectPrice(stopprice) -- Цена Тэйк-Профита T['OFFSET'] = '0' -- отступ T['OFFSET_UNITS'] = 'PRICE_UNITS' -- в шагах цены local spread = 50*PriceStep if operation == 'B' then if PriceMax ~= nil and PriceMax ~= 0 and stopprice + spread > PriceMax then spread = PriceMax - stopprice - 1*PriceStep end elseif operation == 'S' then if PriceMin ~= nil and PriceMin ~= 0 and stopprice - spread < PriceMin then spread = stopprice - PriceMin - 1*PriceStep end end T['SPREAD'] = GetCorrectPrice(spread) -- Защитный спред T['SPREAD_UNITS'] = 'PRICE_UNITS' -- в шагах цены T['MARKET_TAKE_PROFIT'] = 'NO' -- 'YES', или 'NO' -- Вычисляет цену стопа local stopprice2 = 0 if operation == 'B' then stopprice2 = pos_price + stop_size*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and stopprice2 > PriceMax then stopprice2 = PriceMax end elseif operation == 'S' then stopprice2 = pos_price - stop_size*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and stopprice2 < PriceMin then stopprice2 = PriceMin end end T['STOPPRICE2'] = GetCorrectPrice(stopprice2) -- Цена Стоп-Лосса -- Вычисляет цену, по которой выставится заявка при срабатывании стопа local price = 0 if operation == 'B' then price = stopprice2 + 50*PriceStep if PriceMax ~= nil and PriceMax ~= 0 and price > PriceMax then price = PriceMax end elseif operation == 'S' then price = stopprice2 - 50*PriceStep if PriceMin ~= nil and PriceMin ~= 0 and price < PriceMin then price = PriceMin end end T['PRICE'] = GetCorrectPrice(price) -- Цена, по которой выставится заявка при срабатывании Стоп-Лосса (для рыночной заявки по акциям должна быть 0) T['MARKET_STOP_LIMIT'] = 'NO' -- 'YES', или 'NO' T['EXPIRY_DATE'] = EXPIRY_DATE -- 'TODAY', 'GTC', или время T['IS_ACTIVE_IN_TIME'] = 'NO' -- Признак действия заявки типа «Тэйк-профит и стоп-лимит» в течение определенного интервала времени. Значения «YES» или «NO» -- Отправляет транзакцию local Res = sendTransaction(T) if Res ~= '' then message('Ошибка выставления стоп-заявки: '..Res) end end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -- Проверяет наличие в системе стоп-заявки с определенным ID транзакции CheckStopOrder = function(id) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если ID транзакции совпадает if stop_order.trans_id == id then return true end end -- Стоп-заявка с нужным ID не найдена return false end |
-- Проверяет наличие в системе стоп-заявки с определенным ID транзакции CheckStopOrder = function(id) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если ID транзакции совпадает if stop_order.trans_id == id then return true end end -- Стоп-заявка с нужным ID не найдена return false end
1 2 3 4 5 6 7 8 9 10 11 12 13 | -- Возвращает номер стоп-заявки по ее ID транзакции GetStopOrderNum = function(id) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если ID транзакции совпадает if stop_order.trans_id == id then -- Возвращает номер стоп-заявки return stop_order.order_num end end end |
-- Возвращает номер стоп-заявки по ее ID транзакции GetStopOrderNum = function(id) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если ID транзакции совпадает if stop_order.trans_id == id then -- Возвращает номер стоп-заявки return stop_order.order_num end end end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -- Проверяет по номеру активна ли стоп-заявка CheckStopOrderActive = function(order_num) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если номер транзакции совпадает if stop_order.order_num == order_num then -- Если стоп-заявка активна if bit.test(stop_order.flags, 0) then return true else return false end end end end |
-- Проверяет по номеру активна ли стоп-заявка CheckStopOrderActive = function(order_num) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если номер транзакции совпадает if stop_order.order_num == order_num then -- Если стоп-заявка активна if bit.test(stop_order.flags, 0) then return true else return false end end end end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -- Проверяет по номеру исполнена ли стоп-заявка CheckStopOrderCompleted = function(order_num) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если номер транзакции совпадает if stop_order.order_num == order_num then -- Если стоп-заявка не активна и не снята if not bit.test(stop_order.flags, 0) and not bit.test(stop_order.flags, 1) then return true else return false end end end end |
-- Проверяет по номеру исполнена ли стоп-заявка CheckStopOrderCompleted = function(order_num) -- Перебирает таблицу стоп-заявок от последней к первой for i=getNumberOf('stop_orders') - 1, 0, -1 do -- Получает стоп-заявку из строки таблицы с индексом i local stop_order = getItem('stop_orders', i) -- Если номер транзакции совпадает if stop_order.order_num == order_num then -- Если стоп-заявка не активна и не снята if not bit.test(stop_order.flags, 0) and not bit.test(stop_order.flags, 1) then return true else return false end end end end
1 2 3 4 | CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента RUN = true -- Флаг поддержания работы "бесконечного" цикла в функции main trans_id = os.time() -- ID транзакции |
CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента RUN = true -- Флаг поддержания работы "бесконечного" цикла в функции main trans_id = os.time() -- ID транзакции
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | -- Снимает заявку KillOrder = function( order_num -- Номер снимаемой заявки ) -- Находит заявку local index = 0 local find_order = false while RUN and not find_order do for i=getNumberOf('orders')-1,0,-1 do local order = getItem('orders', i) if order.order_num == order_num then -- Если заявка уже была исполнена (не активна) if not bit.test(order.flags, 0) then return false end index = i find_order = true break end end end if not find_order then message('Ошибка: не найдена заявка!') return false end -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции на снятие заявки local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACTION'] = 'KILL_ORDER' -- Тип заявки T['ORDER_KEY'] = tostring(order_num) -- Номер заявки, снимаемой из торговой системы -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит ошибку message('Ошибка снятия заявки: '..Res) return false end -- Ожидает когда заявка перестанет быть активна local active = true while RUN do local order = getItem('orders', index) -- Если заявка не активна if not bit.test(order.flags, 0) then -- Если заявка успела исполниться if not bit.test(order.flags, 1) then return false end active = false break end sleep(10) end if active then message('Возникла неизвестная ошибка при снятии ЗАЯВКИ') return false end return true end |
-- Снимает заявку KillOrder = function( order_num -- Номер снимаемой заявки ) -- Находит заявку local index = 0 local find_order = false while RUN and not find_order do for i=getNumberOf('orders')-1,0,-1 do local order = getItem('orders', i) if order.order_num == order_num then -- Если заявка уже была исполнена (не активна) if not bit.test(order.flags, 0) then return false end index = i find_order = true break end end end if not find_order then message('Ошибка: не найдена заявка!') return false end -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции на снятие заявки local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACTION'] = 'KILL_ORDER' -- Тип заявки T['ORDER_KEY'] = tostring(order_num) -- Номер заявки, снимаемой из торговой системы -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит ошибку message('Ошибка снятия заявки: '..Res) return false end -- Ожидает когда заявка перестанет быть активна local active = true while RUN do local order = getItem('orders', index) -- Если заявка не активна if not bit.test(order.flags, 0) then -- Если заявка успела исполниться if not bit.test(order.flags, 1) then return false end active = false break end sleep(10) end if active then message('Возникла неизвестная ошибка при снятии ЗАЯВКИ') return false end return true end
1 2 3 4 | CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента RUN = true -- Флаг поддержания работы "бесконечного" цикла в функции main trans_id = os.time() -- ID транзакции |
CLASS_CODE = 'SPBFUT' -- Код класса SEC_CODE = 'RIM7' -- Код инструмента RUN = true -- Флаг поддержания работы "бесконечного" цикла в функции main trans_id = os.time() -- ID транзакции
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | -- Снимает стоп-заявку Kill_SO = function( stop_order_num -- Номер снимаемой стоп-заявки ) -- Находит стоп-заявку local index = 0 local find_so = false while RUN and not find_so do for i=getNumberOf('stop_orders')-1,0,-1 do local stop_order = getItem('stop_orders', i) if stop_order.order_num == stop_order_num then -- Если стоп-заявка уже была исполнена (не активна) if not bit.test(stop_order.flags, 0) then return false end index = i find_so = true break end end end if not find_so then message('Ошибка: не найдена стоп-заявка!') return false end -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции на снятие стоп-заявки local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACTION'] = 'KILL_STOP_ORDER' -- Тип заявки T['STOP_ORDER_KEY'] = tostring(stop_order_num) -- Номер стоп-заявки, снимаемой из торговой системы -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит ошибку message('Ошибка снятия стоп-заявки: '..Res) return false end -- Ожидает когда стоп-заявка перестанет быть активна local active = true while RUN do local stop_order = getItem('stop_orders', index) -- Если стоп-заявка не активна if not bit.test(stop_order.flags, 0) then -- Если стоп-заявка успела исполниться if not bit.test(stop_order.flags, 1) then return false end active = false break end sleep(10) end if active then message('Возникла неизвестная ошибка при снятии СТОП-ЗАЯВКИ') return false end return true end |
-- Снимает стоп-заявку Kill_SO = function( stop_order_num -- Номер снимаемой стоп-заявки ) -- Находит стоп-заявку local index = 0 local find_so = false while RUN and not find_so do for i=getNumberOf('stop_orders')-1,0,-1 do local stop_order = getItem('stop_orders', i) if stop_order.order_num == stop_order_num then -- Если стоп-заявка уже была исполнена (не активна) if not bit.test(stop_order.flags, 0) then return false end index = i find_so = true break end end end if not find_so then message('Ошибка: не найдена стоп-заявка!') return false end -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции на снятие стоп-заявки local T = {} T['TRANS_ID'] = tostring(trans_id) T['CLASSCODE'] = CLASS_CODE T['SECCODE'] = SEC_CODE T['ACTION'] = 'KILL_STOP_ORDER' -- Тип заявки T['STOP_ORDER_KEY'] = tostring(stop_order_num) -- Номер стоп-заявки, снимаемой из торговой системы -- Отправляет транзакцию local Res = sendTransaction(T) -- Если при отправке транзакции возникла ошибка if Res ~= '' then -- Выводит ошибку message('Ошибка снятия стоп-заявки: '..Res) return false end -- Ожидает когда стоп-заявка перестанет быть активна local active = true while RUN do local stop_order = getItem('stop_orders', index) -- Если стоп-заявка не активна if not bit.test(stop_order.flags, 0) then -- Если стоп-заявка успела исполниться if not bit.test(stop_order.flags, 1) then return false end active = false break end sleep(10) end if active then message('Возникла неизвестная ошибка при снятии СТОП-ЗАЯВКИ') return false end return true end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | -- Создает объект стека максимальным размером 3 элемента (при добавлении более старые будут затираться более новыми) MyStack = StackFIFO(3) -- Создает 3 элемента local elem_1 = 'Элемент 1' local elem_2 = 'Элемент 2' local elem_3 = 'Элемент 3' -- Добавляет 3 элемента в стек MyStack:Push(elem_1) MyStack:Push(elem_2) MyStack:Push(elem_3) -- Получает самый ранний добавленный элемент local elem = MyStack:Pop() -- Теперь в elem находится элемент 1, а в стеке остались элементы 2 и 3 -- Добавим еще один элемент в стек MyStack:Push('Элемент 4') -- Теперь в стеке 4,2,3 -- Добавим еще один элемент в стек MyStack:Push('Элемент 5') -- 5-й элемент затер 2-й и в стеке сейчас 4,5,3 -- Получает самый ранний добавленный элемент local elem = MyStack:Pop() -- Теперь в elem элемент 3, а в стеке остались 4,5 -- Объект стека предоставляет следующие функции: -- Возвращает количество элементов в стеке MyStack:Count() -- Добавляет запись в стек MyStack:Push() -- Извлекает самую старую запись из стека (с удалением) MyStack:Pop() -- Возвращает последнюю запись без ее удаления MyStack:GetLast() -- Заменяет последний элемент новым MyStack:ChangeLast(new_elem) -- Возвращает содержимое в виде массива, где самый старый элемент под индексом 1 MyStack:Array() |
-- Создает объект стека максимальным размером 3 элемента (при добавлении более старые будут затираться более новыми) MyStack = StackFIFO(3) -- Создает 3 элемента local elem_1 = 'Элемент 1' local elem_2 = 'Элемент 2' local elem_3 = 'Элемент 3' -- Добавляет 3 элемента в стек MyStack:Push(elem_1) MyStack:Push(elem_2) MyStack:Push(elem_3) -- Получает самый ранний добавленный элемент local elem = MyStack:Pop() -- Теперь в elem находится элемент 1, а в стеке остались элементы 2 и 3 -- Добавим еще один элемент в стек MyStack:Push('Элемент 4') -- Теперь в стеке 4,2,3 -- Добавим еще один элемент в стек MyStack:Push('Элемент 5') -- 5-й элемент затер 2-й и в стеке сейчас 4,5,3 -- Получает самый ранний добавленный элемент local elem = MyStack:Pop() -- Теперь в elem элемент 3, а в стеке остались 4,5 -- Объект стека предоставляет следующие функции: -- Возвращает количество элементов в стеке MyStack:Count() -- Добавляет запись в стек MyStack:Push() -- Извлекает самую старую запись из стека (с удалением) MyStack:Pop() -- Возвращает последнюю запись без ее удаления MyStack:GetLast() -- Заменяет последний элемент новым MyStack:ChangeLast(new_elem) -- Возвращает содержимое в виде массива, где самый старый элемент под индексом 1 MyStack:Array()
Код, который нужно добавить в скрипт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | -- Необходимые объявления для ускорения работы стека local table_insert = table.insert local table_sinsert = table.sinsert local table_remove = table.remove local table_sremove = table.sremove -- КЛАСС СТЕКА (FIFO) StackFIFO = function(max) local Stack = {} Stack.items = {} -- Массив для стека Stack.idx_for_add = 1 -- Индекс для добавления следующей, или первой записи Stack.idx_for_get = 1 -- Индекс для изъятия следующей, или первой записи Stack.count = 0 -- Количество находящихся в стеке записей Stack.max = max -- Максимально возможное количество записей в стеке (при переполнении старые записи будут замещаться новыми) -- Возвращает количество элементов в стеке Stack.Count = function(this) return this.count end -- Добавляет запись в стек Stack.Push = function(this, NewEntry) -- Добавляет запись в стек if this.items[this.idx_for_add] ~= nil then table_sremove(this.items, this.idx_for_add) end table_sinsert(this.items, this.idx_for_add, NewEntry) -- Корректирует счетчик находящихся в стеке записей if this.count < this.max then this.count = this.count + 1 end -- Увеличивает индекс для добавления следующей записи this.idx_for_add = this.idx_for_add + 1 -- Если индекс больше максимально допустимого, то следующая запись будет добавляться в начало стека if this.idx_for_add > this.max then this.idx_for_add = 1 end -- Если изъятие записей отстало от записи (новая запись переписала старую), то увеличивает индекс для изъятия следующей записи if this.idx_for_add - this.idx_for_get == 1 and this.count > 1 then -- смещение внутри стека this.idx_for_get = this.idx_for_get + 1 -- Добавил в конец, когда индекс для изъятия тоже был в конце и количество не равно 0 elseif this.idx_for_get - this.idx_for_add == this.max - 1 and this.count > 1 then this.idx_for_get = 1 end end -- Извлекает самую старую запись из стека (с удалением) Stack.Pop = function(this) local OldInxForGet = this.idx_for_get if this.count == 0 then return nil end -- Уменьшает количество записей на 1 this.count = this.count - 1 -- Корректирует, если это была единственная запись if this.count == -1 then this.count = 0 this.idx_for_get = this.idx_for_add -- Выравнивает индексы else -- Если еще есть записи -- Сдвигает индекс изъятия на 1 вправо this.idx_for_get = this.idx_for_get + 1 -- Корректирует, если достигнут конец if this.idx_for_get > this.max then this.idx_for_get = 1 end end return this.items[OldInxForGet] end -- Возвращает последнюю запись без ее удаления Stack.GetLast = function(this) if this.idx_for_get > 1 then return this.items[this.idx_for_get - 1] else return this.items[#this.items] end end -- Заменяет последний элемент новым Stack.ChangeLast = function(this, new_elem) if this.idx_for_get > 1 then this.items[this.idx_for_get - 1] = new_elem else this.items[#this.items] = new_elem end end -- Возвращает содержимое в виде массива, где самый старый элемент под индексом 1 Stack.Array = function(this) local Array = {} for i = this.idx_for_get, #this.items do table_insert(Array, this.items[i]) end for i = 1, this.idx_for_get - 1 do table_insert(Array, this.items[i]) end return Array end return Stack end |
-- Необходимые объявления для ускорения работы стека local table_insert = table.insert local table_sinsert = table.sinsert local table_remove = table.remove local table_sremove = table.sremove -- КЛАСС СТЕКА (FIFO) StackFIFO = function(max) local Stack = {} Stack.items = {} -- Массив для стека Stack.idx_for_add = 1 -- Индекс для добавления следующей, или первой записи Stack.idx_for_get = 1 -- Индекс для изъятия следующей, или первой записи Stack.count = 0 -- Количество находящихся в стеке записей Stack.max = max -- Максимально возможное количество записей в стеке (при переполнении старые записи будут замещаться новыми) -- Возвращает количество элементов в стеке Stack.Count = function(this) return this.count end -- Добавляет запись в стек Stack.Push = function(this, NewEntry) -- Добавляет запись в стек if this.items[this.idx_for_add] ~= nil then table_sremove(this.items, this.idx_for_add) end table_sinsert(this.items, this.idx_for_add, NewEntry) -- Корректирует счетчик находящихся в стеке записей if this.count < this.max then this.count = this.count + 1 end -- Увеличивает индекс для добавления следующей записи this.idx_for_add = this.idx_for_add + 1 -- Если индекс больше максимально допустимого, то следующая запись будет добавляться в начало стека if this.idx_for_add > this.max then this.idx_for_add = 1 end -- Если изъятие записей отстало от записи (новая запись переписала старую), то увеличивает индекс для изъятия следующей записи if this.idx_for_add - this.idx_for_get == 1 and this.count > 1 then -- смещение внутри стека this.idx_for_get = this.idx_for_get + 1 -- Добавил в конец, когда индекс для изъятия тоже был в конце и количество не равно 0 elseif this.idx_for_get - this.idx_for_add == this.max - 1 and this.count > 1 then this.idx_for_get = 1 end end -- Извлекает самую старую запись из стека (с удалением) Stack.Pop = function(this) local OldInxForGet = this.idx_for_get if this.count == 0 then return nil end -- Уменьшает количество записей на 1 this.count = this.count - 1 -- Корректирует, если это была единственная запись if this.count == -1 then this.count = 0 this.idx_for_get = this.idx_for_add -- Выравнивает индексы else -- Если еще есть записи -- Сдвигает индекс изъятия на 1 вправо this.idx_for_get = this.idx_for_get + 1 -- Корректирует, если достигнут конец if this.idx_for_get > this.max then this.idx_for_get = 1 end end return this.items[OldInxForGet] end -- Возвращает последнюю запись без ее удаления Stack.GetLast = function(this) if this.idx_for_get > 1 then return this.items[this.idx_for_get - 1] else return this.items[#this.items] end end -- Заменяет последний элемент новым Stack.ChangeLast = function(this, new_elem) if this.idx_for_get > 1 then this.items[this.idx_for_get - 1] = new_elem else this.items[#this.items] = new_elem end end -- Возвращает содержимое в виде массива, где самый старый элемент под индексом 1 Stack.Array = function(this) local Array = {} for i = this.idx_for_get, #this.items do table_insert(Array, this.items[i]) end for i = 1, this.idx_for_get - 1 do table_insert(Array, this.items[i]) end return Array end return Stack end
Готовая библиотека - распаковать в каталог с QUIK файл StaticVar.dll из архива и использовать \x32\StaticVar.dll - для QUIK 6.x и 7.x версий \x64\StaticVar.dll - для QUIK 8.x версий и более новых Возможности: Библиотека позволяет создать общее хранилище данных для нескольких Lua-скриптов, а также сохранять данные между запусками Lua-скрипта (в пределах одного запуска терминала QUIK!). Между запусками - сохраняйте в файлы самостоятельно. Каждый элемент сохраняется в виде пары "Назначаемое имя параметра" - "Значение". Поддерживается концепция "пространства имен" (Name Space): скрипт может назначить для себя текущий Name Space, после чего сохраняться и считываться данные будут только в пределах этого пространства. Имена данных, сохраняемых в разных Name Space, могут пересекаться, это будут разные данные. Если Name Space не назначен - используется "глобальное пространство" (по сути обособленное пространство имен nil). В любой момент текущее пространство имен может переключаться. (Name Space рекомендуется использовать только при надобности.) Поддерживаются функции: SetVar("var_name", var_data) -- создает переменную с именем "var_name" в текущем Name Space и записывает в нее значение var_data; если передать только 1 параметр или второй параметр задать равным nil - значение с именем "var_name" будет удалено из хранилища GetVar("var_name") -- возвращает сохраненное значение с именем "var_name" из текущего Name Space; если переменной с указанным именем нет - вернет nil UseNameSpace("NameSpace1") -- использовать пространство имен "NameSpace1"; если вызвать без параметров UseNameSpace() (или с пустой строкой "") - активным станет "неименованное" пространство имен; после старта скрипта Lua до вызова UseNameSpace с непустой строкой действует "неименованное" пространство имен GetCurrentNameSpace() -- получить текущее пространство имен; возвращает строку, если какое-то пространство имет выбрано вызовом GetCurrentNameSpace, либо nil, если используется "неименованное" пространство GetVarList() -- возвращает таблицу формата ["имя_переменной"]=значение, содержащую все установленные (и не удаленные) значения для текущего пространства имен; надо понимать, если заполнено много переменных-данных - то таблица будет большая, и ее заполнение окажется накладными SetVarList(table) -- из переданной в качестве аргумента таблицы формата ["var_name"]=var_data заполняет данные с указанными именами в текущем пространстве имен; список сохраненных данных не заменяется, а лишь дополняется из таблицы Clear() -- удаляет все сохранённые значения для текущего NameSpace (потребовалась для тестов) ClearAll() -- все значения из всех NameSpace (потребовалась для тестов) Корректно сохраняются (из var_data) и считываются следующие типы Lua: string boolean number table (любой вложенности) данные остальных типов при сохранении преобразуется в строку "как получится". Ограничения: передача данных между разными скриптами только в пределах одного процесса, т.е. одного QUIK;
Простой пример:
1 2 3 4 5 6 7 8 9 10 11 | -- Файл test-1.lua require("StaticVar") stv.UseNameSpace("testNS") function main() sleep(10000) stv.SetVar("xxx", "xxx-test-value") message("(test-1) " .. tostring(stv.GetCurrentNameSpace()) .. ".xxx=" .. tostring(stv.GetVar("xxx")), 1) end |
-- Файл test-1.lua require("StaticVar") stv.UseNameSpace("testNS") function main() sleep(10000) stv.SetVar("xxx", "xxx-test-value") message("(test-1) " .. tostring(stv.GetCurrentNameSpace()) .. ".xxx=" .. tostring(stv.GetVar("xxx")), 1) end
1 2 3 4 5 6 7 8 9 10 | -- Файл test-2.lua require("StaticVar") stv.UseNameSpace("testNS") function main() sleep(10000) message("(test-2) " .. tostring(stv.GetCurrentNameSpace()) .. ".xxx=" .. tostring(stv.GetVar("xxx")), 1) end |
-- Файл test-2.lua require("StaticVar") stv.UseNameSpace("testNS") function main() sleep(10000) message("(test-2) " .. tostring(stv.GetCurrentNameSpace()) .. ".xxx=" .. tostring(stv.GetVar("xxx")), 1) end
Запускаем сначала test-1.lua, затем test-2.lua. Чрез 10 сек. Будет выведено 2 сообщения:
(test-1) testNS.xxx=xxx-test-value — первый скрипт сохранил значение и отобразил его
(test-2) testNS.xxx=xxx-test-value — второй скрипт отобразил значение, сохраненное первым скриптом
Скачайте архив SharedMemory.zip, распакуйте его. Создайте в корне терминала Quik папку «SharedMemory», поместите в нее файл SharedMemoryManager.lua и запустите его в терминале. Второй файл SharedMemoryClient.lua из архива подключайте к скриптам, которым нужен данный функционал.
Пример использования (в примере файл SharedMemoryClient.lua находится в одной папке со скриптом):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | require('SharedMemoryClient') Sharm = nil RUN = true main = function() -- Добавление клиента, функция new_SharM принимает один параметр - номер клиента, должен быть уникальным от 1 до 100 Sharm = new_SharM(1) -- Решение имеет всего 3 метода: -- SetVar - устанавливает значение переменной, в примере значение 1 переменной 'Var1' пространства имен 'NS' -- устанавливаемое значение может иметь тип boolean, number, string, либо table Sharm:SetVar('NS', 'Var1', 1) -- GetVar - получает значение переменной, в примере значение переменной 'Var1' из пространства имен 'NS' local value = Sharm:GetVar('NS', 'Var1') while RUN do -- Значения могут быть изменены в любом из подключенных клиентов message('Var1: '..tostring(Sharm:GetVar('NS', 'Var1'))) sleep(1000) end end OnStop = function() -- Delete - удаляет клиента (необязательно) Sharm:Delete() RUN = false end |
require('SharedMemoryClient') Sharm = nil RUN = true main = function() -- Добавление клиента, функция new_SharM принимает один параметр - номер клиента, должен быть уникальным от 1 до 100 Sharm = new_SharM(1) -- Решение имеет всего 3 метода: -- SetVar - устанавливает значение переменной, в примере значение 1 переменной 'Var1' пространства имен 'NS' -- устанавливаемое значение может иметь тип boolean, number, string, либо table Sharm:SetVar('NS', 'Var1', 1) -- GetVar - получает значение переменной, в примере значение переменной 'Var1' из пространства имен 'NS' local value = Sharm:GetVar('NS', 'Var1') while RUN do -- Значения могут быть изменены в любом из подключенных клиентов message('Var1: '..tostring(Sharm:GetVar('NS', 'Var1'))) sleep(1000) end end OnStop = function() -- Delete - удаляет клиента (необязательно) Sharm:Delete() RUN = false end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | main = function() local FPath = getScriptPath()..'//.params' -- Создание таблицы для примера local Params = {} Params.a = 10 Params.b = 'qwerty' Params.c = true Params.d = {} Params.d[1] = 100 Params.d[2] = 'asdfg' Params.d[3] = false Params.d[4] = { ['a'] = 10, ['b'] = 'qwerty', ['c'] = true } -- Сохраняет таблицу в файл SaveTable(Params, FPath) -- Загружает таблицу из файла local NewParams = LoadTable(FPath) if NewParams ~= nil then message(NewParams.d[4].b) end -- выведет "qwerty" end -- Сохраняет таблицу в файл SaveTable = function(Table, FilePath) local Lines = {} local level = 0 function Rec(a) local first = true level = level + 1 local s = '' for i=1,level do s = ' '..s end for key, val in pairs(a) do if not first then Lines[#Lines] = Lines[#Lines]..',' end local k = '[\''..key..'\']' if type(key) == 'number' then k = '['..key..']' end if type(val) ~= 'table' then if type(val) == 'string' then val = '\''..val..'\'' else val = tostring(val) end table.insert(Lines, s..k..'='..val) first = false else table.insert(Lines, s..k..'={') first = false Rec(val) table.insert(Lines, s..'}') level = level - 1 end end end table.insert(Lines, 'local a = {') Rec(Table) table.insert(Lines, '}') table.insert(Lines, 'return a') local f = io.open(FilePath, 'w') for i=1,#Lines do f:write(Lines[i]..'\n') f:flush() end f:close() end -- Загружает таблицу из файла LoadTable = function(FilePath) local func, err = loadfile(FilePath) if not func then message('Ошибка загрузки таблицы из файла: '..err) return nil else return func() end end |
main = function() local FPath = getScriptPath()..'//.params' -- Создание таблицы для примера local Params = {} Params.a = 10 Params.b = 'qwerty' Params.c = true Params.d = {} Params.d[1] = 100 Params.d[2] = 'asdfg' Params.d[3] = false Params.d[4] = { ['a'] = 10, ['b'] = 'qwerty', ['c'] = true } -- Сохраняет таблицу в файл SaveTable(Params, FPath) -- Загружает таблицу из файла local NewParams = LoadTable(FPath) if NewParams ~= nil then message(NewParams.d[4].b) end -- выведет "qwerty" end -- Сохраняет таблицу в файл SaveTable = function(Table, FilePath) local Lines = {} local level = 0 function Rec(a) local first = true level = level + 1 local s = '' for i=1,level do s = ' '..s end for key, val in pairs(a) do if not first then Lines[#Lines] = Lines[#Lines]..',' end local k = '[\''..key..'\']' if type(key) == 'number' then k = '['..key..']' end if type(val) ~= 'table' then if type(val) == 'string' then val = '\''..val..'\'' else val = tostring(val) end table.insert(Lines, s..k..'='..val) first = false else table.insert(Lines, s..k..'={') first = false Rec(val) table.insert(Lines, s..'}') level = level - 1 end end end table.insert(Lines, 'local a = {') Rec(Table) table.insert(Lines, '}') table.insert(Lines, 'return a') local f = io.open(FilePath, 'w') for i=1,#Lines do f:write(Lines[i]..'\n') f:flush() end f:close() end -- Загружает таблицу из файла LoadTable = function(FilePath) local func, err = loadfile(FilePath) if not func then message('Ошибка загрузки таблицы из файла: '..err) return nil else return func() end end
Данный пример создаст файл «.params» (можно открыть Блокнотом, это обычный текстовый файл, можете назвать его как угодно) со следующим содержимым:
local a = { ['a']=10, ['d']={ [1]=100, [2]='asdfg', [3]=false, [4]={ ['a']=10, ['c']=true, ['b']='qwerty' } }, ['c']=true, ['b']='qwerty' } return a