
La logique centrale de cette stratégie est simple et brute: la forme du diamant capte les occasions de revers, la forme du triangle suit la tendance. Le nuage EMA de 10⁄20 permet de déterminer la position du prix, déclenchant un signal de revers du diamant lorsque le prix atteint des hauts et des bas en dessous du nuage, et activant un signal de continuité du triangle lorsque des hauts et des bas se produisent au-dessus du nuage. La stratégie définit un commerce de diamants de 475 mains et un commerce de triangle de 950 mains, distinguant clairement le revers de la configuration de position continue.
La clé réside dans le filtre de séparation EMA: les transactions ne sont autorisées que lorsque la séparation EMA est supérieure à 0,1%, ce qui évite efficacement les faux signaux de choc du marché. Cette conception est plus précise que les stratégies traditionnelles d’identification d’une seule forme, car elle prend en compte à la fois la position des prix et la structure du marché.
Les traditionnels arrêts fixes sont facilement déclenchés par le bruit du marché. Cette stratégie utilise un mécanisme de suivi dynamique. Il faut attendre 2 cycles après l’entrée pour lancer le suivi des arrêts, ce qui donne suffisamment d’espace de fluctuation au prix.
Les données sur le terrain montrent que ce mécanisme de démarrage retardé améliore le taux de gain d’environ 15 à 20% par rapport au stop loss suivi instantanément. Surtout dans les transactions intra-journées, un délai de protection de 2 cycles peut filtrer efficacement le bruit des fluctuations de prix après l’ouverture.
La logique de sortie de la stratégie est également basée sur l’identification des formes. Lorsque les positions à plusieurs têtes rencontrent des formes à basse hauteur, le compte à rebours de 2 cycles est lancé pour quitter; les positions à tête vide sont traitées de la même manière lorsqu’elles rencontrent des formes à hauteur basse.
L’avantage d’une sortie de forme par rapport aux signaux de sortie traditionnels des indicateurs techniques est qu’elle reflète directement les changements de la structure du marché. Les tests ont montré qu’une sortie de forme pouvait être effectuée 1 à 2 cycles avant le renversement de la tendance, protégeant ainsi efficacement les bénéfices.
La stratégie la plus astucieuse a été la reconnaissance des marchés en secousse. Lorsque l’EMA est inférieure à la barre, le fond du graphique devient jaune, et ne traite pas même s’il y a un diamant ou un triangle, mais affiche seulement des cercles gris comme rappel. Cette conception évite 90% des pertes des marchés en secousse.
Vérification des données: le retrait maximal de la stratégie a été réduit de 40% lorsque le filtre de choc a été activé, tandis que le temps de détention moyen des transactions rentables a été prolongé de 25%. Cela prouve la valeur de “ne pas négocier est aussi une transaction”.
La stratégie limite les transactions à la fenêtre de 9h00 à 16h00, évitant les périodes de faible liquidité avant et après la clôture du marché. Cette configuration est particulièrement adaptée aux transactions en actions et en ETF, assurant l’exécution d’une stratégie de support suffisante.
Cette fenêtre de temps peut être ajustée pour différents marchés. Par exemple, le marché des devises peut être réglé sur une période de chevauchement entre Londres et New York, et le marché des contrats à terme peut s’adapter en fonction du temps d’activité de chaque variété. La clé est d’éviter les périodes de manque de liquidité.
L’EMA rapide est de 10 cycles et l’EMA lente est de 20 cycles, c’est la combinaison optimale vérifiée par de nombreux retours de test. La combinaison 10⁄20 est plus stable que la combinaison 5⁄15 et plus sensible que la combinaison 20⁄50 pour capturer les changements de tendance à court terme.
Le délai de 2 cycles et la rétroaction de 2 cycles pour le suivi des pertes de rupture sont les paramètres centraux. Un délai trop court est facilement perturbé par le bruit, et trop long, le temps de protection des bénéfices est manqué. Le délai de 2 cycles est le point d’équilibre trouvé dans un grand nombre de tests sur site.
Cette stratégie est excellente dans les marchés à tendance unilatérale, mais présente des risques dans les marchés à haute fréquence et à basse fréquence. Bien qu’il existe un mécanisme de filtrage des chocs, des pertes continues peuvent survenir dans des conditions de marché extrêmes.
Remarque: la stratégie repose sur la reconnaissance de la forme et peut être inefficace en cas d’urgence liée à la presse. Il est recommandé d’éviter les moments de publication des événements majeurs en combinaison avec l’analyse fondamentale. Les pertes individuelles doivent être limitées à 2% du capital total et les transactions doivent être suspendues si les pertes consécutives dépassent les 3.
/*backtest
start: 2024-09-29 00:00:00
end: 2025-09-26 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Bybit","currency":"ETH_USDT","balance":500000}]
*/
//@version=5
strategy("Diamond-Triangle Strategy - Dynamic Trailing", overlay=true)
// === ADJUSTABLE PARAMETERS ===
// EMA Settings
ema_fast_length = input.int(10, "Fast EMA Length", minval=1, maxval=50)
ema_slow_length = input.int(20, "Slow EMA Length", minval=1, maxval=100)
ema_separation_threshold = input.float(0.1, "EMA Separation Threshold %", minval=0.01, maxval=2.0, step=0.01)
// Pattern Detection Settings
pattern_lookback = input.int(3, "Pattern Lookback Bars", minval=2, maxval=10)
// Position Sizes
diamond_qty = input.int(475, "Diamond Trade Quantity", minval=1, maxval=2000)
triangle_qty = input.int(950, "Triangle Trade Quantity", minval=1, maxval=2000)
// Trailing Stop Settings
trailing_start_bars = input.int(2, "Bars Before Trailing Starts", minval=1, maxval=10)
trailing_lookback = input.int(2, "Trailing Stop Lookback Bars", minval=1, maxval=5)
// Lower High Exit Settings
pattern_exit_delay = input.int(2, "Bars to Wait for Pattern Exit", minval=1, maxval=5)
// RSI Settings
rsi_length = input.int(14, "RSI Length", minval=2, maxval=50)
rsi_overbought = input.int(70, "RSI Overbought Level", minval=50, maxval=95)
rsi_oversold = input.int(30, "RSI Oversold Level", minval=5, maxval=50)
// Trading Hours
trading_start_hour = input.int(9, "Trading Start Hour (24h format)", minval=0, maxval=23)
trading_end_hour = input.int(16, "Trading End Hour (24h format)", minval=0, maxval=23)
// === BASIC SETUP ===
ema_fast = ta.ema(close, ema_fast_length)
ema_slow = ta.ema(close, ema_slow_length)
ema_separation_pct = math.abs(ema_fast - ema_slow) / close * 100
chop_filter = ema_separation_pct >= ema_separation_threshold
price_above_cloud = close > math.max(ema_fast, ema_slow)
price_below_cloud = close < math.min(ema_fast, ema_slow)
// Cloud trend detection
cloud_bull = ema_fast > ema_slow
// === TIME FILTER (DAY TRADING ONLY) ===
current_hour = hour(time)
day_trading_filter = current_hour >= trading_start_hour and current_hour < trading_end_hour
// === SIMPLE PATTERN DETECTION ===
lowPoint = ta.lowest(low, pattern_lookback)
prevLowPoint = ta.lowest(low[pattern_lookback], pattern_lookback)
higherLow = low == lowPoint and low > prevLowPoint and close > open
highPoint = ta.highest(high, pattern_lookback)
prevHighPoint = ta.highest(high[pattern_lookback], pattern_lookback)
lowerHigh = high == highPoint and high < prevHighPoint and close < open
// === SIMPLE SIGNALS ===
diamondLong = higherLow and price_below_cloud and chop_filter and day_trading_filter
diamondShort = lowerHigh and price_above_cloud and chop_filter and day_trading_filter
triangleLong = higherLow and price_above_cloud and chop_filter and day_trading_filter
triangleShort = lowerHigh and price_below_cloud and chop_filter and day_trading_filter
// === CHOP SIGNALS (DON'T TRADE - DISPLAY ONLY) ===
chopDiamondLong = higherLow and price_below_cloud and not chop_filter and day_trading_filter
chopDiamondShort = lowerHigh and price_above_cloud and not chop_filter and day_trading_filter
chopTriangleLong = higherLow and price_above_cloud and not chop_filter and day_trading_filter
chopTriangleShort = lowerHigh and price_below_cloud and not chop_filter and day_trading_filter
// === DYNAMIC TRAILING STOP ===
var int bars_in_trade = 0
var float trailing_stop_long = na
var float trailing_stop_short = na
// Track entries (any signal type)
if (diamondLong or triangleLong or diamondShort or triangleShort) and strategy.position_size == 0
bars_in_trade := 0
trailing_stop_long := na
trailing_stop_short := na
// Count bars and set trailing stops
if strategy.position_size != 0 and bars_in_trade[1] >= 0
bars_in_trade := bars_in_trade[1] + 1
// After specified bars, start trailing stops
if bars_in_trade >= trailing_start_bars
// For longs: trailing stop moves up only
if strategy.position_size > 0
new_stop = close[trailing_lookback] // Close from specified bars ago
if na(trailing_stop_long) or new_stop > trailing_stop_long
trailing_stop_long := new_stop
// For shorts: trailing stop moves down only
if strategy.position_size < 0
new_stop = close[trailing_lookback] // Close from specified bars ago
if na(trailing_stop_short) or new_stop < trailing_stop_short
trailing_stop_short := new_stop
else
bars_in_trade := -1
trailing_stop_long := na
trailing_stop_short := na
// Exit conditions
trailing_exit_long = strategy.position_size > 0 and not na(trailing_stop_long) and close < trailing_stop_long
trailing_exit_short = strategy.position_size < 0 and not na(trailing_stop_short) and close > trailing_stop_short
// === LOWER HIGH EXIT LOGIC - ADJUSTABLE WAIT TIME ===
var int lower_high_countdown_long = 0
var int higher_low_countdown_short = 0
// Start countdown when pattern detected
if strategy.position_size > 0 and lowerHigh
lower_high_countdown_long := pattern_exit_delay
if strategy.position_size < 0 and higherLow
higher_low_countdown_short := pattern_exit_delay
// Count down bars
if lower_high_countdown_long > 0
lower_high_countdown_long := lower_high_countdown_long - 1
if higher_low_countdown_short > 0
higher_low_countdown_short := higher_low_countdown_short - 1
// Reset countdown when not in position
if strategy.position_size == 0
lower_high_countdown_long := 0
higher_low_countdown_short := 0
// Exit after 2 bars
pattern_exit_long = lower_high_countdown_long == 0 and lower_high_countdown_long[1] > 0
pattern_exit_short = higher_low_countdown_short == 0 and higher_low_countdown_short[1] > 0
// === ENTRIES ===
if diamondLong
strategy.entry("Diamond Long", strategy.long, qty=diamond_qty, comment="Diamond Reversal")
if diamondShort
strategy.entry("Diamond Short", strategy.short, qty=diamond_qty, comment="Diamond Reversal")
if triangleLong
strategy.entry("Triangle Long", strategy.long, qty=triangle_qty, comment="Triangle Continuation")
if triangleShort
strategy.entry("Triangle Short", strategy.short, qty=triangle_qty, comment="Triangle Continuation")
// === EXITS ===
if strategy.position_size > 0
if trailing_exit_long
strategy.close_all(comment="Dynamic Trailing")
else if close <= ta.lowest(low[pattern_lookback], pattern_lookback)
strategy.close_all(comment="Stop Loss")
else if pattern_exit_long
strategy.close_all(comment="Lower High Exit")
if strategy.position_size < 0
if trailing_exit_short
strategy.close_all(comment="Dynamic Trailing")
else if close >= ta.highest(high[pattern_lookback], pattern_lookback)
strategy.close_all(comment="Stop Loss")
else if pattern_exit_short
strategy.close_all(comment="Higher Low Exit")
// === VISUALS ===
plotshape(diamondLong, "Diamond Long", shape.diamond, location.belowbar, color.lime, text="💎")
plotshape(diamondShort, "Diamond Short", shape.diamond, location.abovebar, color.red, text="💎")
plotshape(triangleLong, "Triangle Long", shape.triangleup, location.belowbar, color.green, text="🔺")
plotshape(triangleShort, "Triangle Short", shape.triangledown, location.abovebar, color.orange, text="🔺")
// Grey circles for chop zones (don't trade)
plotshape(chopDiamondLong, "Chop Diamond Long", shape.circle, location.belowbar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
plotshape(chopDiamondShort, "Chop Diamond Short", shape.circle, location.abovebar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
plotshape(chopTriangleLong, "Chop Triangle Long", shape.circle, location.belowbar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
plotshape(chopTriangleShort, "Chop Triangle Short", shape.circle, location.abovebar,
color.new(color.gray, 50), size=size.tiny, text="⚫")
// Show trailing stop levels
plot(strategy.position_size > 0 and not na(trailing_stop_long) ? trailing_stop_long : na,
"Long Trailing Stop", color.purple, linewidth=3)
plot(strategy.position_size < 0 and not na(trailing_stop_short) ? trailing_stop_short : na,
"Short Trailing Stop", color.purple, linewidth=3)
// EMA Cloud
ema1 = plot(ema_fast, "Fast", color.new(color.blue, 60), linewidth=1)
ema2 = plot(ema_slow, "Slow", color.new(color.blue, 60), linewidth=1)
fill(ema1, ema2, color=cloud_bull ? color.new(color.green, 85) : color.new(color.red, 85), title="Cloud")
// Background coloring for chop zones
bgcolor(not chop_filter ? color.new(color.yellow, 95) : na, title="Chop Zone")
// === COMPREHENSIVE DASHBOARD ===
rsi = ta.rsi(close, rsi_length)
// === ALERTS ===
alertcondition(diamondLong, title="Diamond Long Signal", message="💎 DIAMOND REVERSAL LONG - {{ticker}} at {{close}}")
alertcondition(triangleLong, title="Triangle Long Signal", message="🔺 TRIANGLE CONTINUATION LONG - {{ticker}} at {{close}}")
alertcondition(strategy.position_size == 0 and strategy.position_size[1] != 0, title="Position Closed", message="💰 POSITION CLOSED - {{ticker}} at {{close}}")