local Engine = {} Engine.__index = Engine local Series = {} Series.__index = Series function Series.new(values) local self = setmetatable({}, Series) self.values = values or {} local length = 0 for i = 1, 1000 do if self.values[i] ~= nil then length = i end end self.length = length return self end function Series:__index(index) if type(index) == "number" then if index < 0 then return self.values[#self.values + index + 1] else return self.values[index] end else local raw_val = rawget(self, index) if raw_val ~= nil then return raw_val end if index == "length" then return rawget(self, "length") end return nil end end function Series:__add(other) local result = {} local other_values = (type(other) == "table" and other.values) and other.values or {} local max_len = math.max(#self.values, #other_values) for i = 1, max_len do local a = self.values[i] or 0 local b = other_values[i] or (type(other) == "number" and other or 0) result[i] = a + b end return Series.new(result) end function Series:__sub(other) local result = {} local other_values = (type(other) == "table" and other.values) and other.values or {} local max_len = math.max(#self.values, #other_values) for i = 1, max_len do local a = self.values[i] or 0 local b = other_values[i] or (type(other) == "number" and other or 0) result[i] = a - b end return Series.new(result) end function Series:__mul(other) local result = {} local other_values = (type(other) == "table" and other.values) and other.values or {} local max_len = math.max(#self.values, #other_values) for i = 1, max_len do local a = self.values[i] or 0 local b = other_values[i] or (type(other) == "number" and other or 0) result[i] = a * b end return Series.new(result) end function Series:__div(other) local result = {} local other_values = (type(other) == "table" and other.values) and other.values or {} local max_len = math.max(#self.values, #other_values) for i = 1, max_len do local a = self.values[i] or 0 local b = other_values[i] or (type(other) == "number" and other or 1) result[i] = b ~= 0 and (a / b) or 0 end return Series.new(result) end function Series:__pow(other) local result = {} for i = 1, #self.values do local a = self.values[i] or 0 local b = (type(other) == "table" and other.values and other.values[i]) or other or 1 result[i] = a ^ b end return Series.new(result) end function Series:__eq(other) if type(other) == "number" then local result = {} for i = 1, #self.values do result[i] = self.values[i] == other and 1 or 0 end return Series.new(result) elseif type(other) == "table" and other.values then local result = {} for i = 1, math.max(#self.values, #other.values) do local a = self.values[i] or 0 local b = other.values[i] or 0 result[i] = a == b and 1 or 0 end return Series.new(result) end return false end function Series:__lt(other) if type(self) ~= "table" then return false end local self_values = rawget(self, "values") if type(other) == "number" then local result = {} for i = 1, #self_values do result[i] = (self_values[i] or 0) < other and 1 or 0 end return Series.new(result) elseif type(other) == "table" and rawget(other, "values") then local other_values = rawget(other, "values") local result = {} local max_len = math.max(#self_values, #other_values) for i = 1, max_len do local a = self_values[i] or 0 local b = other_values[i] or 0 result[i] = a < b and 1 or 0 end return Series.new(result) end return false end function Series:__le(other) if type(self) ~= "table" then return false end local self_values = rawget(self, "values") if type(other) == "number" then local result = {} for i = 1, #self_values do result[i] = (self_values[i] or 0) <= other and 1 or 0 end return Series.new(result) elseif type(other) == "table" and rawget(other, "values") then local other_values = rawget(other, "values") local result = {} local max_len = math.max(#self_values, #other_values) for i = 1, max_len do local a = self_values[i] or 0 local b = other_values[i] or 0 result[i] = a <= b and 1 or 0 end return Series.new(result) end return false end function Series:__gt(other) if type(self) ~= "table" then return false end local self_values = rawget(self, "values") if type(other) == "number" then local result = {} for i = 1, #self_values do result[i] = (self_values[i] or 0) > other and 1 or 0 end return Series.new(result) elseif type(other) == "table" and rawget(other, "values") then local other_values = rawget(other, "values") local result = {} local max_len = math.max(#self_values, #other_values) for i = 1, max_len do local a = self_values[i] or 0 local b = other_values[i] or 0 result[i] = a > b and 1 or 0 end return Series.new(result) end return false end function Series:__ge(other) if type(self) ~= "table" then return false end local self_values = rawget(self, "values") if type(other) == "number" then local result = {} for i = 1, #self_values do result[i] = (self_values[i] or 0) >= other and 1 or 0 end return Series.new(result) elseif type(other) == "table" and rawget(other, "values") then local other_values = rawget(other, "values") local result = {} local max_len = math.max(#self_values, #other_values) for i = 1, max_len do local a = self_values[i] or 0 local b = other_values[i] or 0 result[i] = a >= b and 1 or 0 end return Series.new(result) end return false end function Series:__and(other) if type(other) == "number" then local result = {} for i = 1, #self.values do result[i] = ((self.values[i] or 0) ~= 0 and other ~= 0) and 1 or 0 end return Series.new(result) elseif type(other) == "table" and other.values then local result = {} local max_len = math.max(#self.values, #other.values) for i = 1, max_len do local a = (self.values[i] or 0) ~= 0 local b = (other.values[i] or 0) ~= 0 result[i] = (a and b) and 1 or 0 end return Series.new(result) end return false end function Series:__or(other) if type(other) == "number" then local result = {} for i = 1, #self.values do result[i] = ((self.values[i] or 0) ~= 0 or other ~= 0) and 1 or 0 end return Series.new(result) elseif type(other) == "table" and other.values then local result = {} local max_len = math.max(#self.values, #other.values) for i = 1, max_len do local a = (self.values[i] or 0) ~= 0 local b = (other.values[i] or 0) ~= 0 result[i] = (a or b) and 1 or 0 end return Series.new(result) end return false end function Series:__len() return #self.values end function Series:__unm() local result = {} for i = 1, #self.values do result[i] = self.values[i] and -self.values[i] or nil end return Series.new(result) end function Engine.new() local self = setmetatable({}, Engine) self.instrument_config = {} self.plots = {} self.inputs = {} self.input_groups = {} self.series_cache = {} self.candles = {} self.user_inputs = {} return self end function Engine:_create_series_from_candles(field) local series = {} for i, candle in ipairs(self.candles) do series[i] = candle[field] end return Series.new(series) end function Engine:_sma(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} for i = 1, #series do if i < period then result[i] = nil else local sum = 0 for j = i - period + 1, i do sum = sum + (series[j] or 0) end result[i] = sum / period end end return Series.new(result) end function Engine:_ema(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} local multiplier = 2 / (period + 1) for i = 1, period - 1 do result[i] = nil end local sum = 0 for i = 1, period do sum = sum + (series[i] or 0) end result[period] = sum / period for i = period + 1, #series do result[i] = (series[i] or 0) * multiplier + (result[i-1] or result[period]) * (1 - multiplier) end return Series.new(result) end function Engine:_rsi(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} local gains = {} local losses = {} for i = 1, period do result[i] = nil end for i = 2, #series do local change = (series[i] or 0) - (series[i-1] or 0) gains[i] = change > 0 and change or 0 losses[i] = change < 0 and -change or 0 end local avg_gain = 0 local avg_loss = 0 for i = 2, period + 1 do avg_gain = avg_gain + (gains[i] or 0) avg_loss = avg_loss + (losses[i] or 0) end avg_gain = avg_gain / period avg_loss = avg_loss / period for i = period + 1, #series do if i > period + 1 then avg_gain = (avg_gain * (period - 1) + (gains[i] or 0)) / period avg_loss = (avg_loss * (period - 1) + (losses[i] or 0)) / period end local rs = avg_loss > 0 and (avg_gain / avg_loss) or 0 result[i] = 100 - (100 / (1 + rs)) end return Series.new(result) end function Engine:_stdev(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} for i = period, #series do local sum = 0 local mean_sum = 0 for j = i - period + 1, i do mean_sum = mean_sum + series[j] end local mean = mean_sum / period for j = i - period + 1, i do sum = sum + (series[j] - mean) ^ 2 end result[i] = math.sqrt(sum / period) end return Series.new(result) end function Engine:_change(series, period) if type(series) == "table" and series.values then series = series.values end period = period or 1 local result = {} for i = period + 1, #series do result[i] = series[i] - series[i - period] end return Series.new(result) end function Engine:_highest(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} for i = period, #series do local max = series[i - period + 1] for j = i - period + 2, i do if series[j] > max then max = series[j] end end result[i] = max end return Series.new(result) end function Engine:_lowest(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} for i = period, #series do local min = series[i - period + 1] for j = i - period + 2, i do if series[j] < min then min = series[j] end end result[i] = min end return Series.new(result) end function Engine:_rma(series, period) return self:_ema(series, period) end function Engine:_mad(series, period) if type(series) == "table" and series.values then series = series.values end local result = {} for i = period, #series do local sum = 0 for j = i - period + 1, i do sum = sum + series[j] end local mean = sum / period local mad_sum = 0 for j = i - period + 1, i do mad_sum = mad_sum + math.abs(series[j] - mean) end result[i] = mad_sum / period end return Series.new(result) end function Engine:_shift(series, offset, extension_candles) if type(series) == "table" and series.values then series = series.values end offset = offset or 0 extension_candles = extension_candles or 0 local result = {} local len = #series local new_len = len + extension_candles for i = 1, new_len do local src_index = i - offset if src_index >= 1 and src_index <= len then result[i] = series[src_index] else result[i] = nil end end return Series.new(result) end function Engine:_tr() local high_vals = self:_create_series_from_candles("high") local low_vals = self:_create_series_from_candles("low") local close_vals = self:_create_series_from_candles("close") if high_vals.values then high_vals = high_vals.values end if low_vals.values then low_vals = low_vals.values end if close_vals.values then close_vals = close_vals.values end local result = {} for i = 1, #high_vals do if i == 1 then result[i] = high_vals[i] - low_vals[i] else local hl = high_vals[i] - low_vals[i] local hpc = math.abs(high_vals[i] - (close_vals[i-1] or close_vals[i])) local lpc = math.abs(low_vals[i] - (close_vals[i-1] or close_vals[i])) result[i] = math.max(hl, hpc, lpc) end end return Series.new(result) end function Engine:_bb(series, period, mult) if type(series) == "table" and series.values then series = series.values end mult = mult or 2 local middle = self:_sma(series, period) local std = self:_stdev(series, period) local middle_vals = middle.values or middle local std_vals = std.values or std local upper_vals = {} local lower_vals = {} for i = 1, #middle_vals do if middle_vals[i] and std_vals[i] then upper_vals[i] = middle_vals[i] + mult * std_vals[i] lower_vals[i] = middle_vals[i] - mult * std_vals[i] else upper_vals[i] = nil lower_vals[i] = nil end end return { upper = Series.new(upper_vals), middle = middle, lower = Series.new(lower_vals) } end function Engine:_abs(series) if type(series) == "number" then return math.abs(series) end if type(series) == "table" and series.values then series = series.values end local result = {} for i = 1, #series do result[i] = series[i] and math.abs(series[i]) or nil end return Series.new(result) end function Engine:_neg(series) if type(series) == "number" then return -series end if type(series) == "table" and series.values then series = series.values end local result = {} for i = 1, #series do result[i] = series[i] and -series[i] or nil end return Series.new(result) end function Engine:plot(series, label, color, width, style) local values = series if type(series) == "table" and series.values then values = series.values end table.insert(self.plots, { type = "plot", label = label or "Plot", color = color or "#000000", width = width or 1, style = style or "solid", values = values, length = type(series) == "table" and series.length or #values }) end function Engine:hline(value, label, color, width, style) local values = {} for i = 1, #self.candles do values[i] = value end table.insert(self.plots, { type = "hline", label = label or "H-Line", color = color or "#000000", width = width or 1, style = style or "solid", values = values }) end function Engine:fill(series1, series2, color, opacity) if type(series1) == "table" and series1.values then series1 = series1.values end if type(series2) == "table" and series2.values then series2 = series2.values end table.insert(self.plots, { type = "fill", label = "Fill", color = color or "#000000", opacity = opacity or 0.2, values = { series1, series2 } }) end function Engine:plot_histogram(series, label, color, width) if type(series) == "table" and series.values then series = series.values end table.insert(self.plots, { type = "histogram", label = label or "Histogram", color = color or "#000000", width = width or 1, values = series }) end function Engine:plot_candle(open, high, low, close, label, color) if type(open) == "table" and open.values then open = open.values end if type(high) == "table" and high.values then high = high.values end if type(low) == "table" and low.values then low = low.values end if type(close) == "table" and close.values then close = close.values end table.insert(self.plots, { type = "candle", label = label or "Candle", values = { open = open, high = high, low = low, close = close }, colors = color }) end function Engine:plot_shape(condition, label, style, size, color, location, offset, text, text_color) if type(condition) == "table" and condition.values then condition = condition.values end table.insert(self.plots, { type = "shape", label = label or "Shape", style = style or "circle", size = size or "normal", color = color or "#000000", location = location or "abovebar", offset = offset or 0, text = text or "", text_color = text_color or "#000000", values = condition }) end function Engine:plot_arrow(up_series, down_series, label, color) if type(up_series) == "table" and up_series.values then up_series = up_series.values end if type(down_series) == "table" and down_series.values then down_series = down_series.values end table.insert(self.plots, { type = "arrow", label = label or "Arrow", color = color or "#000000", values = { up = up_series, down = down_series } }) end function Engine:input(default, label, input_type, ...) local args = {...} local min, max, step = args[1], args[2], args[3] local input_def = { default = default, name = label, type = input_type or "double", min = min, max = max, step = step } table.insert(self.inputs, input_def) return self.user_inputs[label] or default end function Engine:input_group(name, ...) local args = {...} local group = { name = name, inputs = {} } for i, v in ipairs(args) do if type(v) == "table" and v.name then table.insert(group.inputs, v) end end table.insert(self.input_groups, group) end function Engine:instrument(config) self.instrument_config = config end function Engine:iff(condition, value_true, value_false) if type(condition) == "table" and condition.values then local result = {} for i = 1, #condition.values do local cond = condition.values[i] local v_true = (type(value_true) == "table" and value_true.values) and value_true.values[i] or value_true local v_false = (type(value_false) == "table" and value_false.values) and value_false.values[i] or value_false result[i] = (cond and cond ~= 0) and v_true or v_false end return Series.new(result) else return condition and value_true or value_false end end function Engine:_math_max(...) local args = {...} local result = {} local max_len = 0 for _, arg in ipairs(args) do if type(arg) == "table" and arg.values then max_len = math.max(max_len, #arg.values) end end if max_len == 0 then return math.max(unpack(args)) end for i = 1, max_len do local max_val = -math.huge for _, arg in ipairs(args) do local val if type(arg) == "table" and arg.values then val = arg.values[i] or -math.huge else val = arg or -math.huge end max_val = math.max(max_val, val) end result[i] = max_val end return Series.new(result) end function Engine:_math_min(...) local args = {...} local result = {} local max_len = 0 for _, arg in ipairs(args) do if type(arg) == "table" and arg.values then max_len = math.max(max_len, #arg.values) end end if max_len == 0 then return math.min(unpack(args)) end for i = 1, max_len do local min_val = math.huge for _, arg in ipairs(args) do local val if type(arg) == "table" and arg.values then val = arg.values[i] or math.huge else val = arg or math.huge end min_val = math.min(min_val, val) end result[i] = min_val end return Series.new(result) end function Engine:execute(script, candles, user_inputs) self.candles = candles self.user_inputs = user_inputs or {} self.plots = {} self.inputs = {} self.input_groups = {} local input_types = { integer = "integer", double = "double", string = "string", color = "color", string_selection = "string_selection", line_width = "line_width", line_style = "line_style" } local input_wrapper = setmetatable({}, { __call = function(_, ...) return self:input(...) end }) for k, v in pairs(input_types) do input_wrapper[k] = v end local env = { open = self:_create_series_from_candles("open"), high = self:_create_series_from_candles("high"), low = self:_create_series_from_candles("low"), close = self:_create_series_from_candles("close"), volume = self:_create_series_from_candles("volume"), sma = function(series, period) return self:_sma(series, period) end, ema = function(series, period) return self:_ema(series, period) end, rsi = function(series, period) return self:_rsi(series, period) end, stdev = function(series, period) return self:_stdev(series, period) end, change = function(series, period) return self:_change(series, period) end, highest = function(series, period) return self:_highest(series, period) end, lowest = function(series, period) return self:_lowest(series, period) end, rma = function(series, period) return self:_rma(series, period) end, mad = function(series, period) return self:_mad(series, period) end, shift = function(series, offset, extension) return self:_shift(series, offset, extension) end, tr = function() return self:_tr() end, bb = function(series, period, mult) return self:_bb(series, period, mult) end, add = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = v1 + v2 end return Series.new(result) end return a + b end, sub = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or a_vals[i] local v2 = b_is_num and b or b_vals[i] if v1 == nil or v2 == nil then result[i] = nil else result[i] = v1 - v2 end end return Series.new(result) end return a - b end, mult = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = v1 * v2 end return Series.new(result) end return a * b end, div = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 1) result[i] = v2 ~= 0 and (v1 / v2) or 0 end return Series.new(result) end return b ~= 0 and (a / b) or 0 end, neg = function(series) return self:_neg(series) end, abs = function(series) return self:_abs(series) end, gt = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = v1 > v2 and 1 or 0 end return Series.new(result) end return a > b and 1 or 0 end, lt = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = v1 < v2 and 1 or 0 end return Series.new(result) end return a < b and 1 or 0 end, ge = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = v1 >= v2 and 1 or 0 end return Series.new(result) end return a >= b and 1 or 0 end, le = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = v1 <= v2 and 1 or 0 end return Series.new(result) end return a <= b and 1 or 0 end, and_op = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = (v1 ~= 0 and v2 ~= 0) and 1 or 0 end return Series.new(result) end return (a ~= 0 and b ~= 0) and 1 or 0 end, or_op = function(a, b) if type(a) == "table" or type(b) == "table" then local a_vals = (type(a) == "table" and a.values) and a.values or (type(a) == "table" and a or {}) local b_vals = (type(b) == "table" and b.values) and b.values or (type(b) == "table" and b or {}) local a_is_num = type(a) == "number" local b_is_num = type(b) == "number" local len = math.max(a_is_num and 0 or #a_vals, b_is_num and 0 or #b_vals) local result = {} for i = 1, len do local v1 = a_is_num and a or (a_vals[i] or 0) local v2 = b_is_num and b or (b_vals[i] or 0) result[i] = (v1 ~= 0 or v2 ~= 0) and 1 or 0 end return Series.new(result) end return (a ~= 0 or b ~= 0) and 1 or 0 end, plot = function(...) return self:plot(...) end, hline = function(...) return self:hline(...) end, fill = function(...) return self:fill(...) end, plot_histogram = function(...) return self:plot_histogram(...) end, plot_candle = function(...) return self:plot_candle(...) end, plot_shape = function(...) return self:plot_shape(...) end, plot_arrow = function(...) return self:plot_arrow(...) end, input = input_wrapper, input_group = function(...) return self:input_group(...) end, instrument = function(config) return self:instrument(config) end, iff = function(...) return self:iff(...) end, math = { max = function(...) return self:_math_max(...) end, min = function(...) return self:_math_min(...) end, abs = math.abs, sqrt = math.sqrt, floor = math.floor, ceil = math.ceil, sin = math.sin, cos = math.cos, tan = math.tan, log = math.log, exp = math.exp, pi = math.pi, huge = math.huge }, print = print, type = type, tostring = tostring, tonumber = tonumber, pairs = pairs, ipairs = ipairs, table = table, string = string, shape_style = { triangleup = "triangleup", triangledown = "triangledown", circle = "circle", square = "square", diamond = "diamond" }, shape_size = { small = "small", normal = "normal", large = "large" }, shape_location = { abovebar = "abovebar", belowbar = "belowbar" }, color = { blue = "#0000FF", red = "#FF0000", green = "#00FF00", white = "#FFFFFF", black = "#000000", orange = "#FFA500", yellow = "#FFFF00", aqua = "#00FFFF", lime = "#00FF00", purple = "#800080", gray = "#808080", grey = "#808080", silver = "#C0C0C0", maroon = "#800000", navy = "#000080", teal = "#008080", olive = "#808000", fuchsia = "#FF00FF" }, linestyle = { solid = "solid", dashed = "dashed", dotted = "dotted" }, -- Funções auxiliares para Supertrend hl2 = function() local high = self:_create_series_from_candles("high") local low = self:_create_series_from_candles("low") local result = {} for i = 1, #high.values do result[i] = (high.values[i] + low.values[i]) / 2 end return Series.new(result) end, na = function(value) if type(value) == "table" and value.values then local result = {} for i = 1, #value.values do result[i] = value.values[i] == nil and 1 or 0 end return Series.new(result) end return value == nil and 1 or 0 end, nz = function(value, default) default = default or 0 if type(value) == "table" and value.values then local result = {} for i = 1, #value.values do result[i] = value.values[i] == nil and default or value.values[i] end return Series.new(result) end return value == nil and default or value end, max = function(...) return self:_math_max(...) end, min = function(...) return self:_math_min(...) end } local func, err = load(script, "script", "t", env) if not func then return { success = false, error = "Script error: " .. err } end local success, exec_err = pcall(func) if not success then return { success = false, error = "Execution error: " .. exec_err } end return { success = true, data = { instrument = self.instrument_config, inputs = self.inputs, plots = self.plots } } end function Engine:to_json() local function serialize(obj) if type(obj) == "nil" then return "null" elseif type(obj) == "boolean" then return obj and "true" or "false" elseif type(obj) == "number" then return tostring(obj) elseif type(obj) == "string" then return '"' .. obj:gsub('"', '\\"') .. '"' elseif type(obj) == "table" then if obj.values then local arr = "[" for i = 1, #obj.values do if i > 1 then arr = arr .. "," end arr = arr .. serialize(obj.values[i]) end arr = arr .. "]" return arr else local is_array = true local max_index = 0 for k in pairs(obj) do if type(k) ~= "number" then is_array = false break end if k > max_index then max_index = k end end if is_array then local arr = "[" for i = 1, max_index do if i > 1 then arr = arr .. "," end arr = arr .. serialize(obj[i]) end arr = arr .. "]" return arr else local json = "{" local first = true for k, v in pairs(obj) do if not first then json = json .. "," end first = false json = json .. '"' .. k .. '":' .. serialize(v) end json = json .. "}" return json end end else return "null" end end return serialize({ instrument = self.instrument_config, inputs = self.inputs, plots = self.plots }) end return Engine