Стратегия Javo v1
Javo v1 сочетает свечи Heikin Ashi с двумя экспоненциальными средними. Позиция открывается, когда направление HA и пересечение быстрого и медленного EMA совпадают. Подход пытается уловить зарождающийся тренд, сглаживая шум.
Детали
- Критерии входа:
- Длинная позиция: HA бычья и
EMA_fast > EMA_slow - Короткая позиция: HA медвежья и
EMA_fast < EMA_slow
- Длинная позиция: HA бычья и
- Длинные/короткие: обе стороны
- Критерии выхода: Противоположный сигнал
- Стопы: нет
- Значения по умолчанию:
FastEmaPeriod= 1SlowEmaPeriod= 30
- Фильтры:
- Категория: Следование тренду
- Направление: Оба
- Индикаторы: Heikin Ashi, EMA
- Стопы: Нет
- Сложность: Низкая
- Таймфрейм: Почасовой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// Javo v1 strategy.
/// Builds Heikin Ashi candles and runs a fast and a slow EMA on the Heikin Ashi close. Goes long when the Heikin Ashi
/// candle is bullish and the fast EMA is above the slow one, short when the candle is bearish and the fast EMA is below
/// the slow one. The opposite signal reverses the position.
/// </summary>
public class JavoV1Strategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private decimal? _prevHaOpen;
private decimal? _prevHaClose;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public JavoV1Strategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 1)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period on the Heikin Ashi close", "Moving Averages");
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period on the Heikin Ashi close", "Moving Averages");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastEma = null;
_slowEma = null;
_prevHaOpen = null;
_prevHaClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHaOpen = null;
_prevHaClose = null;
_fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
_slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEma);
DrawIndicator(area, _slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
var haOpen = _prevHaOpen is decimal prevOpen && _prevHaClose is decimal prevClose
? (prevOpen + prevClose) / 2m
: (candle.OpenPrice + candle.ClosePrice) / 2m;
_prevHaOpen = haOpen;
_prevHaClose = haClose;
var fast = _fastEma.Process(haClose, candle.ServerTime, true).ToDecimal();
var slow = _slowEma.Process(haClose, candle.ServerTime, true).ToDecimal();
if (!_fastEma.IsFormed || !_slowEma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (haClose > haOpen && fast > slow && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (haClose < haOpen && fast < slow && Position >= 0)
SellMarket(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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class javo_v1_strategy(Strategy):
"""
Javo v1 strategy.
Builds Heikin Ashi candles and runs a fast and a slow EMA on the Heikin Ashi close. Goes long when the Heikin Ashi
candle is bullish and the fast EMA is above the slow one, short when the candle is bearish and the fast EMA is below
the slow one. The opposite signal reverses the position.
"""
def __init__(self):
super(javo_v1_strategy, self).__init__()
self._fast_ema_period = self.Param("FastEmaPeriod", 1) \
.SetGreaterThanZero() \
.SetDisplay("Fast EMA", "Fast EMA period on the Heikin Ashi close", "Moving Averages")
self._slow_ema_period = self.Param("SlowEmaPeriod", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow EMA", "Slow EMA period on the Heikin Ashi close", "Moving Averages")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle type", "Candle type for strategy calculation", "General")
self._fast_ema = None
self._slow_ema = None
self._prev_ha_open = None
self._prev_ha_close = None
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(javo_v1_strategy, self).OnReseted()
self._fast_ema = None
self._slow_ema = None
self._prev_ha_open = None
self._prev_ha_close = None
def OnStarted2(self, time):
super(javo_v1_strategy, self).OnStarted2(time)
self._prev_ha_open = None
self._prev_ha_close = None
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self._fast_ema_period.Value
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self._slow_ema_period.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ema)
self.DrawIndicator(area, self._slow_ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_price = float(candle.OpenPrice)
close = float(candle.ClosePrice)
ha_close = (open_price + float(candle.HighPrice) + float(candle.LowPrice) + close) / 4.0
if self._prev_ha_open is not None and self._prev_ha_close is not None:
ha_open = (self._prev_ha_open + self._prev_ha_close) / 2.0
else:
ha_open = (open_price + close) / 2.0
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
fast = float(to_decimal(process_float(self._fast_ema, ha_close, candle.ServerTime, True)))
slow = float(to_decimal(process_float(self._slow_ema, ha_close, candle.ServerTime, True)))
if not self._fast_ema.IsFormed or not self._slow_ema.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if ha_close > ha_open and fast > slow and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif ha_close < ha_open and fast < slow and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return javo_v1_strategy()