GitHub で見る
SilverTrend ColorJFatl Digit戦略
概要
SilverTrend ColorJFatl Digit戦略は2つのクラシックなMetaTraderシステムを統一された高レベルStockSharp戦略に融合させます。SilverTrendブロックは短いDonchianスタイルのチャンネル内で価格がどれだけ動くかを測定することで方向性のブレイクアウトを識別します。ColorJFatl DigitブロックはJurik Moving Average(JMA)で価格を平滑化し、出力を設定された桁数に丸めた後の傾きを評価します。両方のサブシステムが方向に合意した場合にのみ、戦略はポジションを開設または維持します。シグナルが分岐すると、戦略はフラットに退出します。
設計はオリジナルのエキスパートアドバイザーの精神を維持しながら、StockSharpの高レベルAPIを活用します:ローソク足サブスクリプション、インジケーターバインディング、キューベースのシグナル遅延、チャート描画ヘルパー。各ステップは詳細に文書化されており、さらなる研究と最適化を簡単にします。
戦略ロジック
1. SilverTrendブレイクアウト検出器
HighestとLowestインジケーターをSilverTrendLength + 1ローソク足で使用して最近の価格チャンネルを形成します。
- チャンネルは
SilverTrendRiskパラメーターによって絞られます:リスク値が高いほど、ブレイクアウトしきい値がチャンネルの中線に近くなります(元の式33 - risk)。
- 終値が調整された上限しきい値を上回ると、SilverTrendブロックは強気のトレンド(
+1)を報告します。下限しきい値を下回ると、ブロックは弱気のトレンド(-1)を報告します。
- 設定可能な遅延(
SilverTrendSignalBar)はシグナルが有効とみなされる前にn個の完全にクローズしたローソク足を待機し、MQLのSignalBarロジックを模倣します。
2. ColorJFatl Digit確認フィルター
JurikMovingAverageはJmaPriceTypeによって選択された応用価格を平滑化します。すべてのMetaTraderの応用価格タイプがサポートされています(クローズ、オープン、中間値、典型的、加重、シンプル、四分の一、トレンドフォローモード、Demark計算)。
- Jurik出力は
JmaRoundDigitsに丸められ、離散化された「digit」インジケーターの動作を再現します。
- 丸められたJMAの傾きの符号がトレンドシグナルになります。傾きが正の場合、フィルターは
+1を発行します;負の場合は-1です。フラットな傾きは以前の状態を継承し、急激な切り替えを避けます。
- SilverTrendと同様に、
JmaSignalBarは実行を遅延させ、傾きがリクエストされた数のクローズしたローソク足の間保持されることを要求します。
3. トレード実行
- エントリー:
- SilverTrendとColorJFatlの両方が
+1を報告し、既存のロングエクスポージャーがない場合にロングに入ります。
- 両方のブロックが
-1を報告し、既存のショートエクスポージャーがない場合にショートに入ります。
- エグジット:
- シグナルが分岐した場合(例:一方のブロックが
+1と言い、他方が-1または0)、現在のポジションを即座にクローズします。
- リバーサルは新しいポジションを開設する前に自動的に反対のエクスポージャーをクローズし、平均化を避けます。
- アクティブな注文はブックをクリーンに保つためにリバーサルの前にキャンセルされます。
パラメーター
| 名前 |
説明 |
SilverTrendCandleType |
SilverTrendブレイクアウトチャンネルを計算するために使用されるローソク足シリーズ。デフォルトはH4相当。 |
SilverTrendLength |
チャンネル計算のルックバック長(元のEAのSSPパラメーター)。 |
SilverTrendRisk |
ブレイクアウトしきい値を絞るリスク修飾子(33 - risk)。値が高いほど速く反応しますが、ダマしが多くなります。 |
SilverTrendSignalBar |
SilverTrendの色変化を受け入れる前に待機する完全にクローズしたローソク足の数。 |
ColorJfatlCandleType |
Jurikフィルターを供給するローソク足シリーズ。SilverTrendの時間軸と異なる場合があります。 |
JmaLength |
Jurik Moving Averageの長さ。 |
JmaSignalBar |
Jurikの傾き変化に対して行動する前の遅延(バー単位)。 |
JmaPriceType |
Jurik入力の応用価格モード(クローズ、オープン、中間値、トレンドフォローバリアント、Demark等)。 |
JmaRoundDigits |
Jurik出力を丸める際に使用される小数点以下の桁数、デジタル化されたインジケーターをエミュレート。 |
実装の注意事項
- シグナル遅延は大きな履歴配列ではなく小さなFIFOキューで実装され、戦略がメモリ効率を保ちオリジナルのエキスパートアドバイザーに忠実であることを保証します。
- コードはインジケーターバッファーを直接クエリしません。代わりに、
AGENTS.mdのガイドラインに従って、高レベルのSubscribeCandles().Bind(...)APIを通じてインジケーターをバインドします。
- 英語のインラインコメントはすべての決定を説明します:しきい値がいつ再計算されるか、傾きがどのように計算されるか、なぜ注文がキャンセルされるか、コンセンサスがどのように強制されるか。
- チャートサポートが含まれています:チャートが利用可能な場合、戦略は価格ローソク足、SilverTrendチャンネルライン、独自のトレードを描画してライブ決定を視覚化します。
使用のヒント
- 市場と時間軸: 元のシステムはH4 forexチャート向けに設計されました。明確なスウィング動作を持つ仮想通貨や商品先物も良好に機能します。より速い市場では
SilverTrendLengthとJmaLengthを慎重に削減します。
- 最適化: ブレイクアウト長(
SilverTrendLength)と確認長(JmaLength)の両方を一緒に最適化します — 一方の辺だけを短縮すると通常は相反するシグナルが生まれます。
- 応用価格の実験: Heikin-AshiまたはRenkoフィードで作業する際にトレンドフォロー価格モードを試みます;それらは純粋なクローズ価格よりもノイズをより良くスムーズにすることが多いです。
- リスク管理: 組み込みのエグジットをポートフォリオレベルのストップと組み合わせます。両方のモジュールはわずかに遅延するため、ボラティリティの急上昇はフィルターが反転する前にチャンネルを超えて到達する可能性があります。
- ポジションサイジング: 戦略はボリューム管理をベース
Strategy.Volumeプロパティに任せます。ピラミッドまたはスケーリングが必要な場合は調整するかStockSharpのマネーマネジメント拡張を統合します。
さらなる研究のアイデア
- テストが好ましいしきい値を確認したら、
StartProtectionを通じてATRベースのストップロスとテイクプロフィット保護を追加します。
- トレンドフィルターを導入するためにSilverTrendをH4に保持しながら、上位時間軸のローソク足(例:日足)をJurik確認に供給します。
- エントリー前の追加確認のためにボリュームベースのフィルター(オンバランスボリューム、VWAP乖離)と組み合わせます。
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>
/// SilverTrend ColorJFatl Digit strategy (simplified). Uses Highest/Lowest channel
/// breakout combined with EMA slope for trend confirmation.
/// </summary>
public class SilverTrendColorJFatlDigitStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _riskLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int RiskLevel
{
get => _riskLevel.Value;
set => _riskLevel.Value = value;
}
public SilverTrendColorJFatlDigitStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_channelLength = Param(nameof(ChannelLength), 21)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators");
_emaLength = Param(nameof(EmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period for trend confirmation", "Indicators");
_riskLevel = Param(nameof(RiskLevel), 3)
.SetDisplay("Risk Level", "Channel threshold tightness", "Logic");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = ChannelLength + 1 };
var lowest = new Lowest { Length = ChannelLength + 1 };
var lastTrend = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, (ICandleMessage candle, decimal highVal, decimal lowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var range = highVal - lowVal;
if (range <= 0)
return;
var riskModifier = 33m - RiskLevel;
if (riskModifier < 0m) riskModifier = 0m;
if (riskModifier > 33m) riskModifier = 33m;
var thresholdPercent = riskModifier / 100m;
var lowerThreshold = lowVal + range * thresholdPercent;
var upperThreshold = highVal - range * thresholdPercent;
var close = candle.ClosePrice;
// SilverTrend breakout logic
if (close < lowerThreshold)
lastTrend = -1;
else if (close > upperThreshold)
lastTrend = 1;
// Simple EMA slope confirmation using close vs channel midpoint
var midpoint = (highVal + lowVal) / 2m;
var emaConfirmUp = close > midpoint;
var emaConfirmDown = close < midpoint;
if (lastTrend > 0 && emaConfirmUp && Position <= 0)
BuyMarket();
else if (lastTrend < 0 && emaConfirmDown && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class silver_trend_color_j_fatl_digit_strategy(Strategy):
def __init__(self):
super(silver_trend_color_j_fatl_digit_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._channel_length = self.Param("ChannelLength", 21) \
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators")
self._risk_level = self.Param("RiskLevel", 3) \
.SetDisplay("Risk Level", "Channel threshold tightness", "Logic")
self._last_trend = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def ChannelLength(self):
return self._channel_length.Value
@property
def RiskLevel(self):
return self._risk_level.Value
def OnReseted(self):
super(silver_trend_color_j_fatl_digit_strategy, self).OnReseted()
self._last_trend = 0
def OnStarted2(self, time):
super(silver_trend_color_j_fatl_digit_strategy, self).OnStarted2(time)
self._last_trend = 0
highest = Highest()
highest.Length = self.ChannelLength + 1
lowest = Lowest()
lowest.Length = self.ChannelLength + 1
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).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 _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
rng = hv - lv
if rng <= 0:
return
risk_modifier = 33.0 - self.RiskLevel
if risk_modifier < 0:
risk_modifier = 0.0
if risk_modifier > 33:
risk_modifier = 33.0
threshold_pct = risk_modifier / 100.0
lower_threshold = lv + rng * threshold_pct
upper_threshold = hv - rng * threshold_pct
close = float(candle.ClosePrice)
if close < lower_threshold:
self._last_trend = -1
elif close > upper_threshold:
self._last_trend = 1
midpoint = (hv + lv) / 2.0
if self._last_trend > 0 and close > midpoint and self.Position <= 0:
self.BuyMarket()
elif self._last_trend < 0 and close < midpoint and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return silver_trend_color_j_fatl_digit_strategy()