← กลับหน้ารายการ

Simple Symmetrical Triangle Strategy (6 points)

Strategy ผู้เขียน: PuestoGlobal Profit Factor: 2.059

ลิงก์ TradingView

เปิดใน TradingView

Equity Chart

Equity chart

เปิดรูปเต็มขนาด

คำอธิบาย

Overview

This strategy identifies triangle patterns formed by a series of key high and low price points. A trade is triggered when the price breaks out from the pattern's final confirmation points: a buy signal occurs on a close above the last high point, and a sell signal on a close below the last low point. To ensure relevance, any pattern that doesn't break out within 10 bars is automatically discarded.

This helps filter out patterns that lose momentum and focuses only on the most imminent breakouts.

How It Works

1. Pattern Detection: The script continuously scans for a sequence of three declining highs (points H1, H2, H3) and three rising lows (points L1, L2, L3) to form a triangle.
2. Entry Logic: The logic is straightforward and based on breaking the last confirmed pivot:
* Long Entry: A buy order is executed if the price closes above the level of the last high (H3).
* Short Entry: A sell order is executed if the price closes below the level of the last low (L3).
3. Pattern Expiration: A triangle only remains "active" for 10 bars after its formation. If a breakout doesn't occur within this window, the pattern is removed from analysis, avoiding trades on prolonged, unresolved consolidations.

Key Features

* Automatic Detection: Identifies and draws triangles for you.
* Simple Breakout Logic: Easy to understand, trades by following the price action.
* Time Filter: Its main advantage is discarding patterns that do not resolve quickly.
* Customizable: You can adjust the sensitivity of the pivot detection in the settings.

Important Disclaimer

This strategy is designed as an entry system and DOES NOT INCLUDE A STOP LOSS OR TAKE PROFIT.

Automation Ready

Want to automate this or ANY strategy on your broker or MetaTrader (MT4/MT5) without keeping your computer on or needing a VPS? You can use WebhookTrade.

รูป Preview

Preview

Pine Script Source

//@version=5
strategy("Symmetrical Triangle Strategy (6 points)", 
     overlay = true, 
     initial_capital = 10000, 
     default_qty_type = strategy.percent_of_equity, 
     default_qty_value = 10,
     pyramiding = 5
     )

// 1. ENTRADAS
var GRP_PATTERN = "Detección del Patrón"
pivotLeftInput = input.int(6, "Fuerza del Pivote (Velas a la Izquierda)", group = GRP_PATTERN)
pivotRightInput = input.int(6, "Retraso de Detección (Velas a la Derecha - Puntos 1 y 2)", group = GRP_PATTERN)
pivotRightSensitiveInput = input.int(1, "Retraso de Detección (Velas a la Derecha - Último Punto)", group = GRP_PATTERN, minval=0)
upperLineColorInput = input.color(color.new(color.red, 50), "Color Líneas Históricas (Sup)", group = GRP_PATTERN)
lowerLineColorInput = input.color(color.new(color.green, 50), "Color Líneas Históricas (Inf)", group = GRP_PATTERN)
maxPatternsInput = input.int(50, "Máximo de Patrones a Dibujar", minval=1, group = GRP_PATTERN)

var GRP_POINTS = "Marcadores de Puntos"
showPointsInput = input.bool(true, "Mostrar Puntos del Patrón", group = GRP_POINTS)
highPointColorInput = input.color(color.new(color.maroon, 20), "Color Puntos Superiores", group = GRP_POINTS)
lowPointColorInput = input.color(color.new(color.teal, 20), "Color Puntos Inferiores", group = GRP_POINTS)
pointSizeInput = input.string(size.small, "Tamaño de los Puntos", options=[size.tiny, size.small, size.normal, size.large, size.huge], group = GRP_POINTS)

// 2. ESTRUCTURAS DE DATOS
type PivotPoint
    float price
    int barIndex
