Phase Cross Strategy with Zone
Стратегия покупает, когда сглаженная SMA с положительным смещением пересекает снизу EMA с отрицательным смещением, и закрывает позицию при обратном пересечении.
Детали
- Условия входа: SMA + смещение пересекает снизу EMA - смещение.
- Позиция: только длинная.
- Условия выхода: обратное пересечение.
- Стопы: отсутствуют.
- Значения по умолчанию:
Length= 20.Offset= 0.5.
- Фильтры: нет.
- Сложность: низкая.
- Таймфрейм: настраиваемый.
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;
public class PhaseCrossWithZoneStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _offset;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevLead;
private decimal _prevLag;
private bool _prevInit;
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
public decimal Offset
{
get => _offset.Value;
set => _offset.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public PhaseCrossWithZoneStrategy()
{
_length = Param(nameof(Length), 20)
.SetGreaterThanZero()
.SetDisplay("Length", "Smoothing length", "General")
.SetOptimize(5, 50, 1);
_offset = Param(nameof(Offset), 0.5m)
.SetDisplay("Offset", "Phase offset", "General")
.SetOptimize(0m, 1m, 0.1m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_prevLead = 0;
_prevLag = 0;
_prevInit = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = Length };
var ema = new ExponentialMovingAverage { Length = Length * 2 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var lead = smaValue + Offset;
var lag = emaValue - Offset;
if (_prevInit)
{
var crossedUp = _prevLead <= _prevLag && lead > lag;
var crossedDown = _prevLead >= _prevLag && lead < lag;
if (crossedUp && Position <= 0)
BuyMarket();
else if (crossedDown && Position >= 0)
SellMarket();
}
_prevLead = lead;
_prevLag = lag;
_prevInit = true;
}
}
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 SimpleMovingAverage, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class phase_cross_with_zone_strategy(Strategy):
def __init__(self):
super(phase_cross_with_zone_strategy, self).__init__()
self._length = self.Param("Length", 20).SetGreaterThanZero().SetDisplay("Length", "Smoothing length", "General")
self._offset = self.Param("Offset", 0.5).SetDisplay("Offset", "Phase offset", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(phase_cross_with_zone_strategy, self).OnReseted()
self._prev_lead = 0
self._prev_lag = 0
self._prev_init = False
def OnStarted2(self, time):
super(phase_cross_with_zone_strategy, self).OnStarted2(time)
self._prev_lead = 0
self._prev_lag = 0
self._prev_init = False
sma = SimpleMovingAverage()
sma.Length = self._length.Value
ema = ExponentialMovingAverage()
ema.Length = self._length.Value * 2
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sma, ema, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sma)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sma_val, ema_val):
if candle.State != CandleStates.Finished:
return
lead = sma_val + self._offset.Value
lag = ema_val - self._offset.Value
if self._prev_init:
crossed_up = self._prev_lead <= self._prev_lag and lead > lag
crossed_down = self._prev_lead >= self._prev_lag and lead < lag
if crossed_up and self.Position <= 0:
self.BuyMarket()
elif crossed_down and self.Position >= 0:
self.SellMarket()
self._prev_lead = lead
self._prev_lag = lag
self._prev_init = True
def CreateClone(self):
return phase_cross_with_zone_strategy()