Estrategia de Media Móvil Adaptativa de Kaufman
Esta estrategia utiliza la Media Móvil Adaptativa de Kaufman (KAMA). Se abre una posición larga cuando la KAMA sube durante un número específico de barras y se cierra cualquier posición corta. Se abre una posición corta cuando la KAMA cae durante el período requerido y se cierra cualquier posición larga.
Parámetros
- Tipo de vela
- Longitud
- Período rápido
- Período lento
- Período de subida
- Período de caída
- Dirección de la orden
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Kaufman Adaptive Moving Average (KAMA) strategy.
/// </summary>
public class KaufmanAdaptiveMovingAverageStrategy : Strategy
{
public enum TradeSides
{
Long,
Short,
Both
}
private readonly StrategyParam<int> _length;
private readonly StrategyParam<int> _fast;
private readonly StrategyParam<int> _slow;
private readonly StrategyParam<int> _risingPeriod;
private readonly StrategyParam<int> _fallingPeriod;
private readonly StrategyParam<TradeSides> _orderDirection;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevKama;
private int _risingCount;
private int _fallingCount;
private bool _isFirst = true;
private bool _wasRising;
private bool _wasFalling;
public int Length { get => _length.Value; set => _length.Value = value; }
public int Fast { get => _fast.Value; set => _fast.Value = value; }
public int Slow { get => _slow.Value; set => _slow.Value = value; }
public int RisingPeriod { get => _risingPeriod.Value; set => _risingPeriod.Value = value; }
public int FallingPeriod { get => _fallingPeriod.Value; set => _fallingPeriod.Value = value; }
public TradeSides OrderDirection { get => _orderDirection.Value; set => _orderDirection.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public KaufmanAdaptiveMovingAverageStrategy()
{
_length = Param(nameof(Length), 10)
.SetGreaterThanZero()
.SetDisplay("Length", "KAMA lookback period", "KAMA")
.SetOptimize(5, 20, 5);
_fast = Param(nameof(Fast), 5)
.SetGreaterThanZero()
.SetDisplay("Fast period", "Fast EMA length for KAMA", "KAMA")
.SetOptimize(2, 10, 1);
_slow = Param(nameof(Slow), 50)
.SetGreaterThanZero()
.SetDisplay("Slow period", "Slow EMA length for KAMA", "KAMA")
.SetOptimize(20, 100, 10);
_risingPeriod = Param(nameof(RisingPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Rising period", "Bars for KAMA rising condition", "Strategy")
.SetOptimize(5, 20, 5);
_fallingPeriod = Param(nameof(FallingPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Falling period", "Bars for KAMA falling condition", "Strategy")
.SetOptimize(5, 20, 5);
_orderDirection = Param(nameof(OrderDirection), TradeSides.Long)
.SetDisplay("Order direction", "Allowed trade direction", "Strategy");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevKama = default;
_risingCount = 0;
_fallingCount = 0;
_isFirst = true;
_wasRising = false;
_wasFalling = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var kama = new KaufmanAdaptiveMovingAverage
{
Length = Length,
FastSCPeriod = Fast,
SlowSCPeriod = Slow
};
var subscription = SubscribeCandles(CandleType);
subscription.Bind(kama, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, kama);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal kamaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_isFirst)
{
_prevKama = kamaValue;
_isFirst = false;
return;
}
if (kamaValue > _prevKama)
{
_risingCount++;
_fallingCount = 0;
}
else if (kamaValue < _prevKama)
{
_fallingCount++;
_risingCount = 0;
}
else
{
_risingCount = 0;
_fallingCount = 0;
}
var isRising = _risingCount >= RisingPeriod;
var isFalling = _fallingCount >= FallingPeriod;
var risingEdge = isRising && !_wasRising;
var fallingEdge = isFalling && !_wasFalling;
if (risingEdge)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
var allowLong = OrderDirection == TradeSides.Long || OrderDirection == TradeSides.Both;
if (allowLong && Position == 0)
BuyMarket(Volume);
}
if (fallingEdge)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
var allowShort = OrderDirection == TradeSides.Short || OrderDirection == TradeSides.Both;
if (allowShort && Position == 0)
SellMarket(Volume);
}
_wasRising = isRising;
_wasFalling = isFalling;
_prevKama = kamaValue;
}
}
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 KaufmanAdaptiveMovingAverage
from StockSharp.Algo.Strategies import Strategy
class kaufman_adaptive_moving_average_strategy(Strategy):
def __init__(self):
super(kaufman_adaptive_moving_average_strategy, self).__init__()
self._length = self.Param("Length", 10) \
.SetGreaterThanZero() \
.SetDisplay("Length", "KAMA lookback period", "KAMA")
self._fast = self.Param("Fast", 5) \
.SetGreaterThanZero() \
.SetDisplay("Fast period", "Fast EMA length for KAMA", "KAMA")
self._slow = self.Param("Slow", 50) \
.SetGreaterThanZero() \
.SetDisplay("Slow period", "Slow EMA length for KAMA", "KAMA")
self._rising_period = self.Param("RisingPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Rising period", "Bars for KAMA rising condition", "Strategy")
self._falling_period = self.Param("FallingPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Falling period", "Bars for KAMA falling condition", "Strategy")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle type", "Type of candles", "General")
self._prev_kama = 0.0
self._rising_count = 0
self._falling_count = 0
self._is_first = True
self._was_rising = False
self._was_falling = False
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(kaufman_adaptive_moving_average_strategy, self).OnReseted()
self._prev_kama = 0.0
self._rising_count = 0
self._falling_count = 0
self._is_first = True
self._was_rising = False
self._was_falling = False
def OnStarted2(self, time):
super(kaufman_adaptive_moving_average_strategy, self).OnStarted2(time)
kama = KaufmanAdaptiveMovingAverage()
kama.Length = self._length.Value
kama.FastSCPeriod = self._fast.Value
kama.SlowSCPeriod = self._slow.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(kama, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, kama)
self.DrawOwnTrades(area)
def OnProcess(self, candle, kama_val):
if candle.State != CandleStates.Finished:
return
kv = float(kama_val)
if self._is_first:
self._prev_kama = kv
self._is_first = False
return
if kv > self._prev_kama:
self._rising_count += 1
self._falling_count = 0
elif kv < self._prev_kama:
self._falling_count += 1
self._rising_count = 0
else:
self._rising_count = 0
self._falling_count = 0
is_rising = self._rising_count >= self._rising_period.Value
is_falling = self._falling_count >= self._falling_period.Value
rising_edge = is_rising and not self._was_rising
falling_edge = is_falling and not self._was_falling
if rising_edge:
if self.Position < 0:
self.BuyMarket()
if self.Position == 0:
self.BuyMarket()
if falling_edge:
if self.Position > 0:
self.SellMarket()
if self.Position == 0:
self.SellMarket()
self._was_rising = is_rising
self._was_falling = is_falling
self._prev_kama = kv
def CreateClone(self):
return kaufman_adaptive_moving_average_strategy()