// MODIFICADO: Se añade 'formationBar' para controlar el vencimiento
type ActiveTriangle
    int id
    line upperLine
    line lowerLine
    int apexBar
    float breakoutLevelHigh 
    float breakoutLevelLow
    int formationBar // <-- AÑADIDO
var array<PivotPoint> highPivots = array.new<PivotPoint>(), var array<PivotPoint> lowPivots = array.new<PivotPoint>()
var array<PivotPoint> highPivotsSensitive = array.new<PivotPoint>(), var array<PivotPoint> lowPivotsSensitive = array.new<PivotPoint>()
var array<line> drawnLines = array.new<line>(), var array<label> drawnPoints = array.new<label>()
var array<ActiveTriangle> activeTriangles = array.new<ActiveTriangle>()
var int patternCounter = 0, var int lastPatternBarH = -1, var int lastPatternBarL = -1

// 3. FUNCIÓN DE CÁLCULO
calculateIntersection(PivotPoint p1_top, PivotPoint p2_top, PivotPoint p1_bot, PivotPoint p2_bot) =>
    float m_top = (p2_top.price - p1_top.price) / (p2_top.barIndex - p1_top.barIndex), float m_bot = (p2_bot.price - p1_bot.price) / (p2_bot.barIndex - p1_bot.barIndex)
    if m_top == m_bot or m_top > m_bot
        [int(na), float(na)]
    else
        float c_top = p1_top.price - m_top * p1_top.barIndex, float c_bot = p1_bot.price - m_bot * p1_bot.barIndex
        float intersect_bar_float = (c_bot - c_top) / (m_top - m_bot)
        [int(math.round(intersect_bar_float)), m_top * intersect_bar_float + c_top]

// 4. LÓGICA PRINCIPAL
// --- Detección de Pivotes y Patrones ---
pivotHighPrice = ta.pivothigh(high, pivotLeftInput, pivotRightInput), pivotLowPrice = ta.pivotlow(low, pivotLeftInput, pivotRightInput)
if not na(pivotHighPrice)
    highPivots.push(PivotPoint.new(pivotHighPrice, bar_index - pivotRightInput))
if not na(pivotLowPrice)
    lowPivots.push(PivotPoint.new(pivotLowPrice, bar_index - pivotRightInput))
pivotHighPrice_sens = ta.pivothigh(high, pivotLeftInput, pivotRightSensitiveInput), pivotLowPrice_sens = ta.pivotlow(low, pivotLeftInput, pivotRightSensitiveInput)
if not na(pivotHighPrice_sens)
    highPivotsSensitive.push(PivotPoint.new(pivotHighPrice_sens, bar_index - pivotRightSensitiveInput))
if not na(pivotLowPrice_sens)
    lowPivotsSensitive.push(PivotPoint.new(pivotLowPrice_sens, bar_index - pivotRightSensitiveInput))
