Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
21.02.2024 12:40:52
Попытка быстро собрать нечеткий апgроксиматор на основе двух готовых lua библиотек (luafuzzy, luann) - застряла? Виновник тому - библиотекa, luann, не проходит обучение если порог err < 0.42. Вот уже который день не могу разобраться почему? Если кто то в теме посмотрите, вот сам модуль
Скрытый текст
Код
local write, writeIndent, writers, refCount;
persistence =
{
store = function (path, ...)
local file, e = io.open(path, "w")
if not file then return error(e) end
local n = sel ect("#", ...)
local objRefCount = {} -- Stores reference that will be exported
for i = 1, n do refCount(objRefCount, (sel ect(i,...))) end
local objRefNames = {}
local objRefIdx = 0;
file:write("-- Persistent Data\n");
file:write("local multiRefObjects = {\n");
for obj, count in pairs(objRefCount) do
if count > 1 then
objRefIdx = objRefIdx + 1;
objRefNames[obj] = objRefIdx;
file:write("{};"); -- table objRefIdx
end;
end;
file:write("\n} -- multiRefObjects\n");
for obj, idx in pairs(objRefNames) do
for k, v in pairs(obj) do
file:write("multiRefObjects["..idx.."][");
write(file, k, 0, objRefNames);
file:write("] = ");
write(file, v, 0, objRefNames);
file:write(";\n");
end;
end;
for i = 1, n do
file:write("local ".."obj"..i.." = ");
write(file, (select(i,...)), 0, objRefNames);
file:write("\n");
end
if n > 0 then
file:write("return obj1");
for i = 2, n do
file:write(" ,obj"..i);
end;
file:write("\n");
else
file:write("return\n");
end;
file:close();
end;
load = function (path)
local f, e = loadfile(path);
if f then
return f();
else
return nil, e;
end;
end;
}
write = function (file, item, level, objRefNames)
writers[type(item)](file, item, level, objRefNames);
end;
writeIndent = function (file, level)
for i = 1, level do
file:write("\t");
end;
end;
refCount = function (objRefCount, item)
if type(item) == "table" then
if objRefCount[item] then
objRefCount[item] = objRefCount[item] + 1;
else
objRefCount[item] = 1;
for k, v in pairs(item) do
refCount(objRefCount, k);
refCount(objRefCount, v);
end;
end;
end;
end;
writers = {
["nil"] = function (file, item) file:write("nil") end;
["number"] = function (file, item)
file:write(tostring(item));
end;
["string"] = function (file, item)
file:write(string.format("%q", item));
end;
["boolean"] = function (file, item)
if item then
file:write("true");
else
file:write("false");
end
end;
["table"] = function (file, item, level, objRefNames)
local refIdx = objRefNames[item];
if refIdx then
file:write("multiRefObjects["..refIdx.."]");
else
file:write("{\n");
for k, v in pairs(item) do
writeIndent(file, level+1);
file:write("[");
write(file, k, level+1, objRefNames);
file:write("] = ");
write(file, v, level+1, objRefNames);
file:write(";\n");
end
writeIndent(file, level);
file:write("}");
end;
end;
["function"] = function (file, item)
local dInfo = debug.getinfo(item, "uS");
if dInfo.nups > 0 then
file:write("nil --[[functions with upvalue not supported]]");
elseif dInfo.what ~= "Lua" then
file:write("nil --[[non-lua function not supported]]");
else
local r, s = pcall(string.dump,item);
if r then
file:write(string.format("loadstring(%q)", s));
else
file:write("nil --[[function could not be dumped]]");
end
end
end;
["thread"] = function (file, item)
file:write("nil --[[thread]]\n");
end;
["userdata"] = function (file, item)
file:write("nil --[[userdata]]\n");
end;
}
local luann = {}
local Layer = {}
local Cell = {}
---local exp = math.exp
local Activation = {}
--Define the activation functions
Activation["sigmoid"] = function(signalSum)
return 1 / (1 + math.exp(-1*signalSum))
end
Activation["relu"] = function(signalSum)
return math.max(0, signalSum)
end
Activation["leakyrelu"] = function(signalSum)
return math.max(0.01*signalSum, signalSum)
end
--// Cell:new(numInputs)
-- numInputs -> The number of inputs to the new cell
-- Note: The cell has a structure containing weights that modify the input fr om the previous layer.
-- Each cell also has a signal, or output.
function Cell:new(numInputs)
local cell = {delta = 0, weights = {}, signal = 0}
for i = 1, numInputs do
cell.weights[i] = math.random() * 0.1
end
setmetatable(cell, self)
self.__index = self
return cell
end
--// Cell:activate(inputs, bias, actFuncName)
-- inputs -> The collection of inputs to the cell
-- bias -> The bias input to the cell
-- actFuncName -> The name of the activation function (see luann:new)
function Cell:activate(inputs, bias, actFuncName)
local signalSum = bias
local weights = self.weights
for i = 1, #weights do
signalSum = signalSum + (weights[i] * inputs[i])
end
---self.signal = 1 / (1 + exp((signalSum * -1) / threshold))
res = Activation[actFuncName](signalSum)
self.signal = res
end
--// Layer:new([numCells [, numInputs]])
-- numCells -> Optional (default: 1). Number of cells in this layer
-- numInputs -> Optional (default: 1). Number of inputs to this layer
-- Note: The layer is a table of cells.
function Layer:new(numCells, numInputs)
numCells = numCells or 1
numInputs = numInputs or 1
local cells = {}
---for i = 1, numCells do cells[i] = Cell:new(numInputs) end
---local layer = {cells = cells, bias = math.random()}
---setmetatable(layer, self)
---self.__index = self
for i = 1, numCells do
cells[i] = Cell:new(numInputs)
end
local layer = {cells = cells, bias = math.random()}
setmetatable(layer, self)
self.__index = self
return layer
end
--// luann:new(layers, learningRate [, actiFuncName])
-- layers -> Table of layer sizes fr om input to output
-- actiFuncName -> Optional (default: 'sigmoid'). Defines the NAME of the function (in the Activation table) to use in for activation.
-- Note: For actiFuncName, the function itself cannot be passed due to issues with table persistence.
-- This is currently considered a workaround..
function luann:new(layers, learningRate, actiFuncName)
local network = {learningRate = learningRate, actiFuncName = actiFuncName or 'sigmoid'}
--initialize the input layer
network[1] = Layer:new(layers[1], layers[1])
---initialize the hidden layers and output layer
for i = 2, #layers do
--initialize the hidden layers and output layer
network[i] = Layer:new(layers[i], layers[i-1])
end
setmetatable(network, self)
self.__index = self
return network
end
--// luann:train(inputs, expectedOutput, rmseThreshold)
-- inputs = collection of a collection of inputs to train on
-- expectedOutput = collection of a collection of expected outputs for the given inputs
-- rmseThreshold = train until RMSE falls below this value
function luann:train(inputs, expectedOutput, rmseThreshold)
local out = {}
local count = 0
repeat
for i=1, #inputs do
-- for each set of inputs
self:bp(inputs[i], expectedOutput[i])
out[i] = self:getOutputs()
end
local rmse = self:getRMSE(out, expectedOutput)
if count>50000 then
print("Current RMSE: " .. rmse)
count = 0
end
count = count + 1
until(rmse < rmseThreshold)
end
---function luann:decode(hiddenSignal)
--// luann:forwardPropagate(inputs)
-- propagates the inputs and returns the outputs, a convience function
function luann:forwardPropagate(inputs)
self:activate(inputs)
return self:getOutputs()
end
--// luann:getOutputs()
-- gets the set of previous outputs
function luann:getOutputs()
local out = {}
for o=1, #self[#self].cells do
out[o] = self[#self].cells[o].signal
end
return out
end
--// luann:getRMSE(predictions, expected)
-- predictions = a collection of a collection of predictions
-- expected = a collection of a collection of expected outputs
function luann:getRMSE(predictions, expected)
assert(#predictions == #expected, "ERR: #predictions ~= #expected")
local numElements = 0
local sum = 0
for i=1, #predictions do
-- for each set of predictions
for j=1, #predictions[i] do
-- for each output node
numElements = numElements+1
sum = sum + math.pow(expected[i][j]-predictions[i][j],2)
end
end
local mse = sum/numElements
return math.sqrt(mse)
end
--// luann:activate(inputs)
-- inputs -> The collection of inputs to be forward propagated through the network
function luann:activate(inputs)
for i = 1, #inputs do
self[1].cells[i].signal = inputs[i]
end
for i = 2, #self do
local passInputs = {}
local cells = self[i].cells
local prevCells = self[i-1].cells
for m = 1, #prevCells do
passInputs[m] = prevCells[m].signal
end
local passBias = self[i].bias
for j = 1, #cells do
--activate each cell
cells[j]:activate(passInputs, passBias, self.actiFuncName)
end
end
end
--// luann:bp(inputs, expectedOutputs)
-- inputs -> The collection of training inputs for backpropagation
-- expectedOutputs -> The collection of expected outputs for the given training inputs
-- Note: Contains some debug info for when cell weights become inf and cell deltas become NaN
function luann:bp(inputs, expectedOutputs)
self:activate(inputs) --update the internal inputs and outputs
local numLayers = #self
local learningRate = self.learningRate
for i = numLayers, 2, -1 do --iterate backwards (nothing to calculate for input layer)
local numCells = #self[i].cells
local cells = self[i].cells
for j = 1, numCells do
-- for each cell in the current layer
local cellOutput = cells[j].signal
if i ~= numLayers then
local weightDelta = 0
local nextLayerCells = self[i+1].cells
for k = 1, #nextLayerCells do
-- for each cell in the next layer
weightDelta = weightDelta + nextLayerCells[k].weights[j] * nextLayerCells[k].delta
-- ensure weightDelta does not become inf
assert(weightDelta ~= math.huge, "weightDelta: INF!\nnextLayerCells["..k.."].weights["..j.."]="..nextLayerCells[k].weights[j]..", \nnextLayerCells["..k.."].delta="..nextLayerCells[k].delta)
end
cells[j].delta = cellOutput * (1 - cellOutput) * weightDelta
-- ensure cell delta does not become NaN
assert(cells[j].delta == cells[j].delta, "cells["..j.."].delta: NaN!\n" .. "cellOutput="..cellOutput..",\nweightDelta="..weightDelta)
else --special calculations for output layer
cells[j].delta = (expectedOutputs[j] - cellOutput) * cellOutput * (1 - cellOutput)
-- ensure cell delta does not become NaN
assert(cells[j].delta == cells[j].delta, "cells["..j.."].delta: NaN! OUTPUT\nexpectedOutputs["..j.."]="..expectedOutputs[j]..",\ncellOutput="..cellOutput)
end
end
end
for i = 2, numLayers do
-- update the bias
self[i].bias = self[i].bias + learningRate * self[i].cells[#self[i].cells].delta
for j = 1, #self[i].cells do
for k = 1, #self[i].cells[j].weights do
-- update the weights
local weights = self[i].cells[j].weights
weights[k] = weights[k] + learningRate * self[i].cells[j].delta * self[i-1].cells[k].signal
end
end
end
end
--// luann:saveNetwork(network, savefile)
-- network -> The luann network to be saved
-- path -> The path of the output file
function luann:saveNetwork(network, path)
print("Saving network to: " .. path)
persistence.store(path, network)
end
--// luann:loadNetwork(path)
-- path -> The path of the file to load
function luann:loadNetwork(path)
local ann = persistence.load(path)
ann.bp = luann.bp
ann.activate = luann.activate
for i = 1, #ann do
for j = 1, #ann[i].cells do
ann[i].cells[j].activate = Cell.activate
end
end
return(ann)
end
--// luann:loadTrainingDataFromFile(path)
-- path -> The path of the file containing the training data
function luann:loadTrainingDataFromFile(path)
local trainingData = {}
local fileLines = {}
local f = io.open(path, "rb")
for line in f:lines() do
table.insert (fileLines, line);
end
f:close()
for i = 1, #fileLines do
if i%2 == 0 then
local tempInputs = {}
for input in fileLines[i]:gmatch("%S+") do
table.insert(tempInputs, tonumber(input))
end
local tempOutputs = {}
for output in fileLines[i+1]:gmatch("%S+") do
table.insert(tempOutputs, tonumber(input))
end
table.insert(trainingData, {tempInputs, tempOutputs})
end
end
return(trainingData)
end
return(luann)
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
19.02.2024 19:05:52
Цитата
VPM написал: Нечеткая логика - равно расширенная логика, полностью совместимая с классической логикой в предельных случаях, обладающая невероятной мощью и простотой.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
19.02.2024 18:56:25
Цитата
nikolz написал: , А чем отличается нечеткая логика от четкой логики? Можете показать пример на луа?
Ну так пример выложен выше, нажмите кнопку скрытый текст?
Вот, результат Бек - теста, период симуляции 1 торговый день, 4 инструмента, вставил нечеткое правило закрытие позиции, в простую торговую стратегию.
[Mon Feb 19 18:22:22 2024] Info: ETS: 337/-23; 32/1; MO=9.52; AveWin=10.53; AveLoss=-23; PF=14.65; %W=96.97; Fopt=0.97 где, 337/-23; -- пункты, выигрыш/проигрыш 32/1; -- количество сделок, выигрыш/проигрыш MO=9.52; -- мат ожидание системы AveWin=10.53; -- средний выигрыш AveLoss=-23; -- средний проигрыш PF=14.65; -- профит фактор системы %W=96.97; -- процент выигрышных сделок системы Fopt=0.97 -- оптимальная фракция
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
19.02.2024 18:20:53
nikolz, Ползает робот - пылесос и меня это совсем не смущает, стиральная машина стирает и меня это не смущает. В быту куда не ткнись наткнешься на Fuzzy Logic, и это ни кого не смущает. Срок говорит о проверке временем, и подтверждает тот факт, что решать задачи управления лучше простыми методами. Хотя при проектировании Fuzzy System легко наделать ошибок.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
19.02.2024 17:15:44
Kolossi, Прежде чем, что - то куда - то вставлять, неплохо бы вначале, разработать лингвистические переменные для входящих данных, для выхода, создать правила, разработать алгоритм использования ответов. И это задача далеко не простая. Ну прежде чем встраивать в реал, нужно от тестировать. (Алгоритм создания есть в примере).
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
15.02.2024 15:51:55
Владимир, Дифирамб мой в отношении луа, как раз и заключается в том что увидел, как эта задача реализуется на языке программирования mql. Относительно ADX, это просто упрощенный пример, хорошо известный широкой публике, для понимания вопроса как этим можно пользоваться а нашем контексте. Про нечеткую логику можно легко "погуглить" (на пример, мне нравится пример управление автомобилем). Обращу внимание лишь на главное. Пример, задали четкую пороговую границу TREND = ADX>30 or false, что получается 30.1 тренд а 29.9 нет. Что же предлагает нечеткая логика. Происходит размытие четко заданных границ, они становятся нечеткими. То есть в приграничных зонах жестко заданных категорий появляется двойственность — сила тренда относится сразу к двум понятиям, но с разной степенью принадлежности.
Относительно трендов согласен с Вами, скажу про свой подход гоняю 5 тайм фреймов это минимум (легко могу увеличить только пока не вижу задачи зачем это делать), 3 тайм фрейма это торговые, я про это писал на страницах "двойной очереди". Главный старший определяет тренд, Затем торговый для поиска сигналов на удержание длительной позиции, и младший на котором все уточняется. Два остальных технические(1 минута и 1 секунда). В своем подходе, выделяю не только тренд, но циклическую компоненту и флат, то есть строю гипотезы о состоянии рынка, от этого зависит, какая стратегия торгует в данный момент, и здесь тоже нечеткая логика.
Волатильность имеет важное значение у меня отвечает за торговые цели, установку параметров sl, tp, но это совершенно другие задачи, определяя направлен тренда - определяем куда наиболее вероятно двигается цена за определенный промежуток времени (если хотите это мера смещения центра, хорошо характеризует альфа в линейной регрессии).
Что касается портфеля, а что мешает Вам написать так: ADX={} ADX[i]=function ADX().
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
15.02.2024 13:22:31
Просматривая материалы по теме, мне захотелось пропеть дифирамб луа, судите сами, как относительно просто, элегантно, интуитивно понятно написана библиотека (Все познается в сравнении!) Все что на страницах данного сайта обсуждается, в конечном итоге с водится к одному - принятию торгового решения, в той или иной рыночной ситуации. И нечеткая логика нам в этом помогает. Для огромного количества технических задач создаются AI с использованием нечеткой логике, вот и я переделывая свою программу, подошел на конец к этапу - "бэктестинга". При котором нужно создовать правила решения управенческих задач, всповнил про нечеткую логику, решил поделиться свими соображениями. Пользоваться этим или не пользоваться решать Вам. Могу сказать одно, я у себя собираю комбинированный подход эксперт + нечеткая логика.
Выкладываю совсем простой пример (собрал "на коленке"), но от этого не менее мощный. Определяем силу тренда при помощи алгоритма ADX (J. Welles Wilder) устанавливая четкие правила, ответ индикатора являются входным сигналом для нечеткого индикатора. Выходной сигнал нечеткого индикатора, будет корректировать нашу позицию на рынке с учетом нечеткой переменной силы тренда, в стратегии это ТП и СЛ; можно задать размер лота; значение процента риска депозита относительно нечеткой переменной или еще чего то там ... Делитесь идеями, выкладывайте примеры! Хорошей алго торговли!
Скрытый текст
-- Выходной сигнал, который будет корректировать нашу позицию на рынке с учетом нечеткой переменной силы тренда, function mamdani_adx( v ) ---- Mamdani Fuzzy System require 'luafuzzy' local fuzzy = luafuzzy() ----- 1). Задаем 4 категории силы тренда: слабый (low), умеренный (moderate),средний (medium) и сильный (high). ----- создать все нечеткие входные переменные, задав имя переменной, её значения:
---- 2) четыре категории для значений целей прибыли: -- первая и четвертая категории(10-20 и 40-50 пунктов) — трапециевидными функциями, а две оставшиеся (20-30 и 30-40 пунктов) — треугольными. -- Так будет выглядеть описание нашего выходного сигнала.
----- 3) составляем базу правил Mamdani (fuzzy rules)
-- Правило R1 если , то local r1 = fuzzy:addrule( 1, 'andmethod' ) r1:addpremise( false, 'trend', 'low' ) r1:addimplic ( false, 'target', 'low' )
-- Правило R2 если , то local r2 = fuzzy:addrule( 1, 'andmethod' ) r2:addpremise( false, 'trend', 'moderate' ) r2:addimplic ( false, 'target', 'moderate' )
-- Правило R3 если , то local r3 = fuzzy:addrule( 1, 'andmethod' ) r3:addpremise( false, 'trend', 'medium' ) r3:addimplic ( false, 'target', 'medium' )
-- Правило R3 если , то local r4 = fuzzy:addrule( 1, 'andmethod' ) r4:addpremise( false, 'trend', 'high' ) r4:addimplic ( false, 'target', 'high' )
-----4) Set input value local res = fuzzy:solve( v ) or 0 --print('res = '..res ,1) return res; end
Имитация: print('системa рекомендаций;') for adx = 30,60, 5 do print('cилы тренда: ADX = ', adx, 'выходной сигнал, с учетом силы тренда корректировать позицию на ',math.floor(mamdani_adx( adx ) ), 'пунктов') end Ответы: системa рекомендаций; cилы тренда: ADX = 30 выходной сигнал, с учетом силы тренда корректировать позицию на 14 пунктов cилы тренда: ADX = 35 выходной сигнал, с учетом силы тренда корректировать позицию на 14 пунктов cилы тренда: ADX = 40 выходной сигнал, с учетом силы тренда корректировать позицию на 14 пунктов cилы тренда: ADX = 45 выходной сигнал, с учетом силы тренда корректировать позицию на 25 пунктов cилы тренда: ADX = 50 выходной сигнал, с учетом силы тренда корректировать позицию на 25 пунктов cилы тренда: ADX = 55 выходной сигнал, с учетом силы тренда корректировать позицию на 30 пунктов cилы тренда: ADX = 60 выходной сигнал, с учетом силы тренда корректировать позицию на 35 пунктов
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Хочу заметить про один недостаток данной библиотеки нет в ней Сигмовидной функции принадлежности, если кто допишет библиотеку выложите. Так как nikolz, дал ссылку на автора, то тем кому тема незнакома, может перейти по ссылке и там лежит пример показывающий как этим пользоваться. Это классический пример из букваря, суть рассчитать комиссионные официанту в зависимости от двух параметров.
Прежде чем говорить о базах знаний, я хочу предложить Вашему вниманию другую ссылку по нашей теме.
Цитата
В современном трейдинге все чаще используются системы автоматической торговли, чаще именуемые торговыми экспертами или роботами. Суть их работы в том, что они имеют четкую, жестко заданную систему, а именно торговую стратегию и систему управления финансами (мани-менеджмент).Преимущества таких систем в том, что они исключают человеческий фактор, строго действуют по определенному алгоритму. Недостатки автоматической торговли заключаются в отсутствии гибкости применяемой торговой стратегии, она всегда будет работать в одних и тех же рамках, с одними и теми же жестко разбитыми на категории параметрами. Проще говоря, система будет груба: средний тренд — входит одним лотом, сильный тренд — двойным и точка!
Как бы торговал человек, которому как раз присуща нечеткость категорий, различное мнение при схожих сигналах на вход? Он бы пытался оценить тренд, задаваться вопросом: а насколько он средний, или, может быть, он ближе к сильному, или сильный, но не настолько, чтобы входить двойным лотом по стратегии?
Все это может описать нечеткая логика. Она не ставит жестких границ между категориями, она их как бы размывает и тем самым делает торговую систему более гибкой, сочетая в себе дисциплину робота и гибкость человеческого мышления.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
13.02.2024 16:52:45
Подскажите пожалуйста, как можно сворачивать окно а при необходимости развернуть, получилось слишком большое окно не очень удобно.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
13.02.2024 16:41:00
Есть небольшая библиотека написана на луа 5.1.
"LuaFuzzy простая библиотека, полностью написана на Lua, для решения проблем с применением нечеткой логики. Она была разработана на основе нечеткой логики арсенале Matlab, поэтому она очень похожа легко понять и использовать его. Она реализует систему логического вывода Mamdani".
Предлагаю Вашему вниманию luafuzzy.lua (библиотека не большая для удобства выкладываю сюда)
Код
---------------------------------
-- Fuzzy Operations
---------------------------------
-------------------------------------------------------------------------------
-- Tmin
-------------------------------------------------------------------------------
function tmin(a1,a2)
if a2 < a1 then
return a2
else
return a1
end
end
-------------------------------------------------------------------------------
-- Tmax
-------------------------------------------------------------------------------
function tmax(a1,a2)
if a2 < a1 then
return a1
else
return a2
end
end
-------------------------------------------------------------------------------
-- Tsum
-------------------------------------------------------------------------------
function tsum(a1,a2)
--local y = a1 + a2
return a1 + a2--y -- stop in one(limit)?
end
-------------------------------------------------------------------------------
-- Tprod
-------------------------------------------------------------------------------
function prod(a1,a2)
return a1*a2
end
---------------------------------
-- Membership Functions (членство)
---------------------------------
-------------------------------------------------------------------------------
--[[-- Gaussian membership function
-- @param x Input value
-- @param params Table of parameters:
-- - params[1] = standard deviation
-- - params[2] = mean
-- @return The value of the pertinence
Гауссова функция принадлежности
- @ Параметров х Входное значение
- @ Параметров ПАРАМЕТРЫ Таблица параметров:
--- ПАРАМЕТРЫ [1] = стандартное отклонение
--- ПАРАМЕТРЫ [2] = средняя
- @ Возвращать значение уместности]]
-------------------------------------------------------------------------------
function gaussmf( x, params )
return math.exp( -((x - params[2])^2)/(2*params[1]^2))
end
-------------------------------------------------------------------------------
--[[-- Trapezoidal membership function
-- @param x Input value
-- @param params Table of parameters(see chart below)
-- @return The value of the pertinence
--
-- pertinency
- Функция принадлежности трапецеидальной
- @ Параметров х Входное значение
- @ Параметров ПАРАМЕТРЫ Таблица параметров (см. таблицу ниже)
- @ Возвращать значение уместности
- уместность]]
-- ^
-- |
-- | /2+++3\
-- | / \
-- -|1---------4-->x
-------------------------------------------------------------------------------
function trapmf( x, params)
if x > params[1] and x < params[2] then
return (x-params[1])/(params[2]-params[1])
elseif x >= params[2] and x < params[3] then
return 1
elseif x >= params[3] and x < params[4] then
return (params[4]-x)/(params[4]-params[3])
else
return 0
end
end
-------------------------------------------------------------------------------
--[[-- Triangular membership function
-- @param x Input value
-- @param params Table of parameters(see chart below)
-- @return The value of the pertinence
--
-- pertinency
- Треугольные функции принадлежности
- @ Параметров х Входное значение
- @ Параметров ПАРАМЕТРЫ Таблица параметров (см. таблицу ниже)
- @ Возвращать значение уместности
- уместность]]
-- ^
-- |
-- | /2\
-- | / \
-- -|1-----3-->x
-------------------------------------------------------------------------------
function trimf( x, params )
if x > params[1] and x < params[2] then
return (x-params[1])/(params[2]-params[1])
elseif x >= params[2] and x < params[3] then
return (params[3]-x)/(params[3]-params[2])
else
return 0
end
end
---------------------------------
-- Deffuzification Functions
---------------------------------
-------------------------------------------------------------------------------
-- Centroid deffuzyfication method
-- @param fs A fuzzyset with pairs of x and y like: fs[1].x, fs[1].y
-- @returm Return the geometric center value
-------------------------------------------------------------------------------
function centroid( fs )
if #fs <= 1 then
error('invalid number of fuzzyset entries')
end
local accxy = 0
local accy = 0
for i,v in ipairs(fs) do
if v.y > 0 then
accxy = accxy + v.x*v.y
accy = accy + v.y
end
end
if accy > 0 then
return accxy/accy
else
return (fs[1].y-fs[#fs].y)/2
end
end
---------------------------------
-- Fuzzy Inference System
---------------------------------
-------------------------------------------------------------------------------
--[[-- Method to solve a fuzzy system
-- @param self The fuzzy system
-- @param ... A vararg list of input values
-- @return A vararg list of output values
Метод решить нечеткой системы
- @ Параметр self нечеткая система
- @ Параметр ... Список переменных аргументов входных значений
- @ Возвращать список VARARG выходных значений]]
-------------------------------------------------------------------------------
local function solvefuzzy( self, ... )
local fuzzy = self
local inpvals = {...}
-- error check
if #fuzzy.inps <= 0 then error('invalid number of inputs') end
if #fuzzy.outs <= 0 then error('invalid number of outputs') end
if #fuzzy.rules <= 0 then error('invalid number of rules') end
-- solve each input
for i,inp in ipairs(fuzzy.inps) do
-- current input value
local x = inpvals[i]
-- error check
if x > inp.mx or x < inp.mn then
error('value ' .. x .. ' out of range for input \'' .. inp.name .. '\'')
end
-- save the current value of the function for each lingvar
for _,lg in pairs(inp.lingvars) do
lg.value = lg.mf( x, lg.params )
end
end
-- for each rule...
for ri,r in ipairs(fuzzy.rules) do
--
-- Errors Check
--
-- range errors check
if #r.pres <= 0 then error('invalid number of premises') end
if #r.imps <= 0 then error('invalid number of implications') end
-- premises errors check
for pi=1,#r.pres do
if not fuzzy.inps[r.pres[pi].ifpart] then
error('invalid \'if part = '..r.pres[pi].ifpart..'\' for premise '..pi..' of rule ' .. ri)
end
if not fuzzy.inps[r.pres[pi].ifpart].lingvars[r.pres[pi].ispart] then
error('invalid \'is part = '..r.pres[pi].ispart..'\' for premise '..pi..' of rule ' .. ri)
end
end
-- implications errors check
for ii,imp in ipairs(r.imps) do
if not fuzzy.outs[imp.thenpart] then
error('invalid \'then part = '..imp.thenpart..'\' for implication '..ii..' of rule ' .. ri)
end
if not fuzzy.outs[imp.thenpart].lingvars[imp.ispart] then
error('invalid \'is part = '..imp.ispart..'\' for implication '..ii..' of rule ' .. ri)
end
end
-- connection function error check
if not fuzzy[r.connmethod] then
error('invalid \'connection method = '..r.connmethod..'\' for rule '..ri..'. (must be \'andmethod\' or \'ormethod\')')
end
--
-- Calculate the result value for a rule...
--
-- retrive the connection function
local conn = fuzzy[r.connmethod]
-- result value of premises
r.value = fuzzy.inps[r.pres[1].ifpart].lingvars[r.pres[1].ispart].value
-- for each premise...
for pi=2,#r.pres do
local v = fuzzy.inps[r.pres[pi].ifpart].lingvars[r.pres[pi].ispart].value
r.value = conn(v, r.value)
end
--
-- Calculate the resulting fuzzyset for each implication...
--
for _,imp in ipairs(r.imps) do
-- retrive the out's table
local out = fuzzy.outs[imp.thenpart]
-- retrive the lingvar fr om the out table
local lg = out.lingvars[imp.ispart]
-- save the fuzzyset for each implication
imp.fuzzyset = {}
-- compute the step
local step = (out.mx - out.mn)*fuzzy.step
-- calculate the resulting fuzzyset
for i=out.mn,out.mx,step do
-- computes the mf value for i
local lgval = lg.mf( i, lg.params )
-- compute the implication result
local v = fuzzy.implicmethod( lgval , r.value )
-- add the result to the fuzzy set
table.insert( imp.fuzzyset, { x=i, y=v } )
end
end -- end implications
end -- end rules
--
-- Computes output...
--
-- result table
local outvals = {}
-- solve each output
for i,out in ipairs(fuzzy.outs) do
-- clear previews fuzzyset
out.fuzzyset = nil
-- for each rule...
for _,r in ipairs(fuzzy.rules) do
--
-- Aggregation
--
-- for each implication
for _,imp in ipairs(r.imps) do
if out.name == imp.thenpart then
if not out.fuzzyset then
out.fuzzyset = {}
-- copy the first implication fuzzyset
for k,v in ipairs(imp.fuzzyset) do
out.fuzzyset[k] = { x=v.x, y=v.y }
end
else
-- calculate the resulting fuzzyset with aggregation method
for i,v in ipairs(out.fuzzyset) do
-- computes the new value
out.fuzzyset[i] = { x=v.x, y = fuzzy.aggregmethod( v.y, imp.fuzzyset[i].y ) }
end
end
end
end
end
--
-- Defuzzification...
--
-- call deffuzyfication method
out.value = fuzzy.defuzzmethod( out.fuzzyset )
-- add output value to result table
table.insert( outvals, out.value )
end
return unpack( outvals )
end
---------------------------------
-- Fuzzy System
---------------------------------
--
-------------------------------------------------------------------------------
--[[-- Method to add a new linguistic variable to a fuzzy input or output
-- @param self The variable's table
-- @param name Name of the variable
-- @param mf The membership function
-- @param params Table of parameters of the membership function
-- @return The lingvar's table
Метод для добавления нового языкового переменной нечеткой входа или выхода
- @ Параметров самостоятельно таблице переменной
- @ Параметров имя Имя переменной
- @ Параметров MF функция принадлежности
- @ Параметров ПАРАМЕТРЫ Таблица параметров функции принадлежности
- @ Вернуться таблицу в lingvar в]]
-------------------------------------------------------------------------------
local function addlingvar( self, name, mf, params )
local var = self
local lg = {}
lg.name = name
lg.mf = mf
lg.params = params
var.lingvars[lg.name] = lg
return lg
end
-------------------------------------------------------------------------------
--[[-- Method to add a new input variable to a fuzzy system
-- @param self The fuzzy system table
-- @param name Name of the variable
-- @param mn Lower lim it of values
-- @param mx Upper limit of values
-- @return The variable's table
- Метод, чтобы добавить новую переменную ввода на нечеткой системы
- @ Параметров самостоятельно нечеткой системной таблицы
- @ Параметров имя Имя переменной
- @ Параметров млн. Нижний предел значений
- @ Параметров м Верхний предел значений
- @ Вернуться таблицу переменной]]
-------------------------------------------------------------------------------
local function addinp( self, name, mn, mx )
local fis = self
local inp = {}
inp.name = name
inp.mn = mn
inp.mx = mx
inp.lingvars = {}
inp.addlingvar = addlingvar
table.insert( fis.inps, inp )
fis.inps[inp.name] = inp
return inp
end
-------------------------------------------------------------------------------
--[[-- Method to add a new output variable to a fuzzy system
-- @param self The fuzzy system table
-- @param name Name of the variable
-- @param mn Lower limit of values
-- @param mx Upper limit of values
-- @return The variable's table
Метод для добавления нового выходной переменной к нечеткой системы
- @ Параметров самостоятельно нечеткой системной таблицы
- @ Параметров имя Имя переменной
- @ Параметров млн. Нижний предел значений
- @ Параметров м Верхний предел значений
- @ Вернуться таблицу переменной]]
-------------------------------------------------------------------------------
local function addout( self, name, mn, mx )
local fis = self
local out = {}
out.name = name
out.mn = mn
out.mx = mx
out.lingvars = {}
out.addlingvar = addlingvar
table.insert( fis.outs, out )
fis.outs[out.name] = out
return out
end
-------------------------------------------------------------------------------
--[[-- Method to add a new premise to a rule
-- @param self The rule's table
-- @param neg Flag to informe if the implication output should be negated
-- @param ifpart Name of the input variable
-- @param ispart Name of the linguistic variable of the input
-- @return The premises table
- Метод, чтобы добавить новое помещение, чтобы правило
- @ Параметров самостоятельно таблице в правиле
- @ Параметров нег Флаг, Informe если выход вывод следует быть сведены на нет
- @ Параметров ifpart Имя входной величины
- @ Параметров ispart Название лингвистической переменной входа
- @ Вернуть таблицу помещения]]
-------------------------------------------------------------------------------
local function addpremise( self, neg, ifpart, ispart )
local rule = self
local prem = {}
prem.neg = neg
prem.ifpart = ifpart
prem.ispart = ispart
table.insert( rule.pres, prem )
return prem
end
-------------------------------------------------------------------------------
--[[-- Method to add a new implication to a rule
-- @param self The rule's table
-- @param neg Flag to informe if the implication output should be negated
-- @param thenpart Name of the output variable
-- @param ispart Name of the linguistic variable of the ouput
-- @return The implication's table--]]
-------------------------------------------------------------------------------
local function addimplic( self, neg, thenpart, ispart )
local rule = self
local impl = {}
impl.neg = neg
impl.thenpart = thenpart
impl.ispart = ispart
table.insert( rule.imps, impl )
return impl
end
-------------------------------------------------------------------------------
--[[-- Method to add a new rule to a fuzzy sistem
-- @param self The fuzzy system
-- @param weight The weight of the rule
-- @param connmethod The connection method. (must be: 'andmethod' or 'ormethod')
-- @return The rule's table--]]
-------------------------------------------------------------------------------
local function addrule( self, weight, connmethod )
local fis = self
local rule = {}
rule.weight = weight
rule.connmethod = connmethod
rule.pres = {}
rule.imps = {}
rule.addpremise = addpremise
rule.addimplic = addimplic
table.insert( fis.rules, rule )
return rule
end
-------------------------------------------------------------------------------
-- Create a new fuzzy system
-- @return A new table with the fuzzy system
-------------------------------------------------------------------------------
function luafuzzy()
-- create new table(создать новую таблицу)
local fuzzy = {}
-- and method
fuzzy.andmethod = tmin
-- or method
fuzzy.ormethod = tmax
-- implication method(метод Смысл)
fuzzy.implicmethod = tmin
-- aggregation method()
fuzzy.aggregmethod = tmax
-- deffuzification method
fuzzy.defuzzmethod = centroid
-- step used to compute a discrete fuzzyset(Шаг используется для вычисления дискретного fuzzyset)
fuzzy.step = 0.01
-- table os rules
fuzzy.rules = {}
-- table of inputs
fuzzy.inps = {}
-- tabla of outputs
fuzzy.outs = {}
-- method to add a new input
fuzzy.addinp = addinp
-- method to add a new output
fuzzy.addout = addout
-- method to add a new rule
fuzzy.addrule = addrule
-- method to solve the fuzzy inferece system
fuzzy.solve = solvefuzzy
return fuzzy
end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
13.02.2024 16:35:44
Система принятия решений и/или Нечеткая логика(FuzzyLogic) ==================================================
"Системы поддержки принятия решения (СППР) (Decision Support System, DSS) - это интерактивные автоматизированные системы, помогающие лицу, принимающему решения, использовать данные и модели для решения слабо структурированных проблем".
В этой ветке предлагаю обсудить область применения Fuzzy Logic в задачах трейдинга. реализации систем правил в задачах принятии управленческих решений, управление риском (риск менеджмент), управление позицией (мани менеджмент), построение торговых стратегий.
В общем случае, область применения нечеткой логики не знает границ. В любом алгоритме, в любой системе правил, где используются четкие выводы (истина и ложь, 1 или 0), можно пробовать заменить их на степень истинности (степень принадлежности), для более точного отражения реальности. Нечеткая логика - равно расширенная логика, полностью совместимая с классической логикой в предельных случаях, обладающая невероятной мощью и простотой. Наш мир, фундаментально нечеток.
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
24.01.2024 10:47:29
nikolz, Не знаю кто что проходил, но мой вариант Вот ,
Код
function List.new()
--return {first = 0, last = -1}
return {first = 0, last = 0}
end
local list=List.new()
local length=10; local M=1000--00--00
print("объем начального массива", M, "Кол. элементов в созданном length=",length);
local count1 = collectgarbage("count") -- получаем текущий размер памяти
------------------------------ LIFO
for i=1, M do
print(i, ')','Начальные индексы', 'list.first =', list.first, '; list.last =', list.last )
List.pushlast(list,i)
print(i, ')','Вставил', 'index list.last =', list.last,'; присвоил значение элементa =',list[list.last], '(',collectgarbage("count"),')' )
if i>length then
List.popfirst(list)
print( i, 'Операция - Удаление первого:', ')', 'присвоил индекс первоve элементу =', list.first, 'вернул значение первого элементa =', list[list.first] ,'(',collectgarbage("count"),')' ) --, list.first
end
end
print("LIFO (вариант реализации стека с помощью двусторонней очереди.) ----------------------");
print("начальный объем занятой памяти",count1);
print("число элементов в LIFO list после "..(M).." циклов функции рор=" ..(list.last-list.first))
local countOUT = collectgarbage("count")
print("объем занятой памяти",countOUT);
--------------------------------
collectgarbage("collect")
print("объем занятой памяти после сборщика мусора",collectgarbage("count"));
это стек, который в трейдинге называют динамическим окном, у меня в этом примере все доделано, то что вы демонстрируете это просто вставка элементов в массив, как она вообще может уменьшаться?
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
24.01.2024 08:36:11
nikolz, программа и тест есть на 25 странице в моей теме Двойные очереди.
Сложно с Вами с программистами, каждый на своей волне, "забейте", проще самому провести.
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
23.01.2024 18:17:11
nikolz, Это я и хотел сравнить, сделать один размер массивов, один размер окна прогнать на скорость на память, на время исполнения?
Цитата
nikolz написал: и еще... ваша стек-очередь напоминает недоделанный циклический массив. Если его доделать, то он будет делать ровно тоже самое, что и мой вариант сдвига массива выше. -------------------- Циклический массив работает быстрее, чем сдвиг массива. Но в луа из него медленнее брать данные. Его интереснее делать на C и встраивать сразу в индикаторы и фильтры. Но это уже другая тема.
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
23.01.2024 17:57:42
Вот из букваря:
Стек — это коллекция, элементы которой получают по принципу «последний вошел, первый вышел» (Last-In-First-Out или LIFO). Это значит, что мы будем иметь доступ только к последнему добавленному элементу.
Очередиочень похожи на стеки. Они также не дают доступа к произвольному элементу, но, в отличие от стека, элементы кладутся (enqueue) и забираются (dequeue) с разных концов. Такой метод называется «первый вошел, первый вышел» (First-In-First-Out или FIFO). То есть забирать элементы из очереди мы будем в том же порядке, что и клали. Как реальная очередь или конвейер.
Двусторонняя очередь (Double-ended queue), или дек (Deque), расширяет поведение очереди. В дек можно добавлять или удалять элементы как с начала, так и с конца очереди. Такое поведение полезно во многих задачах, например, планирование выполнения потоков или реализация других структур данных.
Позже мы рассмотрим вариант реализации стека с помощью двусторонней очереди.
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
23.01.2024 17:50:31
nikolz, Вы попробуйте пример, никакие nil не вставляются, если Вы об этом if first > list.last then return nil end, то это только проверка на ошибку.
В моем примере этой ошибки быть не может, так как вставляется последний элемент, массив нарастает до значения length if i>length then, (то есть определен размер окна). После достижения идет присвоение последнего и переписывание первого значения окна. Все.
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
23.01.2024 14:55:51
Я Вам говорю про этот вариант, в Вашем первоначальном есть логическая ошибка, это тоже окно ну или стек:
Пример от , оказал не оценимую помощь, помог разобраться в чем была путаница и не до понимание, помог собрать вариант который я объяснял.
Ниже пример, то о чем пытался я сказать. И что мы видим, реализован принцип LIFO «последний вошел, первый вышел» (Last-In-First-Out или LIFO). Это вариант стека с помощью двусторонней очереди, не смотря на то что алгоритм называется двусторонняя очередь, собран СТЕК!
function List.new() --return {first = 0, last = -1} return {first = 0, last = 0} end
Код
local list=List.new() local length=10; local M=1000--00--00 print("объем начального массива", M, "Кол. элементов в созданном length=",length); local count1 = collectgarbage("count") -- получаем текущий размер памяти ------------------------------ LIFO for i=1, M do
if i>length then List.popfirst(list) print( i, 'Операция - Удаление первого:', ')', 'присвоил индекс первоve элементу =', list.first, 'вернул значение первого элементa =', list[list.first] ,'(',collectgarbage("count"),')' ) --, list.first end
end print("LIFO (вариант реализации стека с помощью двусторонней очереди.) ----------------------"); print("начальный объем занятой памяти",count1);
print("число элементов в LIFO list после "..(M).." циклов функции рор=" ..(list.last-list.first)) local countOUT = collectgarbage("count") print("объем занятой памяти",countOUT); -------------------------------- collectgarbage("collect") print("объем занятой памяти после сборщика мусора",collectgarbage("count"));
Сдвиговые регистры, циклические массивы. Экономим память
Пользователь
Сообщений: Регистрация: 15.06.2023
23.01.2024 13:41:10
nikolz, Вы можете сравнить это метод с local lifo=List.new() List.pushlast(lifo,i) List.popfirst(lifo), и где какой использовать лучше или предпочтительней?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
22.01.2024 11:30:25
Владимир, Я Вас поздравляю с отличным решением! Я ушел заниматься своим, а то действительно не соберу. НО ХОЧЕТСЯ ПОДНЯТЬ новую тему?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
22.01.2024 11:20:12
Цитата
Владимир написал: Всё, тема исчерпана, вопрос закрыт.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
22.01.2024 11:18:02
Владимир, Вы опять все с ног на голову, пример отличный от слова совсем! почему уже сказано на свои вопросы я ответ получил!
То что вы сейчас описали, свой пример это подход частное решение - личное, я показал обще доступное решение которое с экономит массу времени тем кто только начинает кодить, и мне помог разобраться! Есть такой подход я его опишу словами из широко известного фильма "ЗА ДЕРЖАВУ ОБИДНО". А пользоваться этим или писать свое они разберутся без нас с Вами.
Ну и последнее не нужно к молодому поклонению применять дипломатические термины, как воспитали , чему научили то и получили.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
22.01.2024 10:45:36
Цитата
Владимир написал: Много памяти сэкономили? Хотя бы на КИЛОбайт наберётся?
Ну зря Вы! 1) это модуль легко встроить в любую конструкцию, быстрая реализация основной идеи; 2) универсальность можно собрать и другие подходы кроме ФИФО и ЛИФО; 3) Эффективность за счет хранения массива индексов (Возможно есть и более эффективный варианты, кому нужно всегда можно заменить на свой) ; 4) размер новой таблицы легко устанавливается и меняется под задачу; ....... n) Расход Памяти стабилизируется. Так как новая созданная таблица не растет. Я этот пример доводил до 100 000 значений первоначального массива (~60-70 бар на М1 на фьючерсах). Все четко отработало. Ответ очевиден сэкономили и не один КИЛОбайт!
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
22.01.2024 10:13:18
Владимир, Чему Вы радуетесь, если уж категорично то и Вы в этом списке! Все что требовалось показать вот эти две записи:
---- по принципу «последний вошел, первый вышел» (Last-In-First-Out или LIFO)
Код
local lifo=List.new() List.pushlast(lifo,i) List.popfirst(lifo)
---- «первый вошел, первый вышел» (First-In-First-Out или FIFO)
Код
local fifo=List.new() List.pushfirst(fifo,i) List.popfirst(fifo)
Не знамя заберем
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
22.01.2024 09:03:52
Пример от nikolz, оказал не оценимую помощь, помог разобраться в чем была путаница и не до понимание, помог собрать вариант который я объяснял.
Но прежде чем продолжить , должен извиница перед Владимир, Не чего не забыли, полвека показатель, по прежнему в строю на боевом коне знамя в руках. А также поблагодарить всех кто принимал участие в обсуждении.
Ниже пример, то о чем пытался я сказать. И что мы видим, реализован принцип LIFO «последний вошел, первый вышел» (Last-In-First-Out или LIFO). Это вариант стека с помощью двусторонней очереди, не смотря на то что алгоритм называется двусторонняя очередь, собран СТЕК!
Другую путаницу вносит название функции popfirst удаление первого, несмотря на то что операция называется удаление первого элемента, индекс первого элемента растет, отсекая как бы все то что осталось слева. Подтверждается все то что описал автор, в массив сохраняются значения индексов, получаем заданное количество элементов в которых храним значения, память под контролем, увеличение незначительно. Эффективность высокая. Кто будет пробовать нужно поправить чтоб было как в моем примере. function List.new() --return {first = 0, last = -1} return {first = 0, last = 0} end
Код
local list=List.new()
local length=10; local M=1000--00--00
print("объем начального массива", M, "Кол. элементов в созданном length=",length);
local count1 = collectgarbage("count") -- получаем текущий размер памяти
------------------------------ LIFO
for i=1, M do
print(i, ')','Начальные индексы', 'list.first =', list.first, '; list.last =', list.last )
List.pushlast(list,i)
print(i, ')','Вставил', 'index list.last =', list.last,'; присвоил значение элементa =',list[list.last], '(',collectgarbage("count"),')' )
if i>length then
List.popfirst(list)
print( i, 'Операция - Удаление первого:', ')', 'присвоил индекс первоve элементу =', list.first, 'вернул значение первого элементa =', list[list.first] ,'(',collectgarbage("count"),')' ) --, list.first
end
end
print("LIFO (вариант реализации стека с помощью двусторонней очереди.) ----------------------");
print("начальный объем занятой памяти",count1);
print("число элементов в LIFO list после "..(M).." циклов функции рор=" ..(list.last-list.first))
local countOUT = collectgarbage("count")
print("объем занятой памяти",countOUT);
--------------------------------
collectgarbage("collect")
print("объем занятой памяти после сборщика мусора",collectgarbage("count"));
Вот ответ
Код
объем начального массива 1000 Кол. элементов в созданом length= 10
1 ) Начальные индексы list.first = 0 ; list.last = 0
1 ) Вставил index list.last = 1 ; присвоил значение элементa = 1 ( 27.3759765625 )
2 ) Начальные индексы list.first = 0 ; list.last = 1
2 ) Вставил index list.last = 2 ; присвоил значение элементa = 2 ( 28.4384765625 )
3 ) Начальные индексы list.first = 0 ; list.last = 2
3 ) Вставил index list.last = 3 ; присвоил значение элементa = 3 ( 28.5166015625 )
4 ) Начальные индексы list.first = 0 ; list.last = 3
4 ) Вставил index list.last = 4 ; присвоил значение элементa = 4 ( 28.5634765625 )
5 ) Начальные индексы list.first = 0 ; list.last = 4
5 ) Вставил index list.last = 5 ; присвоил значение элементa = 5 ( 28.6728515625 )
6 ) Начальные индексы list.first = 0 ; list.last = 5
6 ) Вставил index list.last = 6 ; присвоил значение элементa = 6 ( 28.7197265625 )
7 ) Начальные индексы list.first = 0 ; list.last = 6
7 ) Вставил index list.last = 7 ; присвоил значение элементa = 7 ( 28.7666015625 )
8 ) Начальные индексы list.first = 0 ; list.last = 7
8 ) Вставил index list.last = 8 ; присвоил значение элементa = 8 ( 28.8134765625 )
9 ) Начальные индексы list.first = 0 ; list.last = 8
9 ) Вставил index list.last = 9 ; присвоил значение элементa = 9 ( 28.9853515625 )
10 ) Начальные индексы list.first = 0 ; list.last = 9
10 ) Вставил index list.last = 10 ; присвоил значение элементa = 10 ( 29.0146484375 )
11 ) Начальные индексы list.first = 0 ; list.last = 10
11 ) Вставил index list.last = 11 ; присвоил значение элементa = 11 ( 29.0625 )
11 Операция - Удаление первого: ) присвоил индекс первоve элементу = 1 вернул значение первого элементa = 1 ( 29.1484375 )
.........
1000 ) Начальные индексы list.first = 989 ; list.last = 999
1000 ) Вставил index list.last = 1000 ; присвоил значение элементa = 1000 ( 51.08203125 )
1000 Операция - Удаление первого: ) присвоил индекс первоve элементу = 990 вернул значение первого элементa = 990 ( 51.109375 )
LIFO (вариант реализации стека с помощью двусторонней очереди.) ----------------------
начальный объем занятой памяти 26.5283203125
число элементов в LIFO list после 1000 циклов функции рор=10
объем занятой памяти 51.28125
объем занятой памяти после сборщика мусора 30.7470703125
Всем удачи еще раз спасибо за обсуждение!
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 18:37:53
Который раз слышу вот это
Цитата
nikolz написал: Так вот , то что хочет автор этой темы реализуется не очередями и не стеками, а циклическими массивами.
Уважаемые, не сочтите за труд, покажите на примере, как это делается в луа?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 18:31:52
Такая запись не корректна print("число элементов в очереди list после "..M.." циклов функции push="..#list) не работает #list.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 18:21:10
По моему Все четко работает!
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 18:20:26
nikolz, Вот я поправил как хотел сделать на вашем примере. И Вот что получилось.
Код
local M=1000--0000
local count1 = collectgarbage("count") -- получаем текущий размер памяти
print("начальный объем занятой памяти",count1);
--------------------------
local list=List.new()
for i=1, M do
List.pushlast(list,i)
print('Вставил', i, 'элемент ', collectgarbage("count") )
if i>10 then print( 'Удалил первого', List.popfirst(list) , type(list), #list, collectgarbage("count") )
--local countI = collectgarbage("count")
end
end
print("число элементов в очереди list после "..M.." циклов функции push="..#list)
local count1 = collectgarbage("count")
print("объем занятой памяти",count1);
--------------------------------
-- for i=1, M do List.popfirst(list) end
print("число элементов в очереди list после "..M.." циклов pop="..#list)
local count1 = collectgarbage("count")
print("объем занятой памяти после сборщика мусора",count1);
collectgarbage("collect")
local count1 = collectgarbage("count") -- получаем текущий размер памяти
print("объем занятой памяти после pop",count1);
------------------------------
collectgarbage("collect") -- выполняем сбор мусора
local count2 = collectgarbage("count") -- получаем размер памяти после сбора
print("объем занятой памяти после сборщика мусора",count1);
Вот ответ
Код
начальный объем занятой памяти 35.4248046875
List.pushlast: ; number; ; list.last=0; number; list[last]=1
Вставил 1 элемент 27.283203125
List.pushlast: ; number; ; list.last=1; number; list[last]=2
Вставил 2 элемент 27.404296875
List.pushlast: ; number; ; list.last=2; number; list[last]=3
Вставил 3 элемент 27.556640625
List.pushlast: ; number; ; list.last=3; number; list[last]=4
Вставил 4 элемент 28.677734375
List.pushlast: ; number; ; list.last=4; number; list[last]=5
Вставил 5 элемент 28.830078125
List.pushlast: ; number; ; list.last=5; number; list[last]=6
Вставил 6 элемент 28.951171875
List.pushlast: ; number; ; list.last=6; number; list[last]=7
Вставил 7 элемент 29.134765625
List.pushlast: ; number; ; list.last=7; number; list[last]=8
Вставил 8 элемент 29.255859375
List.pushlast: ; number; ; list.last=8; number; list[last]=9
Вставил 9 элемент 29.376953125
List.pushlast: ; number; ; list.last=9; number; list[last]=10
Вставил 10 элемент 29.5009765625
List.pushlast: ; number; ; list.last=10; number; list[last]=11
Вставил 11 элемент 29.751953125
Удалил первого 1 table 10 29.7802734375
List.pushlast: ; number; ; list.last=11; number; list[last]=12
Вставил 12 элемент 29.9052734375
Удалил первого 2 table 11 29.9345703125
List.pushlast: ; number; ; list.last=12; number; list[last]=13
Вставил 13 элемент 30.0595703125
Удалил первого 3 table 12 30.0888671875
......
Удалил первого 989 table 0 56.8974609375
List.pushlast: ; number; ; list.last=999; number; list[last]=1000
Вставил 1000 элемент 57.0283203125
Удалил первого 990 table 0 57.0576171875
число элементов в очереди list после 1000 циклов функции push=0
объем занятой памяти 57.1650390625
число элементов в очереди list после 1000 циклов pop=0
объем занятой памяти после сборщика мусора 57.263671875
объем занятой памяти после pop 28.4912109375
объем занятой памяти после сборщика мусора 28.4912109375
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 16:16:40
Хранил данные баров для надежности так ка делал проверки (p0 = (Value(I, v_t, ds) or 0). Но сейчас добавил Проверку по индексу, посчитал что сохранять значения свечей избыточно. Вы опять правы при этом подходе все можно решить через замыкание. Спасибо. "А ларчик просто открывался"
Очереди и двойные очереди в луа, Пример из книги Р.Е.
VPM написал: "НУЖЕН КОНКРЕТНО В ВАШЕЙ ЗАДАЧЕ".Я говорил что мне не нравится как моя программа обращается с памятью. Основная проблема это накопление массивов данных (в моем варианте таблиц).Ну к примеру с частотой в 1 минуту получаю данные по свечам и индикаторам, складываю их в таблицу, которая за время сессии просто растет. Для программы использующей портфель из тикеров, тайм фреймов, индикаторов(планирую переключаться между торговыми стратегиями внутри сессии) это расточительно! Не знаю как назвать данный способ хранения но точно не стек, хоть и тарелочки из Вашего примера. Так как вся длинна этого массива не нужна (достаточно скажем 5 последних значения)Нужен подход уменьшения количества элементов в таблицах Я Вижу два подхода как организовать такую структуру:1) После обработке 5 последних значений наставить nil; bar[j][index-5].dec=nil;2) Так как 1 вариант сильно похож на очередь то я вспомнил про двойную очередь из примера автора (которую не удалось обсудить и разобрать с первого поста)И так задача сводится к удобному универсальному методу уменьшения хранения данных в ОЗУ, по сути в моем представлении к организации ОЧЕРЕДИ!
Это массив уже собирается в main()? С индикаторами нашли решения, зачистка лишнего в массивах. Дальше передали в main() хотим выработать не которые правила. Мой массив выглядит так
Код
for i=1,#sec do ---- цикла по бумагам:
for j=1,#tf do ---- Получаю Тек.index Свечей на всех tf:
Index[i][j]=DS[i][j]:Size()
td[i][j] = DS[i][j]:T( Index[i][j] );
bar[i][j][index].d = td[i][j] and get_date(td[i][j]) or nil;---- день один для разных тайфремов
bar[i][j][index].t = td[i][j] and get_time(td[i][j]) or nil;
bar[i][j][index].o = DS[i][j]:O( Index[i][j] );
bar[i][j][index].h = DS[i][j]:H( Index[i][j] );
bar[i][j][index].l = DS[i][j]:L( Index[i][j] );
---- ответ от индикатора тоже добавляю
bar[i][j][index].dec=nil;
Но потом добавил Проверку по индексу посчитал что сохранять значения свечей избыточно
Но массив растет
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 14:50:03
Цитата
Nikolay написал: Пробежался и так не понял в чем проблема, и причем здесь очередь. Озвучена проблема роста памяти при расчете индикаторов. Ок. Но для расчета индикаторов нужен банальный массив. Тупо для каждого индекса бара от 1 храним какое-то значение. Пришел новый бар - записали данные по его индексу. Все. Но такой вариант - это постоянное увеличение хранимых данных. Что можно сделать? Банально очищать неиспользуемые данные, присваивая nil. Правда помня, что перестанет работать #. Но это решается очень просто. Сложнее - можно сделать массив фиксированного размера и записывать данные по кольцу. Так сделали разработчики терминала в последней версии примеров расчета индикаторов. Что это дает - объем занимаемой постоянен и контролируем.
Зачем здесь очереди, стеки и др. списки - не ясно.
А Вы можете на примере индикатора от разработчиков, показать места "массива фиксированного размера"? Как это работает?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 14:19:48
Цитата
Glukator написал: , чтобы мусорщик память почистил в конкретном этом примере с очередью. Есть у меня некое подобие очереди на свечах - прошлая, текущая, накапливаемая. На границе таймфреймов прошлой присваивается текущая, текущей - накапливаемая, а накапливаемая обнуляется. Понятно, что тут никаких присваиваний nil нафиг не надо, три арифметических операции и все дела. Но тут, насколько я могу понять, VPM пихает в очередь куда больше, чем 3 значения, ему это не подойдет :)
Да хочу чтоб значения были переменной, ну к примеру для сглаживания достаточно три значения, для поиска паттерна нужно 30 и т.д.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
написал: При перезаписи, если нет других ссылок на область памяти, то она будет удалена (почищена) мусорщиком.
Это значит, что память расти не будет.
Тогда хоть Вы поясните Очередь здесь применима как прием?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 14:11:32
Владимир, Вы опять все собрали в кучу, отсюда сумбур. Ветка не моя, публикуются тут все, кому мало мальски интересны темы (я это никак не контролирую), просто также как все высказываюсь. Если Вы не хотите чтоб с Вами дискутировал, не обращайтесь поименно со знаком вопроса. Мне к Вам не зачем обращаться все последние Ваши посты пустые. А пол века не показатель. Зачем к придуркам в вики, определения выложены на этой ветки от азов программирования. Раз не подверглись разбору то я делаю вывод правильные. Про Ваш чудо скрипт все наслышаны ни кто не видел но все знают, зачем одно и тоже повторять (без знака вопроса).
Очереди и двойные очереди в луа, Пример из книги Р.Е.
написал: А что если просто перезаписывать, я про пример из 5 элементов? nil будет вызывать сборщик, а перезапись ну поменял элемент объем остался прежним?
При перезаписи, если нет других ссылок на область памяти, то она будет удалена (почищена) мусорщиком. Под все данные, создаваемые непосредственно в Lua, память выделяется автоматически. Память, занимаемая неиспользуемыми (недостижимыми из скрипта) данными Lua, освобождается также автоматически (при сборке мусора).
Ну что получается мой поход не верен? Пусть массивы растут? Хорошо вопрос ставлю по другому как взять память под контроль чтобы за торговый день в 25 раз не росла?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
написал: А что если просто перезаписывать, я про пример из 5 элементов? nil будет вызывать сборщик, а перезапись ну поменял элемент объем остался прежним?
Не очень понял, что перезаписывать? Если мы все еще про очередь (давайте для определенности положим, что мы добавляем элементы в конец, а извлекаем - с начала), то вариантов что-либо перезаписывать нет. При добавлении элемента - добавляем его, инкрементируем индекс конца очереди. При удалении - извлекаем первый элемент, присваиваем по его индексу nil, инкрементируем индекс начального элемента.
Я не просто про очередь, про двойную очередь из приведенного примера. Переписываются значения, а индексы либо увеличиваются либо уменьшаются в зависимости от варианта(Стек, очередь), структура таблицы остается равная 5 элементам. То есть потребление памяти стабильно, ну или меняется незначительно.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
А что если просто перезаписывать, я про пример из 5 элементов? nil будет вызывать сборщик, а перезапись ну поменял элемент объем остался прежним?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 11:37:23
nikolz, Вам нужно научиться отвечать на заданые Вам вопросы (ну хотябы так Да,Нет) для образованого, интелегеннтного человека это несложно, даже вежливо. Вы погрузились сильно в тему "цифровой обработки сигналов" бывает. В Программирование один сленг, в DSP другой, в торговле третий, еще есть арифметика... И здесь важно, чтоб друг друга понимали. А вот это не понятно
Цитата
nikolz написал: Для экономии памяти очередь вообще не причем.
Как же не влияет?
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Структура с методами это простейший вариант объекта. Метод это функция, сохраненная в элементе таблицы.
Когда я утверждал?
Цитата
Glukator написал: Распинаться здесь, доказывая очевидные вещи (например, что lua НЕ является объектно-ориентированным языком), я не собираюсь - читайте книги (и не по lua, а по структурам данных в общем), поймете многое сами.
Я Вам напомнил что, таблица в луа это половина ОПП! Или и это тоже не верно.
Цитата
Glukator написал: Непонятно, чем вас не устраивает самое простое и самое очевидное решение.
1) Как оказалось есть разные варианты как выбрасывать: сдвигать очередь (table.remove)? Вызывать сборщик (nil); Либо, как в двойной очереди контролировать индексы, пере присваивая значения.
2) Универсальность "написал и забыл", где нужно поднял. Двойную я уже пробовал при обработке таблицы всех сделок, показала себя неплохо. Я уже столько побросал скриптов из-за увеличивающейся сложности, частных решений, что принял свой подход писать модулями, замена одного не влияет на всю конструкцию, плюс оказалось еще и удобно и здесь таблица просто супер.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 09:18:34
Цитата
Владимир написал: А уж изворачиваться и выпендриваться в такой убогой прикладной задаче как торговля...
Задача далеко не простая, просто Ваш подход в моей задаче - это только одна из торговых стратегий, торговую эффективность которой нужно еще проверять! buy = a>b таких примеров полно в том числе и на этом форуме.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
21.01.2024 09:11:33
Glukator, Вы вроде хотели обсуждать торговые Задачи? ДА, за излишнею резкость извиняюсь.
Знание или не знания какого-то языка, ни как не влияют на умственные способности. Про ОПП, на этих страницах я уже приводил авторов, выкладывал цитаты, откуда я делаю свой вывод. Если Вам нужно это оспорить обращайтесь к ним, со мной просто бессмысленно, либо приводите доводы опровергающие их утверждения.
Владимир, Вы начинаете опять все запутывать, у стека есть четкое определение, при вашем подходе и очередь можно называть разновидность стека, но ее называют очередью и дают четкое определение. Вот и двойная очередь оказывается широко известный подход.
Давайте уже определимся что хотя бы здесь, назвать стек стеком, очередь очередью, а разные модификации как Вам нравится.
"НУЖЕН КОНКРЕТНО В ВАШЕЙ ЗАДАЧЕ". Я говорил что мне не нравится как моя программа обращается с памятью. Основная проблема это накопление массивов данных (в моем варианте таблиц). Ну к примеру с частотой в 1 минуту получаю данные по свечам и индикаторам, складываю их в таблицу, которая за время сессии просто растет. Для программы использующей портфель из тикеров, тайм фреймов, индикаторов(планирую переключаться между торговыми стратегиями внутри сессии) это расточительно!
Не знаю как назвать данный способ хранения но точно не стек, хоть и тарелочки из Вашего примера. Так как вся длинна этого массива не нужна (достаточно скажем 5 последних значения) Нужен подход уменьшения количества элементов в таблицах Я Вижу два подхода как организовать такую структуру: 1) После обработке 5 последних значений наставить nil; bar[i][j][index-5].dec=nil; 2) Так как 1 вариант сильно похож на очередь то я вспомнил про двойную очередь из примера автора (которую не удалось обсудить и разобрать с первого поста)
И так задача сводится к удобному универсальному методу уменьшения хранения данных в ОЗУ, по сути в моем представлении к организации ОЧЕРЕДИ!
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
20.01.2024 08:47:55
Владимир, Для особо одаренных. Повторюсь уже в сотый раз, для меня интересно знать возможности языка, как и где их можно применять. Для чего служит тот или другой прием. Не зная возможности не сможешь применить! Пользователь решает чем ему пользоваться. Такой подход называется конструирование. Все автомобили по своей структуре одинаковые (кузов, двигатель, шасси), пользовательские свойства разные.
Вот я же говорю подзабыли, "А двум другим НЕ пофиг, новые элементы заносятся тоже строго на вершину стека, а вот выдернуть их обработчики могут ЛЮБОЙ из них - первый, последний или любой другой из середины. И, если это не последний, скидывают на освободившееся место последний и декрементируют размер стека. А почему это стало стеком и где тут принцип LIFO. Я такие утверждения называю "горе от ума"!
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 22:25:41
Двусторонняя очередь (Double-ended queue), или дек (Deque), расширяет поведение очереди. В дек можно добавлять или удалять элементы как с начала, так и с конца очереди. Такое поведение полезно во многих задачах, например, планирование выполнения потоков или реализация других структур данных. Позже мы рассмотрим вариант реализации стека с помощью двусторонней очереди.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 22:21:39
Посмотрел действительно все логично и просто: Стек — это коллекция, элементы которой получают по принципу «последний вошел, первый вышел» (Last-In-First-Out или LIFO). Это значит, что мы будем иметь доступ только к последнему добавленному элементу.
Очереди очень похожи на стеки. Они также не дают доступа к произвольному элементу, но, в отличие от стека, элементы кладутся (enqueue) и забираются (dequeue) с разных концов. Такой метод называется «первый вошел, первый вышел» (First-In-First-Out или FIFO). То есть забирать элементы из очереди мы будем в том же порядке, что и клали. Как реальная очередь или конвейер.
Прямо как складской учет.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 22:04:18
Nikolay, Ну Вы и пример привели, волосы дыбом от такого примера
Цитата
Nikolay написал: VPM, я могу Вам предложить в качестве развлечения один проект pПогрузитесь в крайнюю степень использования _ENV и все на чистом Lua.Правда не ясно зачем, но, как говорится, красиво.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
VPM написал: 1) value = loadstring("return " .. varname)() 2) value = _G[varname] -- в десятки раз эффективнее
Цитата
VPM написал: В двойной очереди он этот прием демонстрирует.
Glukator, Вы поймите я Вас не обидеть хочу, а показываю прямо то место где идет заблуждение, еще раз Луа = таблица = ОПП, но если Вы используете таблицу , как можно можно не пользоваться ОПП, хотите Вы того или нет, мы эти пользуемся по умолчанию.
Вы опять пытаетесь определять кому что нужно, отвечайте за себя. Давайте про автоматизацию торговли, я только за!
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 21:02:42
Nikolay, Я уже отвечал у меня частная прикладная задача, ну если автор языка пишет двойная очередь, то причем здесь мои академические знания, я принимаю терминологию такой какой в нее заложен смысл автором. За ссылку спасибо посмотрю. Но я уже из беседы сделал ряд выводов для себя мне пока этого достаточно.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 20:42:39
Цитата
Glukator написал: Ага, а утверждение "не буду пользоваться молотком" тождественно "не понимаю, как забивать гвозди"?
не буду пользоваться молотком, когда молоток в рука, а заколочу лбом! Почувствуйте разницу.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 20:40:49
Glukator, Тот пример который Вы показываете, связан с понятия свободных имен. А вопрос который обсуждается относится к применению глобальных переменных с динамическими именами. А Вопрос звучал в каких случаях нужны эти таблицы. На что в нескольких постах получен ответ.
Очереди и двойные очереди в луа, Пример из книги Р.Е.
Пользователь
Сообщений: Регистрация: 15.06.2023
19.01.2024 20:26:46
Еще раз Пересмотрел главу Окружение. Нашел. "Конечно, главной областью применения _ENV является изменение окружения, используемого фрагментом кода." TGB, Спасибо.