Eins-Zwei-Drei Umkehr-Strategie
Die Eins-Zwei-Drei Umkehr-Strategie sucht nach einem bullischen 1-2-3-Muster in der Preisentwicklung. Eine Long-Position wird eröffnet, wenn das heutige Tief unter dem gestrigen liegt, das gestrige Tief unter dem Tief vor drei Bars liegt, das Tief vor zwei Bars unter dem Tief vor vier Bars liegt und das Hoch vor zwei Bars unter dem Hoch vor drei Bars liegt. Der Trade wird nach einer definierten Anzahl von Bars oder wenn der Preis über einem gleitenden Durchschnitt schließt, geschlossen.
Details
- Einstiegskriterien:
- Aktuelles Tief < vorheriges Tief.
- Vorheriges Tief < Tief vor drei Bars.
- Tief vor zwei Bars < Tief vor vier Bars.
- Hoch vor zwei Bars < Hoch vor drei Bars.
- Long/Short: Nur Long.
- Ausstiegskriterien:
- Halten für
DaysToHoldBars oder Schlusskurs überquert den gleitenden Durchschnitt nach oben.
- Halten für
- Stops: Keine.
- Standardwerte:
DaysToHold= 7MaLength= 200
- Filter:
- Kategorie: Umkehr
- Richtung: Nur Long
- Indikatoren: Price action, SMA
- Stops: Nein
- Komplexität: Niedrig
- Zeitrahmen: Täglich
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// One-Two-Three Reversal Strategy.
/// Detects 1-2-3 bottom pattern (descending lows with rising highs) and buys.
/// Exits after holding period or when price crosses above MA.
/// </summary>
public class OneTwoThreeReversalStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _holdBars;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _sma;
private decimal _low1, _low2, _low3, _low4;
private decimal _high1, _high2, _high3;
private int _historyCount;
private int _barsSinceEntry;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int HoldBars
{
get => _holdBars.Value;
set => _holdBars.Value = value;
}
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public OneTwoThreeReversalStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_holdBars = Param(nameof(HoldBars), 15)
.SetGreaterThanZero()
.SetDisplay("Hold Bars", "Bars to hold position", "Trading");
_maLength = Param(nameof(MaLength), 50)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Moving average period", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_low1 = _low2 = _low3 = _low4 = 0;
_high1 = _high2 = _high3 = 0;
_historyCount = 0;
_barsSinceEntry = int.MaxValue;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal maValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
_barsSinceEntry++;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
UpdateHistory(candle);
return;
}
if (_historyCount >= 4)
{
// Exit conditions
if (Position > 0 && (_barsSinceEntry >= HoldBars || candle.ClosePrice >= maValue))
{
SellMarket(Math.Abs(Position));
_barsSinceEntry = int.MaxValue;
_cooldownRemaining = CooldownBars;
}
// 1-2-3 bottom pattern: descending lows (bearish trend weakening)
// + highs starting to rise (bullish reversal)
else if (Position <= 0)
{
var condition1 = candle.LowPrice < _low1;
var condition2 = _low1 < _low3;
var condition3 = _low2 < _low4;
var condition4 = _high2 < _high3;
if (condition1 && condition2 && condition3 && condition4)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_barsSinceEntry = 0;
_cooldownRemaining = CooldownBars;
}
}
}
UpdateHistory(candle);
}
private void UpdateHistory(ICandleMessage candle)
{
_low4 = _low3;
_low3 = _low2;
_low2 = _low1;
_low1 = candle.LowPrice;
_high3 = _high2;
_high2 = _high1;
_high1 = candle.HighPrice;
if (_historyCount < 4)
_historyCount++;
}
}
import clr
import sys
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class one_two_three_reversal_strategy(Strategy):
"""One-Two-Three Reversal Strategy."""
def __init__(self):
super(one_two_three_reversal_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._hold_bars = self.Param("HoldBars", 15) \
.SetDisplay("Hold Bars", "Bars to hold position", "Trading")
self._ma_length = self.Param("MaLength", 50) \
.SetDisplay("MA Length", "Moving average period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._sma = None
self._low1 = 0.0
self._low2 = 0.0
self._low3 = 0.0
self._low4 = 0.0
self._high1 = 0.0
self._high2 = 0.0
self._high3 = 0.0
self._history_count = 0
self._bars_since_entry = 999999999
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(one_two_three_reversal_strategy, self).OnReseted()
self._sma = None
self._low1 = 0.0
self._low2 = 0.0
self._low3 = 0.0
self._low4 = 0.0
self._high1 = 0.0
self._high2 = 0.0
self._high3 = 0.0
self._history_count = 0
self._bars_since_entry = 999999999
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(one_two_three_reversal_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = int(self._ma_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._sma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
self._bars_since_entry += 1
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._update_history(candle)
return
hold = int(self._hold_bars.Value)
cooldown = int(self._cooldown_bars.Value)
price = float(candle.ClosePrice)
ma_val = float(ma_value)
if self._history_count >= 4:
if self.Position > 0 and (self._bars_since_entry >= hold or price >= ma_val):
self.SellMarket(Math.Abs(self.Position))
self._bars_since_entry = 999999999
self._cooldown_remaining = cooldown
elif self.Position <= 0:
condition1 = float(candle.LowPrice) < self._low1
condition2 = self._low1 < self._low3
condition3 = self._low2 < self._low4
condition4 = self._high2 < self._high3
if condition1 and condition2 and condition3 and condition4:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._bars_since_entry = 0
self._cooldown_remaining = cooldown
self._update_history(candle)
def _update_history(self, candle):
self._low4 = self._low3
self._low3 = self._low2
self._low2 = self._low1
self._low1 = float(candle.LowPrice)
self._high3 = self._high2
self._high2 = self._high1
self._high1 = float(candle.HighPrice)
if self._history_count < 4:
self._history_count += 1
def CreateClone(self):
return one_two_three_reversal_strategy()