Mi estrategia — Strategy by fasc3333

By version

Performance Metrics

Description

//version=5indicator("Zonas de Rebote + SL/TP (HobbieCode)", overlay=true, max_boxes_count=100, max_lines_count=200, max_labels_count=200, max_bars_back=5000)// ============================================================================// ENTRADAS / INPUTS// ============================================================================grpDet = "Detección"pivotLen = input.int(10, "Longitud Pivote S/R", minval=2, maxval=50, group=grpDet)tlPivotLen = input.int(8, "Longitud Pivote Tendencia", minval=2, maxval=30, group=grpDet)lookback = input.int(300, "Barras a analizar", minval=50, maxval=5000, group=grpDet)srTolerance = input.float(0.5,"Tolerancia agrupación (×ATR)", minval=0.1, maxval=5.0, step=0.1, group=grpDet)tlTolerance = input.float(0.3,"Tolerancia toque tendencia (×ATR)", minval=0.1, maxval=3.0, step=0.1, group=grpDet)minTouchesTL = input.int(2, "Toques mínimos tendencia", minval=2, maxval=10, group=grpDet)grpZonas = "Zonas de Rebote"zoneHeight = input.float(0.6, "Altura de zona (×ATR)", minval=0.1, maxval=3.0, step=0.1, group=grpZonas)maxZones = input.int(5, "Máx. zonas a mostrar", minval=1, maxval=15, group=grpZonas)minScore = input.float(30, "Puntuación mínima (%)", minval=10, maxval=100, step=5, group=grpZonas)mergeZones = input.bool(true, "Fusionar zonas solapadas", group=grpZonas)grpFiltro = "Filtros de Relevancia"showOnlyNearby = input.bool(true, "Mostrar solo zonas cercanas", group=grpFiltro)nearbyRange = input.float(8.0, "Rango cercanía (×ATR)", minval=1.0, maxval=30.0, step=0.5, group=grpFiltro)grpTrade = "Plan de Trade (SL/TP)"showTradePlan = input.bool(true, "Mostrar plan SL/TP", group=grpTrade)slBufferATR = input.float(0.5, "Colchón SL (×ATR)", minval=0.1, maxval=3.0, step=0.1, group=grpTrade, tooltip="Distancia extra del SL fuera de la zona para evitar barridos")minRR = input.float(1.0, "Ratio R:R mínimo", minval=0.5, maxval=5.0, step=0.1, group=grpTrade, tooltip="Si TP1 no alcanza este ratio, no se muestra el plan")tpExtendATR = input.float(3.0, "TP fallback (×ATR si no hay objetivo)", minval=1.0, maxval=10.0, step=0.5, group=grpTrade)showOnlyTopPlan = input.bool(false, "Solo plan de la mejor zona", group=grpTrade, tooltip="Si está activo, solo dibuja el plan de la zona con mayor score")grpStyle = "Estilo Visual"demandColor = input.color(#26a69a, "Color zona de DEMANDA", group=grpStyle)supplyColor = input.color(#ef5350, "Color zona de OFERTA", group=grpStyle)slColor = input.color(#e91e63, "Color SL", group=grpStyle)tp1Color = input.color(#4caf50, "Color TP1", group=grpStyle)tp2Color = input.color(#2e7d32, "Color TP2", group=grpStyle)showScore = input.bool(true, "Mostrar puntuación de zona", group=grpStyle)showPanel = input.bool(true, "Mostrar panel resumen", group=grpStyle)extendBars = input.int(30, "Extensión hacia la derecha", minval=5, maxval=100, group=grpStyle)// ============================================================================// FUNCIONES AUXILIARES// ============================================================================atr = ta.atr(14)f_scoreAlpha(float score) => int(math.round(80.0 - (score / 100.0) * 65.0))// ============================================================================// PIVOTES// ============================================================================ph = ta.pivothigh(high, pivotLen, pivotLen)pl = ta.pivotlow(low, pivotLen, pivotLen)phTL = ta.pivothigh(high, tlPivotLen, tlPivotLen)plTL = ta.pivotlow(low, tlPivotLen, tlPivotLen)var array pHighs = array.new()var array pHighB = array.new()var array pLows = array.new()var array pLowB = array.new()if not na(ph) array.push(pHighs, ph) array.push(pHighB, bar_index - pivotLen) if array.size(pHighs) > 200 array.shift(pHighs) array.shift(pHighB)if not na(pl) array.push(pLows, pl) array.push(pLowB, bar_index - pivotLen) if array.size(pLows) > 200 array.shift(pLows) array.shift(pLowB)var array tlPHs = array.new()var array tlPHb = array.new()var array tlPLs = array.new()var array tlPLb = array.new()if not na(phTL) array.push(tlPHs, phTL) array.push(tlPHb, bar_index - tlPivotLen) if array.size(tlPHs) > 100 array.shift(tlPHs) array.shift(tlPHb)if not na(plTL) array.push(tlPLs, plTL) array.push(tlPLb, bar_index - tlPivotLen) if array.size(tlPLs) > 100 array.shift(tlPLs) array.shift(tlPLb)// ============================================================================// TIPOS// ============================================================================type SRLevel float price int touches int firstBar int lastBar bool isDemandtype Zone float topPrice float botPrice float centerPrice int firstBar int touches int trendlineHits bool isDemand float score float entryPrice float slPrice float tp1Price float tp2Price float rr1 float rr2 bool hasValidPlan// ============================================================================// CLUSTERS S/R// ============================================================================f_buildClusters(array prices, array bars, bool isDem) => array result = array.new() int n = array.size(prices) if n > 0 for i = 0 to n - 1 float p = array.get(prices, i) int b = array.get(bars, i) if (bar_index - b) 0 for j = 0 to csize - 1 SRLevel lvl = array.get(result, j) if math.abs(lvl.price - p) int hits = 0 float tol = atr * (srTolerance + 0.2) if isDemand int n = array.size(tlPLs) if n >= 2 for i = 0 to n - 2 for j = i + 1 to n - 1 int b1 = array.get(tlPLb, i) float p1 = array.get(tlPLs, i) int b2 = array.get(tlPLb, j) float p2 = array.get(tlPLs, j) if (bar_index - b1) p1 and b2 > b1 float slope = (p2 - p1) / float(b2 - b1) int tcount = 0 for b = b1 to bar_index int off = bar_index - b if off >= 0 and off = minTouchesTL float yNow = p1 + slope * (bar_index - b1) if math.abs(yNow - price) = 2 for i = 0 to n - 2 for j = i + 1 to n - 1 int b1 = array.get(tlPHb, i) float p1 = array.get(tlPHs, i) int b2 = array.get(tlPHb, j) float p2 = array.get(tlPHs, j) if (bar_index - b1) b1 float slope = (p2 - p1) / float(b2 - b1) int tcount = 0 for b = b1 to bar_index int off = bar_index - b if off >= 0 and off = minTouchesTL float yNow = p1 + slope * (bar_index - b1) if math.abs(yNow - price) zoneBoxes = array.new()var array zoneLabels = array.new()var array planLines = array.new()var array planLabels = array.new()f_clearAll() => if array.size(zoneBoxes) > 0 for i = 0 to array.size(zoneBoxes) - 1 box.delete(array.get(zoneBoxes, i)) array.clear(zoneBoxes) if array.size(zoneLabels) > 0 for i = 0 to array.size(zoneLabels) - 1 label.delete(array.get(zoneLabels, i)) array.clear(zoneLabels) if array.size(planLines) > 0 for i = 0 to array.size(planLines) - 1 line.delete(array.get(planLines, i)) array.clear(planLines) if array.size(planLabels) > 0 for i = 0 to array.size(planLabels) - 1 label.delete(array.get(planLabels, i)) array.clear(planLabels)// ============================================================================// CÁLCULO DE PLAN SL/TP PARA UNA ZONA// ============================================================================// Busca los siguientes objetivos (zonas opuestas) en el array completo de zonasf_calculatePlan(Zone z, array allZones) => float entry = z.centerPrice float sl = na float tp1 = na float tp2 = na if z.isDemand // LONG: SL debajo del fondo de la zona, TPs en zonas de oferta superiores sl := z.botPrice - (atr * slBufferATR) // Recopilar zonas de oferta por encima del entry, ordenadas por cercanía array targets = array.new() if array.size(allZones) > 0 for i = 0 to array.size(allZones) - 1 Zone t = array.get(allZones, i) if not t.isDemand and t.botPrice > entry array.push(targets, t.botPrice) // Ordenar ascendente if array.size(targets) > 1 array.sort(targets, order.ascending) if array.size(targets) >= 1 tp1 := array.get(targets, 0) else tp1 := entry + (atr * tpExtendATR) if array.size(targets) >= 2 tp2 := array.get(targets, 1) else tp2 := entry + (atr * tpExtendATR * 1.8) else // SHORT: SL encima del techo de la zona, TPs en zonas de demanda inferiores sl := z.topPrice + (atr * slBufferATR) array targets = array.new() if array.size(allZones) > 0 for i = 0 to array.size(allZones) - 1 Zone t = array.get(allZones, i) if t.isDemand and t.topPrice 1 array.sort(targets, order.descending) if array.size(targets) >= 1 tp1 := array.get(targets, 0) else tp1 := entry - (atr * tpExtendATR) if array.size(targets) >= 2 tp2 := array.get(targets, 1) else tp2 := entry - (atr * tpExtendATR * 1.8) // Calcular ratios R:R float risk = math.abs(entry - sl) float r1 = risk > 0 ? math.abs(tp1 - entry) / risk : 0.0 float r2 = risk > 0 ? math.abs(tp2 - entry) / risk : 0.0 bool valid = r1 >= minRR z.entryPrice := entry z.slPrice := sl z.tp1Price := tp1 z.tp2Price := tp2 z.rr1 := r1 z.rr2 := r2 z.hasValidPlan := valid z// ============================================================================// VARIABLES DE PANEL// ============================================================================var int panelDemandCount = 0var int panelSupplyCount = 0var float panelTopScore = 0.0var float panelTopPrice = 0.0var bool panelTopIsDemand = falsevar float panelTopRR = 0.0// ============================================================================// PROCESO PRINCIPAL// ============================================================================if barstate.islast f_clearAll() // 1) Construir clusters array demands = f_buildClusters(pLows, pLowB, true) array supplies = f_buildClusters(pHighs, pHighB, false) array allLevels = array.new() if array.size(demands) > 0 for i = 0 to array.size(demands) - 1 array.push(allLevels, array.get(demands, i)) if array.size(supplies) > 0 for i = 0 to array.size(supplies) - 1 array.push(allLevels, array.get(supplies, i)) // 2) Máximo de toques int maxTouches = 1 if array.size(allLevels) > 0 for i = 0 to array.size(allLevels) - 1 SRLevel lvl = array.get(allLevels, i) if lvl.touches > maxTouches maxTouches := lvl.touches // 3) Generar zonas con scoring array zones = array.new() if array.size(allLevels) > 0 for i = 0 to array.size(allLevels) - 1 SRLevel lvl = array.get(allLevels, i) if lvl.touches >= 2 bool keep = true if showOnlyNearby if math.abs(lvl.price - close) > atr * nearbyRange keep := false if keep int tlHits = f_trendlineConfluence(lvl.price, lvl.isDemand) float touchPct = math.min(1.0, lvl.touches / float(math.max(maxTouches, 3))) float tlPct = math.min(1.0, tlHits / 3.0) float agePct = math.min(1.0, (lvl.lastBar - lvl.firstBar) / float(lookback)) float bonusPct = lvl.touches >= 3 ? 1.0 : (lvl.touches >= 2 ? 0.5 : 0.0) float score = (touchPct * 50.0) + (tlPct * 25.0) + (agePct * 15.0) + (bonusPct * 10.0) score := math.min(100.0, score) if score >= minScore float halfH = atr * zoneHeight / 2.0 Zone z = Zone.new(lvl.price + halfH, lvl.price - halfH, lvl.price, lvl.firstBar, lvl.touches, tlHits, lvl.isDemand, score, na, na, na, na, 0.0, 0.0, false) array.push(zones, z) // 4) Fusión de zonas solapadas if mergeZones and array.size(zones) > 1 array merged = array.new() for i = 0 to array.size(zones) - 1 Zone cur = array.get(zones, i) bool absorbed = false int ms = array.size(merged) if ms > 0 for k = 0 to ms - 1 Zone ex = array.get(merged, k) bool sameType = ex.isDemand == cur.isDemand bool overlap = cur.botPrice = ex.botPrice if sameType and overlap ex.topPrice := math.max(ex.topPrice, cur.topPrice) ex.botPrice := math.min(ex.botPrice, cur.botPrice) ex.centerPrice := (ex.topPrice + ex.botPrice) / 2.0 ex.touches += cur.touches ex.trendlineHits += cur.trendlineHits ex.score := math.min(100.0, ex.score + cur.score * 0.3) ex.firstBar := math.min(ex.firstBar, cur.firstBar) array.set(merged, k, ex) absorbed := true break if not absorbed array.push(merged, cur) zones := merged // 5) Ordenar por score int zsize = array.size(zones) if zsize > 1 for i = 0 to zsize - 2 for j = 0 to zsize - 2 - i Zone a = array.get(zones, j) Zone b = array.get(zones, j + 1) if a.score finalZones = array.new() int toDraw = math.min(maxZones, array.size(zones)) if toDraw > 0 for i = 0 to toDraw - 1 array.push(finalZones, array.get(zones, i)) // 7) Calcular plan SL/TP para cada zona (usando el conjunto completo como referencia) int fz = array.size(finalZones) if fz > 0 for i = 0 to fz - 1 Zone z = array.get(finalZones, i) z := f_calculatePlan(z, finalZones) array.set(finalZones, i, z) // 8) Dibujar zonas panelDemandCount := 0 panelSupplyCount := 0 panelTopScore := 0.0 panelTopRR := 0.0 if fz > 0 for i = 0 to fz - 1 Zone z = array.get(finalZones, i) color baseCol = z.isDemand ? demandColor : supplyColor color fillCol = color.new(baseCol, f_scoreAlpha(z.score)) color borderCol = color.new(baseCol, math.max(0, f_scoreAlpha(z.score) - 30)) int xEnd = bar_index + extendBars box bx = box.new(z.firstBar, z.topPrice, xEnd, z.botPrice, border_color=borderCol, border_width=1, bgcolor=fillCol) array.push(zoneBoxes, bx) if showScore string typeTxt = z.isDemand ? "DEMANDA" : "OFERTA" string txt = typeTxt + " " + str.tostring(math.round(z.score)) + "%" if z.trendlineHits > 0 txt := txt + " ⚡" + str.tostring(z.trendlineHits) txt := txt + " ×" + str.tostring(z.touches) label lb = label.new(xEnd, z.centerPrice, txt, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(baseCol, 10), textcolor=color.white, size=size.small) array.push(zoneLabels, lb) if z.isDemand panelDemandCount += 1 else panelSupplyCount += 1 if z.score > panelTopScore panelTopScore := z.score panelTopPrice := z.centerPrice panelTopIsDemand := z.isDemand panelTopRR := z.rr1 // 9) Dibujar SL/TP solo para zonas con plan válido if showTradePlan // Determinar índice máximo a dibujar int planLimit = showOnlyTopPlan ? 1 : fz for i = 0 to math.min(planLimit, fz) - 1 Zone z = array.get(finalZones, i) if z.hasValidPlan int xEnd = bar_index + extendBars int xStart = bar_index + 2 // Línea SL line slLine = line.new(xStart, z.slPrice, xEnd, z.slPrice, color=color.new(slColor, 0), width=2, style=line.style_dashed) array.push(planLines, slLine) label slLabel = label.new(xEnd, z.slPrice, "SL " + str.tostring(math.round_to_mintick(z.slPrice)), xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(slColor, 20), textcolor=color.white, size=size.small) array.push(planLabels, slLabel) // Línea TP1 line tp1Line = line.new(xStart, z.tp1Price, xEnd, z.tp1Price, color=color.new(tp1Color, 0), width=2, style=line.style_dashed) array.push(planLines, tp1Line) string tp1Txt = "TP1 " + str.tostring(math.round_to_mintick(z.tp1Price)) + " (R:R " + str.tostring(z.rr1, "#.##") + ")" label tp1Label = label.new(xEnd, z.tp1Price, tp1Txt, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(tp1Color, 20), textcolor=color.white, size=size.small) array.push(planLabels, tp1Label) // Línea TP2 line tp2Line = line.new(xStart, z.tp2Price, xEnd, z.tp2Price, color=color.new(tp2Color, 0), width=2, style=line.style_dotted) array.push(planLines, tp2Line) string tp2Txt = "TP2 " + str.tostring(math.round_to_mintick(z.tp2Price)) + " (R:R " + str.tostring(z.rr2, "#.##") + ")" label tp2Label = label.new(xEnd, z.tp2Price, tp2Txt, xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(tp2Color, 20), textcolor=color.white, size=size.small) array.push(planLabels, tp2Label) // Línea de entrada line entryLine = line.new(xStart, z.entryPrice, xEnd, z.entryPrice, color=color.new(color.yellow, 30), width=1, style=line.style_solid) array.push(planLines, entryLine) string dirArrow = z.isDemand ? "↑ LONG" : "↓ SHORT" label entryLabel = label.new(xEnd, z.entryPrice, dirArrow + " " + str.tostring(math.round_to_mintick(z.entryPrice)), xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(color.yellow, 20), textcolor=color.black, size=size.small) array.push(planLabels, entryLabel)// ============================================================================// PANEL RESUMEN// ============================================================================var table panel = table.new(position.top_right, 2, 6, bgcolor=color.new(color.black, 80), border_width=1, border_color=color.new(color.gray, 50))if barstate.islast and showPanel table.cell(panel, 0, 0, "ZONAS + PLAN", text_color=color.white, text_size=size.normal, bgcolor=color.new(color.blue, 40)) table.cell(panel, 1, 0, "", bgcolor=color.new(color.blue, 40)) table.cell(panel, 0, 1, "Demanda", text_color=color.white, text_size=size.small) table.cell(panel, 1, 1, str.tostring(panelDemandCount), text_color=color.new(demandColor, 0), text_size=size.small) table.cell(panel, 0, 2, "Oferta", text_color=color.white, text_size=size.small) table.cell(panel, 1, 2, str.tostring(panelSupplyCount), text_color=color.new(supplyColor, 0), text_size=size.small) string topTxt = panelTopScore > 0 ? (panelTopIsDemand ? "↑ " : "↓ ") + str.tostring(math.round_to_mintick(panelTopPrice)) : "—" table.cell(panel, 0, 3, "Mejor zona", text_color=color.white, text_size=size.small) table.cell(panel, 1, 3, topTxt, text_color=color.white, text_size=size.small) table.cell(panel, 0, 4, "Score", text_color=color.white, text_size=size.small) table.cell(panel, 1, 4, str.tostring(math.round(panelTopScore)) + "%", text_color=color.yellow, text_size=size.small) table.cell(panel, 0, 5, "R:R TP1", text_color=color.white, text_size=size.small) table.cell(panel, 1, 5, panelTopRR > 0 ? str.tostring(panelTopRR, "#.##") : "—", text_color=color.aqua, text_size=size.small)

Browse all 5,900+ TradingView Pine Script strategies

View on TradingView