Turtle Trader V1 combines multiple momentum oscillators with a moving average filter. A long position is opened when the fast EMA is above the slow EMA and RSI, Stochastic, CCI, Momentum and Chaikin oscillator all point upward. Shorts require the opposite conditions.
Details
Entry Criteria:
Fast EMA above slow EMA (below for shorts)
RSI rising and below 70 for longs, RSI falling and above 30 for shorts
Stochastic %K below 88 for longs, above 12 for shorts
CCI and Momentum increasing for longs, decreasing for shorts
Chaikin oscillator moving in trade direction
Long/Short: Both
Exit Criteria: opposite signal
Stops: none by default
Default Values:
FastMaPeriod = 10
SlowMaPeriod = 50
RsiPeriod = 14
StochPeriod = 14
CciPeriod = 20
MomentumPeriod = 10
ChoFastPeriod = 3
ChoSlowPeriod = 10
Filters:
Category: Trend Following / Momentum
Direction: Both
Indicators: EMA, RSI, Stochastic, CCI, Momentum, Chaikin Oscillator
Stops: None
Complexity: Advanced
Timeframe: 1 hour
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Medium
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>
/// Turtle Trader strategy based on EMA crossover with RSI confirmation.
/// </summary>
public class TurtleTraderV1Strategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TurtleTraderV1Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast EMA period", "General");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow EMA period", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "Data");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}