// © RicardoSantos
//@version=5
// @description Method to generate decision tree based on weights.
library(title='FunctionDecisionTree')
// @function Method to generate decision tree based on weights.
// @param weights float array, weights for decision consideration.
// @param depth int, depth of the tree.
// @returns int array
export decision_tree(float[] weights, int depth) => //{
int _size_w = array.size(id=weights)
//
int[] _path = array.new_int(size=0, initial_value=0)
int _sumweights = math.ceil(array.sum(id=weights))
if _size_w > 0 and depth > 0 and _sumweights == 1
for _d = 1 to depth by 1
for _w = 0 to 999 by 1
int _select_weight_index = int(math.random(max=_size_w))
float _rng = math.random(max=1.0)
float _weight = array.get(id=weights, index=_select_weight_index)
if _weight >= _rng
array.push(id=_path, value=_select_weight_index)
break
_path
//{ usage:
// Input Parameters:
int depth = input.int(defval=1, minval=1)
int paths = input.int(defval=2, minval=1)
int number_of_weights = input.int(defval=2, minval=1)
// Array to contain weights, sum of array values must be 1.
var float[] node_weights = array.new_float(size=number_of_weights, initial_value=0)
if barstate.isfirst
float _weight = 1.0 / number_of_weights
for _i=1 to number_of_weights
array.set(node_weights, _i-1, _weight)
string t = ''
for _p = 1 to paths by 1
_path = decision_tree(node_weights, depth)
t := t + '\nPath ' + str.tostring(_p, '#') + ': ' + str.tostring(_path)
t
var label la = label.new(bar_index, 0.0, t)
//{ remarks:
//}}}
//@version=5
indicator("Decision Tree Indicator with Technical Indicators and Signals", overlay=true)
// Importar la librería
import RicardoSantos/FunctionDecisionTree/1 as dt
// Parámetros de entrada
depth = input.int(defval=3, minval=1, title="Depth of the Tree")
paths = input.int(defval=2, minval=1, title="Number of Paths")
number_of_weights = input.int(defval=2, minval=1, title="Number of Weights")
// Array para contener los pesos, la suma de los valores del array debe ser 1.
var float[] node_weights = array.new_float(size=number_of_weights, initial_value=0)
if barstate.isfirst
float _weight = 1.0 / number_of_weights
for _i=0 to number_of_weights - 1
array.set(node_weights, _i, _weight)
// Generar caminos de decisión
string t = ''
var int[] decision_paths = na
if barstate.islast
decision_paths := array.new_int(0)
for _p = 1 to paths by 1
_path = dt.decision_tree(node_weights, depth)
for val in _path
array.push(decision_paths, val)
t := t + '\nPath ' + str.tostring(_p, '#') + ': ' + str.tostring(_path)
// Mostrar los caminos en el gráfico
var label la = na
if barstate.islast
la := label.new(bar_index, na, t, color=color.blue, textcolor=color.white, style=label.style_label_down, size=size.small)
label.set_xy(la, bar_index, high)
// Indicadores técnicos
sma_short = ta.sma(close, 14)
sma_long = ta.sma(close, 50)
rsi = ta.rsi(close, 14)
[macdLine, signalLine, _] = ta.macd(close, 12, 26, 9)
// Plotear indicadores técnicos
plot(sma_short, color=color.green, title="SMA 14")
plot(sma_long, color=color.red, title="SMA 50")
hline(70, "RSI Overbought", color=color.red)
hline(30, "RSI Oversold", color=color.green)
plot(rsi, color=color.blue, title="RSI")
plot(macdLine, color=color.orange, title="MACD Line")
plot(signalLine, color=color.purple, title="Signal Line")
// Generar señales de compra y venta basadas en indicadores técnicos y caminos de decisión
buy_signal = (not na(decision_paths)) and (array.size(decision_paths) > 0) and (array.get(decision_paths, 0) == 1) and (rsi < 30) and (macdLine > signalLine) and (sma_short > sma_long)
sell_signal = (not na(decision_paths)) and (array.size(decision_paths) > 0) and (array.get(decision_paths, 0) == 0) and (rsi > 70) and (macdLine < signalLine) and (sma_short < sma_long)
// Plotear señales de compra y venta
plotshape(series=buy_signal, location=location.belowbar, color=color.green, style=shape.labelup, title="Buy Signal", text="BUY")
plotshape(series=sell_signal, location=location.abovebar, color=color.red, style=shape.labeldown, title="Sell Signal", text="SELL")