トリプルMA
トリプル移動平均クロスオーバーに基づく戦略。
テスト結果では、年間平均リターンが約55%であることが示されています。株式市場で最も効果を発揮します。
トリプルMAは3つの移動平均を並べて方向を定義します。最も短い平均が中期および長期の平均を上回ると、ロングエントリーが発生します。逆の並びはショートを開き、短期線と中期線のクロスで取引が終了します。
3つの平均を使用することで、単一MAシステムに存在するノイズを除去するのに役立ちます。この多層的なアプローチは、取引にコミットする前にモメンタムを確認しようとします。
詳細
- エントリー条件: MAに基づくシグナル。
- ロング/ショート: 両方の方向。
- エグジット条件: 逆シグナルまたはストップ。
- ストップ: はい。
- デフォルト値:
ShortMaPeriod= 5MiddleMaPeriod= 20LongMaPeriod= 50StopLossPercent= 2mCandleType= TimeSpan.FromMinutes(5)
- フィルター:
- カテゴリ: トレンド
- 方向: 両方
- インジケーター: MA
- ストップ: はい
- 複雑さ: 基本
- 時間軸: イントラデイ (5m)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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;
/// <summary>
/// Strategy based on Triple Moving Average crossover.
/// It enters long when the short MA is above both the middle and the long MA, and short when it is below both.
/// A cross of the short and the middle MA closes the position, and a percent stop protects it.
/// </summary>
public class TripleMAStrategy : Strategy
{
private readonly StrategyParam<int> _shortMaPeriod;
private readonly StrategyParam<int> _middleMaPeriod;
private readonly StrategyParam<int> _longMaPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
// Current state
/// <summary>
/// Period for short moving average.
/// </summary>
public int ShortMaPeriod
{
get => _shortMaPeriod.Value;
set => _shortMaPeriod.Value = value;
}
/// <summary>
/// Period for middle moving average.
/// </summary>
public int MiddleMaPeriod
{
get => _middleMaPeriod.Value;
set => _middleMaPeriod.Value = value;
}
/// <summary>
/// Period for long moving average.
/// </summary>
public int LongMaPeriod
{
get => _longMaPeriod.Value;
set => _longMaPeriod.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Triple MA strategy.
/// </summary>
public TripleMAStrategy()
{
_shortMaPeriod = Param(nameof(ShortMaPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Short MA Period", "Period for short moving average", "Indicators")
.SetOptimize(3, 10, 1);
_middleMaPeriod = Param(nameof(MiddleMaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Middle MA Period", "Period for middle moving average", "Indicators")
.SetOptimize(15, 30, 5);
_longMaPeriod = Param(nameof(LongMaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Long MA Period", "Period for long moving average", "Indicators")
.SetOptimize(40, 100, 10);
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss (%)", "Stop loss as a percentage of entry price", "Risk parameters")
.SetOptimize(1, 3, 0.5m);
_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();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var shortMa = new ExponentialMovingAverage { Length = ShortMaPeriod };
var middleMa = new ExponentialMovingAverage { Length = MiddleMaPeriod };
var longMa = new ExponentialMovingAverage { Length = LongMaPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(shortMa, middleMa, longMa, ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, shortMa);
DrawIndicator(area, middleMa);
DrawIndicator(area, longMa);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle, decimal shortMaValue, decimal middleMaValue, decimal longMaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var longSetup = shortMaValue > middleMaValue && shortMaValue > longMaValue;
var shortSetup = shortMaValue < middleMaValue && shortMaValue < longMaValue;
if (Position > 0)
{
// The short MA has crossed below the middle one.
if (shortMaValue < middleMaValue)
SellMarket(shortSetup ? Volume + Position : Position);
}
else if (Position < 0)
{
if (shortMaValue > middleMaValue)
BuyMarket(longSetup ? Volume - Position : -Position);
}
else if (longSetup)
{
BuyMarket(Volume);
}
else if (shortSetup)
{
SellMarket(Volume);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class triple_ma_strategy(Strategy):
"""
Strategy based on Triple Moving Average crossover.
Enters long when the short MA is above both the middle and the long MA, and short when it is below both.
A cross of the short and the middle MA closes the position, and a percent stop protects it.
"""
def __init__(self):
super(triple_ma_strategy, self).__init__()
self._short_ma_period = self.Param("ShortMaPeriod", 5).SetGreaterThanZero().SetDisplay("Short MA Period", "Period for short moving average", "Indicators")
self._middle_ma_period = self.Param("MiddleMaPeriod", 20).SetGreaterThanZero().SetDisplay("Middle MA Period", "Period for middle moving average", "Indicators")
self._long_ma_period = self.Param("LongMaPeriod", 50).SetGreaterThanZero().SetDisplay("Long MA Period", "Period for long moving average", "Indicators")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss (%)", "Stop loss as a percentage of entry price", "Risk parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(triple_ma_strategy, self).OnReseted()
def OnStarted2(self, time):
super(triple_ma_strategy, self).OnStarted2(time)
short_ma = ExponentialMovingAverage()
short_ma.Length = self._short_ma_period.Value
middle_ma = ExponentialMovingAverage()
middle_ma.Length = self._middle_ma_period.Value
long_ma = ExponentialMovingAverage()
long_ma.Length = self._long_ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(short_ma, middle_ma, long_ma, self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, short_ma)
self.DrawIndicator(area, middle_ma)
self.DrawIndicator(area, long_ma)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle, short_val, middle_val, long_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
long_setup = short_val > middle_val and short_val > long_val
short_setup = short_val < middle_val and short_val < long_val
position = self.Position
if position > 0:
# The short MA has crossed below the middle one.
if short_val < middle_val:
self.SellMarket(self.Volume + position if short_setup else position)
elif position < 0:
if short_val > middle_val:
self.BuyMarket(self.Volume - position if long_setup else -position)
elif long_setup:
self.BuyMarket(self.Volume)
elif short_setup:
self.SellMarket(self.Volume)
def CreateClone(self):
return triple_ma_strategy()