Стратегия Ichimoku by FarmerBTC
Стратегия открывает длинные позиции, когда цена выше облака Ichimoku, облако бычье, SMA старшего таймфрейма подтверждает тренд, а объём превышает свою скользящую среднюю, умноженную на коэффициент. Выход происходит при падении цены ниже облака.
Детали
- Условия входа: сигнал индикаторов
- Длинные/короткие: только лонг
- Условия выхода: противоположный сигнал
- Стопы: нет
- Значения по умолчанию:
TenkanPeriod= 10KijunPeriod= 30SenkouSpanBPeriod= 53SmaLength= 13VolumeLength= 20VolumeMultiplier= 1.5CandleType= 1 часHtfCandleType= 1 день
- Фильтры:
- Категория: Следование тренду
- Направление: Лонг
- Индикаторы: Ichimoku, SMA, объём
- Стопы: Нет
- Сложность: Средняя
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// Ichimoku by FarmerBTC strategy.
/// Long only. A long opens when the close is above the Ichimoku cloud, the cloud is bullish (Senkou A above Senkou B), the close is above
/// the SmaLength SMA of the higher timeframe and the candle volume exceeds its VolumeLength average multiplied by VolumeMultiplier.
/// The position closes when the close falls below the cloud. There are no stops.
/// </summary>
public class IchimokuByFarmerBtcStrategy : Strategy
{
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private readonly StrategyParam<int> _senkouSpanBPeriod;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<int> _volumeLength;
private readonly StrategyParam<decimal> _volumeMultiplier;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<DataType> _htfCandleType;
private SimpleMovingAverage _volumeSma;
private decimal? _htfSma;
/// <summary>
/// Tenkan-sen period.
/// </summary>
public int TenkanPeriod
{
get => _tenkanPeriod.Value;
set => _tenkanPeriod.Value = value;
}
/// <summary>
/// Kijun-sen period.
/// </summary>
public int KijunPeriod
{
get => _kijunPeriod.Value;
set => _kijunPeriod.Value = value;
}
/// <summary>
/// Senkou Span B period.
/// </summary>
public int SenkouSpanBPeriod
{
get => _senkouSpanBPeriod.Value;
set => _senkouSpanBPeriod.Value = value;
}
/// <summary>
/// Higher timeframe SMA period.
/// </summary>
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
/// <summary>
/// Volume moving average period.
/// </summary>
public int VolumeLength
{
get => _volumeLength.Value;
set => _volumeLength.Value = value;
}
/// <summary>
/// Factor applied to the volume average.
/// </summary>
public decimal VolumeMultiplier
{
get => _volumeMultiplier.Value;
set => _volumeMultiplier.Value = value;
}
/// <summary>
/// Working candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Higher timeframe candle type for the trend SMA.
/// </summary>
public DataType HtfCandleType
{
get => _htfCandleType.Value;
set => _htfCandleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IchimokuByFarmerBtcStrategy()
{
_tenkanPeriod = Param(nameof(TenkanPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Tenkan Period", "Tenkan-sen period", "Ichimoku");
_kijunPeriod = Param(nameof(KijunPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Kijun Period", "Kijun-sen period", "Ichimoku");
_senkouSpanBPeriod = Param(nameof(SenkouSpanBPeriod), 53)
.SetGreaterThanZero()
.SetDisplay("Senkou Span B Period", "Senkou Span B period", "Ichimoku");
_smaLength = Param(nameof(SmaLength), 13)
.SetGreaterThanZero()
.SetDisplay("SMA Length", "Higher timeframe SMA period", "Trend");
_volumeLength = Param(nameof(VolumeLength), 20)
.SetGreaterThanZero()
.SetDisplay("Volume Length", "Volume moving average period", "Volume");
_volumeMultiplier = Param(nameof(VolumeMultiplier), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Volume Multiplier", "Factor applied to the volume average", "Volume");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Working candle type", "General");
_htfCandleType = Param(nameof(HtfCandleType), TimeSpan.FromDays(1).TimeFrame())
.SetDisplay("HTF Candle Type", "Higher timeframe candle type for the trend SMA", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType), (Security, HtfCandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_volumeSma = null;
_htfSma = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_htfSma = null;
_volumeSma = new SimpleMovingAverage { Length = VolumeLength };
var ichimoku = new Ichimoku
{
Tenkan = { Length = TenkanPeriod },
Kijun = { Length = KijunPeriod },
SenkouB = { Length = SenkouSpanBPeriod },
};
var htfSma = new SimpleMovingAverage { Length = SmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ichimoku, ProcessCandle)
.Start();
SubscribeCandles(HtfCandleType)
.BindEx(htfSma, ProcessHtfCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ichimoku);
DrawOwnTrades(area);
}
}
private void ProcessHtfCandle(ICandleMessage candle, IIndicatorValue smaValue)
{
if (candle.State != CandleStates.Finished || !smaValue.IsFormed)
return;
_htfSma = smaValue.GetValue<decimal>();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue ichimokuValue)
{
if (candle.State != CandleStates.Finished)
return;
var volume = candle.TotalVolume;
var volumeValue = _volumeSma.Process(new DecimalIndicatorValue(_volumeSma, volume, candle.OpenTime) { IsFinal = true });
if (!_volumeSma.IsFormed || volumeValue.IsEmpty)
return;
var averageVolume = volumeValue.GetValue<decimal>();
if (!ichimokuValue.IsFormed || ichimokuValue is not IchimokuValue { SenkouA: decimal senkouA, SenkouB: decimal senkouB })
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var cloudTop = Math.Max(senkouA, senkouB);
var cloudBottom = Math.Min(senkouA, senkouB);
if (Position > 0)
{
if (close < cloudBottom)
SellMarket(Position);
return;
}
if (_htfSma is not decimal trendSma)
return;
if (close > cloudTop && senkouA > senkouB && close > trendSma && volume > averageVolume * VolumeMultiplier)
BuyMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Ichimoku, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class ichimoku_by_farmer_btc_strategy(Strategy):
"""
Ichimoku by FarmerBTC strategy.
Long only. A long opens when the close is above the Ichimoku cloud, the cloud is bullish (Senkou A above Senkou B), the close is above
the SmaLength SMA of the higher timeframe and the candle volume exceeds its VolumeLength average multiplied by VolumeMultiplier.
The position closes when the close falls below the cloud. There are no stops.
"""
def __init__(self):
super(ichimoku_by_farmer_btc_strategy, self).__init__()
self._tenkan_period = self.Param("TenkanPeriod", 10).SetGreaterThanZero().SetDisplay("Tenkan Period", "Tenkan-sen period", "Ichimoku")
self._kijun_period = self.Param("KijunPeriod", 30).SetGreaterThanZero().SetDisplay("Kijun Period", "Kijun-sen period", "Ichimoku")
self._senkou_span_b_period = self.Param("SenkouSpanBPeriod", 53).SetGreaterThanZero().SetDisplay("Senkou Span B Period", "Senkou Span B period", "Ichimoku")
self._sma_length = self.Param("SmaLength", 13).SetGreaterThanZero().SetDisplay("SMA Length", "Higher timeframe SMA period", "Trend")
self._volume_length = self.Param("VolumeLength", 20).SetGreaterThanZero().SetDisplay("Volume Length", "Volume moving average period", "Volume")
self._volume_multiplier = self.Param("VolumeMultiplier", 1.5).SetGreaterThanZero().SetDisplay("Volume Multiplier", "Factor applied to the volume average", "Volume")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Working candle type", "General")
self._htf_candle_type = self.Param("HtfCandleType", DataType.TimeFrame(TimeSpan.FromDays(1))).SetDisplay("HTF Candle Type", "Higher timeframe candle type for the trend SMA", "General")
self._volume_sma = None
self._htf_sma = None
@property
def candle_type(self):
return self._candle_type.Value
@property
def htf_candle_type(self):
return self._htf_candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.candle_type), (self.Security, self.htf_candle_type)]
def OnReseted(self):
super(ichimoku_by_farmer_btc_strategy, self).OnReseted()
self._volume_sma = None
self._htf_sma = None
def OnStarted2(self, time):
super(ichimoku_by_farmer_btc_strategy, self).OnStarted2(time)
self._htf_sma = None
self._volume_sma = SimpleMovingAverage()
self._volume_sma.Length = self._volume_length.Value
ichimoku = Ichimoku()
ichimoku.Tenkan.Length = self._tenkan_period.Value
ichimoku.Kijun.Length = self._kijun_period.Value
ichimoku.SenkouB.Length = self._senkou_span_b_period.Value
htf_sma = SimpleMovingAverage()
htf_sma.Length = self._sma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ichimoku, self._process_candle).Start()
self.SubscribeCandles(self.htf_candle_type).BindEx(htf_sma, self._process_htf_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ichimoku)
self.DrawOwnTrades(area)
def _process_htf_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished or not sma_value.IsFormed:
return
self._htf_sma = sma_value.GetValue[Decimal](None)
def _process_candle(self, candle, ichimoku_value):
if candle.State != CandleStates.Finished:
return
volume = candle.TotalVolume
volume_value = process_value(self._volume_sma, volume, candle.OpenTime, True)
if not self._volume_sma.IsFormed or volume_value.IsEmpty:
return
average_volume = to_decimal(volume_value)
if not ichimoku_value.IsFormed or ichimoku_value.SenkouA is None or ichimoku_value.SenkouB is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
senkou_a = ichimoku_value.SenkouA
senkou_b = ichimoku_value.SenkouB
cloud_top = max(senkou_a, senkou_b)
cloud_bottom = min(senkou_a, senkou_b)
if self.Position > 0:
if close < cloud_bottom:
self.SellMarket(self.Position)
return
if self._htf_sma is None:
return
if close > cloud_top and senkou_a > senkou_b and close > self._htf_sma and volume > average_volume * Decimal(self._volume_multiplier.Value):
self.BuyMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return ichimoku_by_farmer_btc_strategy()