Die Karacatica-Strategie ist ein trendfolgender Ansatz, der Preisaktionen mit dem Average Directional Index (ADX) kombiniert. Sie sucht nach Situationen, in denen der aktuelle Schlusskurs höher oder niedriger als der Schlusskurs vor einer bestimmten Anzahl von Kerzen ist, und bestätigt die Bewegung mit der Dominanz der +DI- oder -DI-Linie.
Indikatoren
Average Directional Index (ADX) – misst die Trendstärke und liefert die +DI- und -DI-Komponenten.
Preisvergleich – prüft, ob der letzte Schluss über oder unter dem Schluss von Period Kerzen zurück liegt.
Parameter
Period – Anzahl der Kerzen für die ADX-Berechnung und den Rückblick für den Preisvergleich. Standard ist 70.
TakeProfitPercent – Take-Profit ausgedrückt als Prozentsatz des Einstiegspreises. Standard ist 2%.
StopLossPercent – Stop-Loss ausgedrückt als Prozentsatz des Einstiegspreises. Standard ist 1%.
CandleType – Zeitrahmen der zu abonnierenden Kerzen. Standard ist 1 Stunde.
Handelslogik
Long-Einstieg: Close > Close[Period] und +DI > -DI ohne vorhandenes Long-Signal. Schließt Short-Positionen und eröffnet eine Long-Position.
Short-Einstieg: Close < Close[Period] und -DI > +DI ohne vorhandenes Short-Signal. Schließt Long-Positionen und eröffnet eine Short-Position.
Positionsschutz: StartProtection wendet sowohl Take-Profit- als auch Stop-Loss-Prozentsätze an.
Verwendungshinweise
Entwickelt für die High-Level-API von StockSharp; abonniert Kerzen und bindet den ADX-Indikator.
Die Strategie schließt automatisch entgegengesetzte Positionen, wenn ein neues Signal erscheint.
Derzeit ist keine Python-Implementierung vorgesehen.
Haftungsausschluss
Dieses Beispiel dient nur zu Bildungszwecken und garantiert keine Gewinne. Der Handel ist mit erheblichem Risiko verbunden. Testen Sie Strategien immer gründlich, bevor Sie sie auf Live-Märkten einsetzen.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Karacatica strategy uses ADX to determine trend direction and compares
/// current close price with the close price from a specified period ago.
/// It goes long when an uptrend is detected and price is rising, and
/// goes short when a downtrend is detected and price is falling.
/// </summary>
public class KaracaticaStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private AverageDirectionalIndex _adx;
private readonly Queue<decimal> _closeQueue = new();
private int _lastSignal;
/// <summary>
/// Indicator period used for ADX and price comparison.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// Candle type parameter.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public KaracaticaStrategy()
{
_period = Param(nameof(Period), 30)
.SetGreaterThanZero()
.SetDisplay("Period", "ADX period and lookback for close comparison", "Indicators")
.SetOptimize(20, 50, 10);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_adx = null;
_closeQueue.Clear();
_lastSignal = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_adx = new AverageDirectionalIndex { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_adx, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _adx);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
_closeQueue.Enqueue(candle.ClosePrice);
if (_closeQueue.Count > Period + 1)
_closeQueue.Dequeue();
if (_closeQueue.Count <= Period)
return;
if (!adxValue.IsFormed)
return;
var pastClose = _closeQueue.Peek();
var adxTyped = adxValue as IAverageDirectionalIndexValue;
if (adxTyped?.Dx is not IDirectionalIndexValue dxVal)
return;
var plusDi = dxVal.Plus;
var minusDi = dxVal.Minus;
if (plusDi is null || minusDi is null)
return;
var buySignal = candle.ClosePrice > pastClose && plusDi > minusDi && _lastSignal != 1;
var sellSignal = candle.ClosePrice < pastClose && minusDi > plusDi && _lastSignal != -1;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (buySignal && Position <= 0)
{
BuyMarket();
_lastSignal = 1;
}
else if (sellSignal && Position >= 0)
{
SellMarket();
_lastSignal = -1;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageDirectionalIndex
from StockSharp.Algo.Strategies import Strategy
class karacatica_strategy(Strategy):
def __init__(self):
super(karacatica_strategy, self).__init__()
self._period = self.Param("Period", 30) \
.SetDisplay("Period", "ADX period and lookback for close comparison", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._close_queue = []
self._last_signal = 0
@property
def period(self):
return self._period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(karacatica_strategy, self).OnReseted()
self._close_queue = []
self._last_signal = 0
def OnStarted2(self, time):
super(karacatica_strategy, self).OnStarted2(time)
adx = AverageDirectionalIndex()
adx.Length = self.period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(adx, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, adx)
self.DrawOwnTrades(area)
def process_candle(self, candle, adx_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
self._close_queue.append(close)
if len(self._close_queue) > self.period + 1:
self._close_queue.pop(0)
if len(self._close_queue) <= self.period:
return
if not adx_value.IsFormed:
return
past_close = self._close_queue[0]
plus_di = adx_value.Dx.Plus
minus_di = adx_value.Dx.Minus
if plus_di is None or minus_di is None:
return
plus_di = float(plus_di)
minus_di = float(minus_di)
buy_signal = close > past_close and plus_di > minus_di and self._last_signal != 1
sell_signal = close < past_close and minus_di > plus_di and self._last_signal != -1
if buy_signal and self.Position <= 0:
self.BuyMarket()
self._last_signal = 1
elif sell_signal and self.Position >= 0:
self.SellMarket()
self._last_signal = -1
def CreateClone(self):
return karacatica_strategy()