平均回帰プロ戦略
Mean Reversion Proは主要指数向けに構築された平均回帰システムです。2本の移動平均とイントラバーのレンジレベルを使用してプルバックを検出します。指数は上昇傾向にあるため、ロング取引が優先されます。
詳細
- エントリー条件:
- ロング: 終値が高速SMA以下、終値がレンジの20%水準以下、終値が低速SMA以上、ポジションなし。
- ショート: 終値が高速SMA以上、終値がレンジの80%水準以上、終値が低速SMA以下、ポジションなし。
- ロング/ショート: 両方(ロング推奨)。
- エグジット条件:
- ロング: 終値が高速SMAを上抜け。
- ショート: 終値が高速SMAを下抜け。
- ストップ: なし。
- デフォルト値:
Fast SMA= 5Slow SMA= 100Direction= ロングのみ
- フィルター:
- カテゴリ: 平均回帰
- 方向: 設定可能
- インジケーター: 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>
/// Mean Reversion Pro strategy.
/// When flat, a long opens on a close below the fast SMA, inside the lowest 20% of the candle range and above the slow SMA;
/// a short opens on a close above the fast SMA, inside the highest 20% of the range (above the 80% level) and below the slow SMA.
/// A long closes when the close crosses above the fast SMA and a short when it crosses below. Direction selects
/// "Long only", "Short only" or "Both".
/// </summary>
public class MeanReversionProStrategy : Strategy
{
private const string LongOnlyValue = "Long only";
private const string ShortOnlyValue = "Short only";
private readonly StrategyParam<int> _fastSma;
private readonly StrategyParam<int> _slowSma;
private readonly StrategyParam<string> _direction;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevClose;
private decimal? _prevFast;
/// <summary>
/// Fast SMA length.
/// </summary>
public int FastSma
{
get => _fastSma.Value;
set => _fastSma.Value = value;
}
/// <summary>
/// Slow SMA length.
/// </summary>
public int SlowSma
{
get => _slowSma.Value;
set => _slowSma.Value = value;
}
/// <summary>
/// Allowed trade direction: "Long only", "Short only" or "Both".
/// </summary>
public string Direction
{
get => _direction.Value;
set => _direction.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public MeanReversionProStrategy()
{
_fastSma = Param(nameof(FastSma), 5)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA length", "Indicators");
_slowSma = Param(nameof(SlowSma), 100)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA length", "Indicators");
_direction = Param(nameof(Direction), LongOnlyValue)
.SetDisplay("Direction", "Allowed trade direction: Long only, Short only or Both", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
_prevFast = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevFast = null;
var fast = new SimpleMovingAverage { Length = FastSma };
var slow = new SimpleMovingAverage { Length = SlowSma };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue fastValue, IIndicatorValue slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!fastValue.IsFormed || !slowValue.IsFormed)
return;
var fast = fastValue.GetValue<decimal>();
var slow = slowValue.GetValue<decimal>();
var close = candle.ClosePrice;
var prevClose = _prevClose;
var prevFast = _prevFast;
_prevClose = close;
_prevFast = fast;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var crossedUp = prevClose is decimal pc1 && prevFast is decimal pf1 && pc1 <= pf1 && close > fast;
var crossedDown = prevClose is decimal pc2 && prevFast is decimal pf2 && pc2 >= pf2 && close < fast;
if (Position > 0)
{
if (crossedUp)
SellMarket(Position);
return;
}
if (Position < 0)
{
if (crossedDown)
BuyMarket(-Position);
return;
}
var range = candle.HighPrice - candle.LowPrice;
var lowLevel = candle.LowPrice + 0.2m * range;
var highLevel = candle.LowPrice + 0.8m * range;
var allowLong = !Direction.EqualsIgnoreCase(ShortOnlyValue);
var allowShort = !Direction.EqualsIgnoreCase(LongOnlyValue);
if (allowLong && close < fast && close < lowLevel && close > slow)
BuyMarket(Volume);
else if (allowShort && close > fast && close > highLevel && close < slow)
SellMarket(Volume);
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
LONG_ONLY = "long only"
SHORT_ONLY = "short only"
class mean_reversion_pro_strategy(Strategy):
"""
Mean Reversion Pro strategy.
When flat, a long opens on a close below the fast SMA, inside the lowest 20% of the candle range and above the slow SMA;
a short opens on a close above the fast SMA, inside the highest 20% of the range (above the 80% level) and below the slow SMA.
A long closes when the close crosses above the fast SMA and a short when it crosses below. Direction selects
"Long only", "Short only" or "Both".
"""
def __init__(self):
super(mean_reversion_pro_strategy, self).__init__()
self._fast_sma = self.Param("FastSma", 5).SetGreaterThanZero().SetDisplay("Fast SMA", "Fast SMA length", "Indicators")
self._slow_sma = self.Param("SlowSma", 100).SetGreaterThanZero().SetDisplay("Slow SMA", "Slow SMA length", "Indicators")
self._direction = self.Param("Direction", "Long only").SetDisplay("Direction", "Allowed trade direction: Long only, Short only or Both", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_close = None
self._prev_fast = None
def OnReseted(self):
super(mean_reversion_pro_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(mean_reversion_pro_strategy, self).OnStarted2(time)
self._reset_state()
fast = SimpleMovingAverage()
fast.Length = self._fast_sma.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_sma.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(fast, slow, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not fast_value.IsFormed or not slow_value.IsFormed:
return
fast = fast_value.GetValue[Decimal](None)
slow = slow_value.GetValue[Decimal](None)
close = candle.ClosePrice
prev_close = self._prev_close
prev_fast = self._prev_fast
self._prev_close = close
self._prev_fast = fast
if not self.IsFormedAndOnlineAndAllowTrading():
return
has_prev = prev_close is not None and prev_fast is not None
crossed_up = has_prev and prev_close <= prev_fast and close > fast
crossed_down = has_prev and prev_close >= prev_fast and close < fast
if self.Position > 0:
if crossed_up:
self.SellMarket(self.Position)
return
if self.Position < 0:
if crossed_down:
self.BuyMarket(-self.Position)
return
range_ = candle.HighPrice - candle.LowPrice
low_level = candle.LowPrice + Decimal(0.2) * range_
high_level = candle.LowPrice + Decimal(0.8) * range_
direction = (self._direction.Value or "").strip().lower()
allow_long = direction != SHORT_ONLY
allow_short = direction != LONG_ONLY
if allow_long and close < fast and close < low_level and close > slow:
self.BuyMarket(self.Volume)
elif allow_short and close > fast and close > high_level and close < slow:
self.SellMarket(self.Volume)
def CreateClone(self):
return mean_reversion_pro_strategy()