トレンドラインアラート戦略
この戦略はユーザー定義の2本のトレンドラインを監視し、価格がそれらを突破したときに反応します。上限ラインと下限ラインは抵抗と支持のレベルを表します。終値が上限ラインを上方クロスするとロングポジションが開かれます。価格が下限ラインを下回るとショートポジションが開かれます。オプションのトレーリングストップロジックはトレードの方向にストップレベルを移動することで開いたポジションを保護します。
パラメーター
Breakout Points– ブレイクアウト閾値を定義するためにトレンドラインレベルに追加される追加ポイント。Upper Line– 強気ブレイクアウトの価格レベル。Lower Line– 弱気ブレイクアウトの価格レベル。Start Hour– 取引開始時間(時間単位)。End Hour– 取引終了時間(時間単位)。Use Trailing Stop– トレーリングストップ管理を有効にする。Trailing Stop Points– トレーリングストップのポイント距離。Candle Type– 分析に使用するローソク足の時間軸。
動作方法
- 戦略は選択されたローソク足シリーズに登録します。
- 各確定ローソク足について、時間が指定された取引ウィンドウ内にあることを確認します。
- ローソク足の終値がブレイクアウトポイント閾値で調整された上限ラインを上回るか下限ラインを下回るとブレイクアウトが検出されます。
- ブレイクアウトが発生し既存ポジションがない場合、ブレイクアウト方向に成行注文が送信されます。
- トレーリングストップが有効な場合、ストップレベルはトリガーされるまで価格に追従します。
注意事項
- この戦略はMetaTraderのオリジナルTrendlineAlertエキスパートアドバイザーの簡略化された変換です。トレンドラインの手動描画はパラメーターで定義された固定価格レベルに置き換えられています。
- 指定された取引時間外には注文は行われません。
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 reacts to price breakouts above or below predefined trendlines.
/// </summary>
public class TrendlineAlertStrategy : Strategy
{
private readonly StrategyParam<int> _breakoutPoints;
private readonly StrategyParam<int> _startHour;
private readonly StrategyParam<int> _endHour;
private readonly StrategyParam<bool> _useTrailingStop;
private readonly StrategyParam<int> _trailingStopPoints;
private readonly StrategyParam<decimal> _upperLine;
private readonly StrategyParam<decimal> _lowerLine;
private readonly StrategyParam<DataType> _candleType;
private decimal _lastPrice;
private decimal _stopPrice;
private bool _upAlerted;
private bool _downAlerted;
/// <summary>
/// Breakout threshold in points.
/// </summary>
public int BreakoutPoints { get => _breakoutPoints.Value; set => _breakoutPoints.Value = value; }
/// <summary>
/// Trading start hour (0-23).
/// </summary>
public int StartHour { get => _startHour.Value; set => _startHour.Value = value; }
/// <summary>
/// Trading end hour (0-24).
/// </summary>
public int EndHour { get => _endHour.Value; set => _endHour.Value = value; }
/// <summary>
/// Enable trailing stop logic.
/// </summary>
public bool UseTrailingStop { get => _useTrailingStop.Value; set => _useTrailingStop.Value = value; }
/// <summary>
/// Trailing stop distance in points.
/// </summary>
public int TrailingStopPoints { get => _trailingStopPoints.Value; set => _trailingStopPoints.Value = value; }
/// <summary>
/// Price level of the upper trendline.
/// </summary>
public decimal UpperLine { get => _upperLine.Value; set => _upperLine.Value = value; }
/// <summary>
/// Price level of the lower trendline.
/// </summary>
public decimal LowerLine { get => _lowerLine.Value; set => _lowerLine.Value = value; }
/// <summary>
/// Type of candles to subscribe.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initialize <see cref="TrendlineAlertStrategy"/>.
/// </summary>
public TrendlineAlertStrategy()
{
_breakoutPoints = Param(nameof(BreakoutPoints), 0)
.SetDisplay("Breakout Points", "Additional points for breakout", "General");
_startHour = Param(nameof(StartHour), 0)
.SetDisplay("Start Hour", "Strategy start hour", "General");
_endHour = Param(nameof(EndHour), 24)
.SetDisplay("End Hour", "Strategy end hour", "General");
_useTrailingStop = Param(nameof(UseTrailingStop), false)
.SetDisplay("Use Trailing Stop", "Enable trailing stop", "Protection");
_trailingStopPoints = Param(nameof(TrailingStopPoints), 5)
.SetDisplay("Trailing Stop Points", "Trailing stop distance", "Protection");
_upperLine = Param(nameof(UpperLine), 68000m)
.SetDisplay("Upper Line", "Upper trendline level", "Levels");
_lowerLine = Param(nameof(LowerLine), 62000m)
.SetDisplay("Lower Line", "Lower trendline level", "Levels");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastPrice = 0;
_stopPrice = 0;
_upAlerted = false;
_downAlerted = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
new Unit(2, UnitTypes.Percent),
new Unit(2, UnitTypes.Percent));
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var hour = candle.OpenTime.Hour;
if (hour < StartHour || hour >= EndHour)
return;
var step = Security.PriceStep ?? 1m;
var threshold = BreakoutPoints * step;
var upper = UpperLine + threshold;
var lower = LowerLine - threshold;
var price = candle.ClosePrice;
if (!_upAlerted && price > upper && _lastPrice <= upper)
{
_upAlerted = true;
if (Position <= 0)
BuyMarket();
}
else if (!_downAlerted && price < lower && _lastPrice >= lower)
{
_downAlerted = true;
if (Position >= 0)
SellMarket();
}
if (UseTrailingStop)
UpdateTrailingStop(candle);
_lastPrice = price;
}
private void UpdateTrailingStop(ICandleMessage candle)
{
var step = Security.PriceStep ?? 1m;
var trail = TrailingStopPoints * step;
if (Position > 0)
{
_stopPrice = Math.Max(_stopPrice, candle.ClosePrice - trail);
if (candle.LowPrice <= _stopPrice)
SellMarket();
}
else if (Position < 0)
{
_stopPrice = Math.Min(_stopPrice, candle.ClosePrice + trail);
if (candle.HighPrice >= _stopPrice)
BuyMarket();
}
else
{
_stopPrice = 0;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, Unit, UnitTypes, CandleStates
from StockSharp.Algo.Strategies import Strategy
class trendline_alert_strategy(Strategy):
def __init__(self):
super(trendline_alert_strategy, self).__init__()
self._breakout_points = self.Param("BreakoutPoints", 0) \
.SetDisplay("Breakout Points", "Additional points for breakout", "General")
self._start_hour = self.Param("StartHour", 0) \
.SetDisplay("Start Hour", "Strategy start hour", "General")
self._end_hour = self.Param("EndHour", 24) \
.SetDisplay("End Hour", "Strategy end hour", "General")
self._use_trailing_stop = self.Param("UseTrailingStop", False) \
.SetDisplay("Use Trailing Stop", "Enable trailing stop", "Protection")
self._trailing_stop_points = self.Param("TrailingStopPoints", 5) \
.SetDisplay("Trailing Stop Points", "Trailing stop distance", "Protection")
self._upper_line = self.Param("UpperLine", 68000.0) \
.SetDisplay("Upper Line", "Upper trendline level", "Levels")
self._lower_line = self.Param("LowerLine", 62000.0) \
.SetDisplay("Lower Line", "Lower trendline level", "Levels")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._last_price = 0.0
self._stop_price = 0.0
self._up_alerted = False
self._down_alerted = False
@property
def BreakoutPoints(self):
return self._breakout_points.Value
@BreakoutPoints.setter
def BreakoutPoints(self, value):
self._breakout_points.Value = value
@property
def StartHour(self):
return self._start_hour.Value
@StartHour.setter
def StartHour(self, value):
self._start_hour.Value = value
@property
def EndHour(self):
return self._end_hour.Value
@EndHour.setter
def EndHour(self, value):
self._end_hour.Value = value
@property
def UseTrailingStop(self):
return self._use_trailing_stop.Value
@UseTrailingStop.setter
def UseTrailingStop(self, value):
self._use_trailing_stop.Value = value
@property
def TrailingStopPoints(self):
return self._trailing_stop_points.Value
@TrailingStopPoints.setter
def TrailingStopPoints(self, value):
self._trailing_stop_points.Value = value
@property
def UpperLine(self):
return self._upper_line.Value
@UpperLine.setter
def UpperLine(self, value):
self._upper_line.Value = value
@property
def LowerLine(self):
return self._lower_line.Value
@LowerLine.setter
def LowerLine(self, value):
self._lower_line.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def _update_trailing_stop(self, candle):
step_raw = self.Security.PriceStep
step = float(step_raw) if step_raw is not None else 1.0
trail = self.TrailingStopPoints * step
if self.Position > 0:
self._stop_price = max(self._stop_price, float(candle.ClosePrice) - trail)
if float(candle.LowPrice) <= self._stop_price:
self.SellMarket()
elif self.Position < 0:
self._stop_price = min(self._stop_price, float(candle.ClosePrice) + trail)
if float(candle.HighPrice) >= self._stop_price:
self.BuyMarket()
else:
self._stop_price = 0.0
def OnStarted2(self, time):
super(trendline_alert_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(
Unit(2, UnitTypes.Percent),
Unit(2, UnitTypes.Percent))
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
hour = candle.OpenTime.Hour
if hour < self.StartHour or hour >= self.EndHour:
return
step_raw = self.Security.PriceStep
step = float(step_raw) if step_raw is not None else 1.0
threshold = self.BreakoutPoints * step
upper = float(self.UpperLine) + threshold
lower = float(self.LowerLine) - threshold
price = float(candle.ClosePrice)
if not self._up_alerted and price > upper and self._last_price <= upper:
self._up_alerted = True
if self.Position <= 0:
self.BuyMarket()
elif not self._down_alerted and price < lower and self._last_price >= lower:
self._down_alerted = True
if self.Position >= 0:
self.SellMarket()
if self.UseTrailingStop:
self._update_trailing_stop(candle)
self._last_price = price
def OnReseted(self):
super(trendline_alert_strategy, self).OnReseted()
self._last_price = 0.0
self._stop_price = 0.0
self._up_alerted = False
self._down_alerted = False
def CreateClone(self):
return trendline_alert_strategy()