GitHub で見る
AnyRange クラウドテールシステム Tm Plus 戦略
この戦略は、StockSharpの高レベルAPIを使用してエキスパートアドバイザー Exp_i-AnyRangeCldTail_System_Tm_Plus.mq5 の動作を再現します。ユーザー定義の2つの時刻の間にカスタムのイントラデイレンジを構築し、そのレンジを超えたブレイクアウトを待ち、シグナルが元のMQLタイミングロジックと整合するようにブレイクアウト後の設定可能なバー数で注文をスケジュールします。
この戦略はロングとショートの両取引向けに設計されています。ブレイクアウトの許可、価格ステップでのストップロス/テイクプロフィット距離、保有期間、インジケーター計算ウィンドウを制御するパラメーターを公開しています。さらに、設定された分数より長く開いたままのポジションを閉じる時間ベースのエグジットがあり、元のエキスパートアドバイザーの保護ロジックと一致します。
トレーディングロジック
レンジ構築
- 2つのタイムスタンプ(
RangeStartTime と RangeEndTime)が、参照レンジを計算するために使用するセッションウィンドウを定義します。
- 各完了した日について、戦略はこれらのタイムスタンプ間の最高値と最安値を記録します。
RangeStartTime が RangeEndTime より大きい場合、ウィンドウは元のインジケーターと同様に自動的に深夜をまたぎます。
- 最後に完了したレンジは、新しい日次レンジが完了するまで再利用されます。
ブレイクアウト検出
- 各完了したローソク足が保存されたレンジと比較されます。
- レンジの最高値の上で閉じるローソク足はMLQインジケーターと同じカラーコード(2または3)を受け取り、レンジの最安値の下で閉じるローソク足はコード0または1を受け取ります。レンジ内のローソク足はコード4(シグナルなし)でタグ付けされます。
SignalBar パラメーターは検査ポイントをシフトします:戦略は SignalBar + 1 バー前のローソク足を評価し、より最近のローソク足(SignalBar)が同じ色を持っていないことを確認します。これは、EAがブレイクアウトローソク足の1バー後に注文を発動するために使用する遅延確認を再現します。
エントリー
- ロング:
AllowBuyEntry が真で、シグナルバーで強気色(2または3)が検出され、次のバーがブレイクアウト色を繰り返さない場合に許可されます。
- ショート:
AllowSellEntry が真で、シグナルバーで弱気色(0または1)が検出され、次のバーがブレイクアウト色を繰り返さない場合に許可されます。
- 反対のポジションが開いている場合、そのボリュームが新しい成行注文に追加され、ポジションが即座に転換し、
TradeAlgorithms.mqh のヘルパー関数の動作をエミュレートします。
エグジット
- 反対のシグナル:
AllowBuyExit が有効な場合、シグナルバーの弱気色(0または1)がロングポジションを閉じます。AllowSellExit が有効な場合、強気色(2または3)がショートポジションを閉じます。
- 時間エグジット:
UseTimeExit が真の場合、エントリーから ExitAfterMinutes 分後にポジションが清算され、nTime 分後にポジションをスキャンして閉じるMQLループと一致します。
- ストップ/ターゲット: オプションのストップロスとテイクプロフィット保護は
StopLossPoints と TakeProfitPoints を通じて設定されます。値は証券の価格ステップを使用して価格距離に変換され、元のポイントベースの設定を反映します。
リスクコントロール
- 注文は設定された
OrderVolume(楽器のボリューム単位で表されたベースサイズ)を使用します。注文サイズは各 BuyMarket/SellMarket 呼び出しで適用され、ポジションを転換する際に調整されます。
- ストップロスとテイクプロフィットは組み込みの
StartProtection ヘルパーによって管理され、戦略開始直後にOCO保護を登録します。
パラメーター
| パラメーター |
説明 |
デフォルト |
OrderVolume |
新しいポジションのベース注文サイズ。 |
0.1 |
AllowBuyEntry |
強気ブレイクアウトでのロングエントリーを許可。 |
true |
AllowSellEntry |
弱気ブレイクアウトでのショートエントリーを許可。 |
true |
AllowBuyExit |
弱気ブレイクアウトでロングポジションを閉じる。 |
true |
AllowSellExit |
強気ブレイクアウトでショートポジションを閉じる。 |
true |
UseTimeExit |
時間ベースのエグジットを有効化。 |
true |
ExitAfterMinutes |
時間エグジットが発動するまでの保有時間(分)。 |
1500 |
StopLossPoints |
価格ステップでのストップロス距離。無効化には 0 を使用。 |
1000 |
TakeProfitPoints |
価格ステップでのテイクプロフィット距離。無効化には 0 を使用。 |
2000 |
SignalBar |
ブレイクアウト検出のために検査するバー数(MQLの SignalBar に対応)。 |
1 |
RangeLookbackDays |
完了したレンジを見つけるためにスキャンする過去セッションの最大数。最新のレンジのみを常に使用するには 0 に設定。 |
1 |
RangeStartTime |
レンジ構築ウィンドウの開始(TimeSpan)。 |
02:00 |
RangeEndTime |
レンジ構築ウィンドウの終了(TimeSpan)。 |
07:00 |
CandleType |
計算に使用するローソク足データタイプ/時間軸。 |
30分 |
実装上の注意
- クラスは
SubscribeCandles とイベント駆動型の WhenNew パイプラインを使用して完了したローソク足のみを処理し、IsNewBar チェックに依存したMQLエキスパートアドバイザーと決定が一致することを保証します。
- レンジ値は軽量な構造体に格納され、アルゴリズムはプロジェクトのガイドラインに従うために完全なコレクションに対するLINQを避けます。
- 時間エグジットは現在開いている方向のエントリータイムスタンプを保存し、ソースコードが開いたポジションをどのように反復したかを反映します。
- 注文ボリュームはベース
Strategy.Volume プロパティと同期され、StockSharpのUIが設定されたサイズを反映します。
- コードには各主要セクションを説明する英語コメントが含まれており、メンテナンスと追加カスタマイズを容易にします。
使用上のヒント
- データフィードが選択した
CandleType と整合するローソク足を提供することを確認してください。ブレイクアウト検出は完了したローソク足に依存します;ティックベースまたは部分的に形成されたバーは処理すべきではありません。
- 異なる取引セッションを持つ市場を取引する場合、原資産に最もよく対応する蓄積期間をカバーするように
RangeStartTime と RangeEndTime を調整してください。
- 楽器に不規則な価格ステップがある場合、チャートまたは注文ログで生成された保護注文を検査して
StopLossPoints/TakeProfitPoints の変換を確認してください。
- より速い時間軸で取引する場合は、意図した以上に長くポジションを保有しないように
ExitAfterMinutes を減らしてください。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// AnyRange Cloud Tail System TM Plus strategy. Uses Highest/Lowest channel midline crossover.
/// </summary>
public class AnyRangeCloudTailSystemTmPlusStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevMid;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
public AnyRangeCloudTailSystemTmPlusStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 20)
.SetGreaterThanZero()
.SetDisplay("Period", "Channel lookback period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMid = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMid = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var mid = (high + low) / 2m;
var close = candle.ClosePrice;
if (_prevMid == null)
{
_prevMid = mid;
return;
}
// Close crosses above midline → buy
if (close > mid && candle.OpenPrice <= _prevMid.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Close crosses below midline → sell
else if (close < mid && candle.OpenPrice >= _prevMid.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMid = mid;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class any_range_cloud_tail_system_tm_plus_strategy(Strategy):
"""
AnyRange Cloud Tail System TM Plus strategy.
Uses Highest/Lowest channel midline crossover for entries.
"""
def __init__(self):
super(any_range_cloud_tail_system_tm_plus_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(60)) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 20) \
.SetGreaterThanZero() \
.SetDisplay("Period", "Channel lookback period", "Indicators")
self._prev_mid = None
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
@property
def Period(self): return self._period.Value
@Period.setter
def Period(self, v): self._period.Value = v
def OnReseted(self):
super(any_range_cloud_tail_system_tm_plus_strategy, self).OnReseted()
self._prev_mid = None
def OnStarted2(self, time):
super(any_range_cloud_tail_system_tm_plus_strategy, self).OnStarted2(time)
self._prev_mid = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, high, low):
if candle.State != CandleStates.Finished:
return
mid = (high + low) / 2.0
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
if self._prev_mid is None:
self._prev_mid = mid
return
if close > mid and open_price <= self._prev_mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < mid and open_price >= self._prev_mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_mid = mid
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return any_range_cloud_tail_system_tm_plus_strategy()