TMAブレイクアウト戦略
この戦略は、三角移動平均(TMA)に対するブレイクアウトを活用します。設定可能なローソク足シリーズを監視し、前のローソク足の終値をTMA値にユーザー定義のオフセットを加減した値と比較します。前の終値がTMA + UpLevelを上回るとロングポジションを建て、TMA - DownLevelを下回るとショートポジションを建てます。逆のシグナルはポジションを反転させます。
パラメーター
- TMA Length – 三角移動平均の計算に使用する期間。
- Upper Level – ロングシグナルを検出するためにTMAに加算する価格オフセット。
- Lower Level – ショートシグナルを検出するためにTMAから減算する価格オフセット。
- Candle Type – 戦略が使用するローソク足の時間軸。
動作の仕組み
- 選択したローソク足シリーズをサブスクライブします。
- 三角移動平均インジケーターをローソク足にバインドします。
- 各ローソク足の完成時に:
- TMAと終値の前回値を保存します。
- 前の終値が上限または下限を超えたかどうかを確認します。
- 状況に応じてポジションを建てまたは反転させる成行注文を送信します。
- ビジュアル分析のためにローソク足、インジケーターライン、自己取引をチャートに描画します。
注意事項
この戦略はストップロスやテイクプロフィットの管理なしに成行注文を使用します。教育目的を意図しており、実取引の前に適切なリスク管理を追加して拡張する必要があります。
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 that enters when price breaks the Triangular Moving Average by configurable offsets.
/// </summary>
public class TmaBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _upLevel;
private readonly StrategyParam<decimal> _downLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevTma;
private decimal? _prevClose;
/// <summary>
/// Period for the Triangular Moving Average.
/// </summary>
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
/// <summary>
/// Offset above the TMA to trigger a long entry.
/// </summary>
public decimal UpLevel
{
get => _upLevel.Value;
set => _upLevel.Value = value;
}
/// <summary>
/// Offset below the TMA to trigger a short entry.
/// </summary>
public decimal DownLevel
{
get => _downLevel.Value;
set => _downLevel.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the TMA breakout strategy.
/// </summary>
public TmaBreakoutStrategy()
{
_length = Param(nameof(Length), 30)
.SetDisplay("TMA Length", "Period for the Triangular Moving Average", "Parameters")
.SetOptimize(10, 60, 10);
_upLevel = Param(nameof(UpLevel), 300m)
.SetDisplay("Upper Level", "Offset above TMA in price units", "Parameters")
.SetOptimize(100m, 500m, 100m);
_downLevel = Param(nameof(DownLevel), 300m)
.SetDisplay("Lower Level", "Offset below TMA in price units", "Parameters")
.SetOptimize(100m, 500m, 100m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_prevTma = _prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var tma = new ExponentialMovingAverage { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(tma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, tma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal tmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var prevTma = _prevTma;
var prevClose = _prevClose;
if (prevTma is null || prevClose is null)
{
_prevTma = tmaValue;
_prevClose = candle.ClosePrice;
return;
}
var signalUp = prevClose > prevTma + UpLevel;
var signalDn = prevClose < prevTma - DownLevel;
if (signalUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (signalDn && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevTma = tmaValue;
_prevClose = candle.ClosePrice;
}
}
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
class tma_breakout_strategy(Strategy):
def __init__(self):
super(tma_breakout_strategy, self).__init__()
self._length = self.Param("Length", 30) \
.SetDisplay("TMA Length", "Period for the Triangular Moving Average", "Parameters")
self._up_level = self.Param("UpLevel", 300.0) \
.SetDisplay("Upper Level", "Offset above TMA in price units", "Parameters")
self._down_level = self.Param("DownLevel", 300.0) \
.SetDisplay("Lower Level", "Offset below TMA in price units", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_tma = None
self._prev_close = None
@property
def length(self):
return self._length.Value
@property
def up_level(self):
return self._up_level.Value
@property
def down_level(self):
return self._down_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(tma_breakout_strategy, self).OnReseted()
self._prev_tma = None
self._prev_close = None
def OnStarted2(self, time):
super(tma_breakout_strategy, self).OnStarted2(time)
tma = ExponentialMovingAverage()
tma.Length = self.length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(tma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, tma)
self.DrawOwnTrades(area)
def process_candle(self, candle, tma_value):
if candle.State != CandleStates.Finished:
return
tma_val = float(tma_value)
close = float(candle.ClosePrice)
if self._prev_tma is None or self._prev_close is None:
self._prev_tma = tma_val
self._prev_close = close
return
signal_up = self._prev_close > self._prev_tma + float(self.up_level)
signal_dn = self._prev_close < self._prev_tma - float(self.down_level)
if signal_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif signal_dn and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_tma = tma_val
self._prev_close = close
def CreateClone(self):
return tma_breakout_strategy()