if highPivots.size() >= 2 and lowPivots.size() >= 2 and highPivotsSensitive.size() >= 1 and lowPivotsSensitive.size() >= 1
    PivotPoint h1 = highPivots.get(highPivots.size() - 2), PivotPoint h2 = highPivots.get(highPivots.size() - 1)
    PivotPoint l1 = lowPivots.get(lowPivots.size() - 2), PivotPoint l2 = lowPivots.get(lowPivots.size() - 1)
    PivotPoint h3 = highPivotsSensitive.last(), PivotPoint l3 = lowPivotsSensitive.last()
    bool isLowerHighs = h3.price < h2.price and h2.price < h1.price, bool isHigherLows = l3.price > l2.price and l2.price > l1.price
    bool isChronologyOK = h3.barIndex > h2.barIndex and h2.barIndex > h1.barIndex and l3.barIndex > l2.barIndex and l2.barIndex > l1.barIndex
    bool isNewPattern = h3.barIndex > lastPatternBarH and l3.barIndex > lastPatternBarL
    if isLowerHighs and isHigherLows and isChronologyOK and isNewPattern
        [intersectBar, intersectPrice] = calculateIntersection(h1, h3, l1, l3)
        if not na(intersectBar) and intersectBar > bar_index
            patternCounter += 1, lastPatternBarH := h3.barIndex, lastPatternBarL := l3.barIndex
            if showPointsInput
                drawnPoints.push(label.new(h1.barIndex, h1.price, style=label.style_circle, color=highPointColorInput, size=pointSizeInput, tooltip="")), drawnPoints.push(label.new(h2.barIndex, h2.price, style=label.style_circle, color=highPointColorInput, size=pointSizeInput, tooltip="")), drawnPoints.push(label.new(h3.barIndex, h3.price, style=label.style_circle, color=highPointColorInput, size=pointSizeInput, tooltip=""))
                drawnPoints.push(label.new(l1.barIndex, l1.price, style=label.style_circle, color=lowPointColorInput, size=pointSizeInput, tooltip="")), drawnPoints.push(label.new(l2.barIndex, l2.price, style=label.style_circle, color=lowPointColorInput, size=pointSizeInput, tooltip="")), drawnPoints.push(label.new(l3.barIndex, l3.price, style=label.style_circle, color=lowPointColorInput, size=pointSizeInput, tooltip=""))
            line historicalUpper = line.new(h1.barIndex, h1.price, intersectBar, intersectPrice, color=upperLineColorInput, width=1), line historicalLower = line.new(l1.barIndex, l1.price, intersectBar, intersectPrice, color=lowerLineColorInput, width=1)
            drawnLines.push(historicalUpper), drawnLines.push(historicalLower)
            line activeUpper = line.copy(historicalUpper), line activeLower = line.copy(historicalLower)
            activeUpper.set_color(color.new(color.blue, 0)), activeUpper.set_width(2), activeLower.set_color(color.new(color.blue, 0)), activeLower.set_width(2)
            // MODIFICADO: Se guarda la vela de formación del triángulo
            int formationBarIndex = math.max(h3.barIndex, l3.barIndex)
            newTriangle = ActiveTriangle.new(patternCounter, activeUpper, activeLower, intersectBar, h3.price, l3.price, formationBarIndex) // <-- AÑADIDO
            activeTriangles.push(newTriangle)

// --- LÓGICA DE TRADING CON VENCIMIENTO ---
if activeTriangles.size() > 0
    for i = activeTriangles.size() - 1 to 0
        ActiveTriangle currentTriangle = activeTriangles.get(i)
        bool removeTriangle = false

        float triggerLongPrice = currentTriangle.breakoutLevelHigh
        float triggerShortPrice = currentTriangle.breakoutLevelLow

        // NUEVO: Condición de vencimiento por tiempo (10 velas)
        if (bar_index - currentTriangle.formationBar >= 10)
            removeTriangle := true
        
        // CONDICIÓN DE ENTRADA LONG: Si el cierre es mayor que el nivel de ruptura H3.
        if not removeTriangle and (close > triggerLongPrice)
            string tradeId = "L-" + str.tostring(currentTriangle.id)
            strategy.entry(tradeId, strategy.long)
            removeTriangle := true

        // CONDICIÓN DE ENTRADA SHORT: Si el cierre es menor que el nivel de ruptura L3.
        else if not removeTriangle and (close < triggerShortPrice)
            string tradeId = "S-" + str.tostring(currentTriangle.id)
            strategy.entry(tradeId, strategy.short)
            removeTriangle := true

        // Eliminar el triángulo si se marcó para ello (por operación o por vencimiento)
        if removeTriangle
            line.delete(currentTriangle.upperLine)
            line.delete(currentTriangle.lowerLine)
            activeTriangles.remove(i)

// --- Gestión de Dibujos Antiguos ---
while drawnLines.size() > maxPatternsInput * 2
    line.delete(drawnLines.shift())
while drawnPoints.size() > maxPatternsInput * 6
    label.delete(drawnPoints.shift())

// --- Visualización ---
bgcolor(activeTriangles.size() > 0 ? color.new(color.blue, 90) : na, title="Triángulo(s) Activo(s)")