GLFX戦略
MetaTrader 4 エキスパート アドバイザー GLFX が StockSharp のハイレベル API 用に書き直されました。このポートは、外部指標に依存するめったに使用されないフィルターの膨大なコレクションを削除しながら、より高いタイムフレームの確認と厳格な資金管理ゲートを組み合わせるという元のアイデアを維持しています。
取引ロジック
- この戦略はプライマリ タイムフレーム (デフォルト M15) で機能し、オプションで従来の MetaTrader ラダー (
M15 → M30 → H1 → H4 → D1 → W1 → MN) を上って確認タイムフレームを構築します。
- より高い時間枠 RSI (デフォルトの期間 57) は、勢いが上昇しているか下降しているかを追跡します。 RSI が上昇しているものの、設定された買われすぎの上限を下回っている場合、購入確認が表示されます。売り確認には、売られ過ぎのフロアを超えた状態で RSI をチェックダウンする必要があります。
- より長い時間枠 単純移動平均 (デフォルト期間 60) は、価格が平均から離れているかどうかを検出します。強気の確認には、現在の終値を上回りながらMAが上昇する必要があります(価格が上昇トレンドに戻る)。弱気の確証はこのロジックを反映しています。
- 有効になっている各フィルターは、強気の感情には
+1、弱気の感情には -1 をもたらします。有効な信号としてカウントするには、合計がアクティブなフィルターの数に達する必要があります。カウンタは、最大強度シグナルが連続して何回出現したかを記憶します (SignalsRepeat)。結合強度がしきい値を下回り、SignalsReset が有効になっている場合、カウンターはリセットされます。
- 戦略がフラットで、ロング/ショート エントリー スイッチによって許可されている場合、次に完了したカウンターが構成された
Volume で成行注文をトリガーします。静的なストップロスとテイクプロフィットのレベルは、商品のティックサイズを使用してピップから価格オフセットに変換されます。
- ポジションがすでにオープンしている場合、強い逆シグナルによって早期にポジションがクローズされる可能性があります (
AllowLongExit / AllowShortExit)。それ以外の場合、出口は StartProtection() によって管理されるストップまたはターゲットに依存します。
この移植では、オリジナルの EA のオプションのクォンタム、Twitter 感情、オープンバー相関、セット テスト、または高度な資金管理ラダーは再現されません**。これらのモジュールには、StockSharp に存在しない追加のカスタム インジケーターまたはブローカー状態が必要でした。
パラメーター
| パラメータ |
デフォルト |
説明 |
CandleType |
M15 |
価格評価の作業時間枠。 |
HigherTimeFrameShift |
1 |
確認時間枠を構築するために使用される MT4 ステップの数。 0 は現在の時間枠を維持します。 |
UseRsiSignal |
本当の |
より長い時間枠 RSI の確認を有効にします。 |
RsiPeriod |
57 |
確認期間 RSI。 |
RsiUpperThreshold |
65 |
RSI がこの値を超えると、新しい Long が無効になります。 |
RsiLowerThreshold |
25 |
RSI がこの値を下回ると、新しいショート動画を無効にします。 |
UseMaSignal |
本当の |
より長い時間枠の移動平均の確認を有効にします。 |
MaPeriod |
60 |
確認移動平均の期間。 |
SignalsRepeat |
1 |
取引を開始する前に必要な連続した最大強度のシグナルの数。 |
SignalsReset |
本当の |
結合された信号が勢いを失ったときにカウンターをリセットします。 |
TakeProfitPips |
308 |
ピップスで表されるテイクプロフィット距離。無効にするには、0 に設定します。 |
StopLossPips |
290 |
ピップスで表されるストップロス距離。無効にするには、0 に設定します。 |
Volume |
0.1 |
新しいポジション (ロット) に使用される注文サイズ。 |
AllowLongEntry / AllowShortEntry |
本当の |
ロングまたはショート取引を開始するための許可スイッチ。 |
AllowLongExit / AllowShortExit |
本当の |
反対の信号で既存のエクスポージャを自動的に閉じることができます。 |
使用上の注意
- ピップ変換が正確に保たれるように、信頼性の高いティックサイズを持つインストゥルメントを選択してください。小数点以下 3 桁または 5 桁の外国為替ペアは、価格ステップを 10 倍することで、自動的に MetaTrader の「ポイント」にマッピングされます。
- すべてを同じ時間枠で実行する場合は、
HigherTimeFrameShift を 0 に設定します。この場合、サブスクリプションの重複を避けるために、インジケーターはプライマリローソク足ストリームによって供給されます。
- 反対のシグナルに関係なく取引を開いたままにする従来の動作が必要な場合は、対応する
Allow*Exit フラグを無効にします。
- 元のスクリプトの資金管理スケーリング (
MMC_* 設定)、後続モジュール、およびエキゾチックな出口フィルターは意図的に省略されました。必要に応じて、このクリーンなコアの上にそれらを実装します。
オリジナルの EA との違い
| 機能グループ |
MetaTrader EA |
StockSharp ポート |
| 確認フィルター |
RSI、MA、オプションのQuantum、TSI、複数通貨相関 |
RSI および MA のみ (コア動作) |
| 入場ゲート |
信号の繰り返しと時間フィルター |
信号の繰り返しとオプションのリセット |
| リスク管理 |
大規模な後続モジュール ライブラリを備えた静的 TP/SL |
StartProtection() 経由の静的 TP/SL |
| お金の管理 |
増分ロットのスケーリングと損失のはしご |
固定ボリュームパラメータ |
| 外部依存関係 |
カスタム インジケーター (Quantum、TSI、ファイルベースのセット読み込み) |
なし |
その結果、StockSharp フレームワークを使用して簡単に拡張できる一方で、遅いチャートでトレンドの確認を待ち、合意が繰り返された場合にのみエントリーするという、認識可能な GLFX の動作を維持するコンパクトで保守可能な戦略が得られます。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// GLFX strategy: RSI + SMA confirmation for entry.
/// Requires consecutive confirmations before trading.
/// </summary>
public class GlfxStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiUpper;
private readonly StrategyParam<decimal> _rsiLower;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _signalsRepeat;
private decimal _prevRsi;
private decimal _prevMa;
private int _buyCount;
private int _sellCount;
private decimal _entryPrice;
public GlfxStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI period.", "Indicators");
_rsiUpper = Param(nameof(RsiUpper), 65m)
.SetDisplay("RSI Upper", "Overbought level.", "Indicators");
_rsiLower = Param(nameof(RsiLower), 35m)
.SetDisplay("RSI Lower", "Oversold level.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 60)
.SetDisplay("MA Period", "SMA period.", "Indicators");
_signalsRepeat = Param(nameof(SignalsRepeat), 2)
.SetDisplay("Signals Repeat", "Consecutive confirmations needed.", "Signals");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiUpper
{
get => _rsiUpper.Value;
set => _rsiUpper.Value = value;
}
public decimal RsiLower
{
get => _rsiLower.Value;
set => _rsiLower.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public int SignalsRepeat
{
get => _signalsRepeat.Value;
set => _signalsRepeat.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_prevMa = 0;
_buyCount = 0;
_sellCount = 0;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevRsi == 0 || _prevMa == 0)
{
_prevRsi = rsiVal;
_prevMa = maVal;
return;
}
var close = candle.ClosePrice;
// RSI signal: rising and below upper = bullish, falling and above lower = bearish
var rsiSignal = 0;
if (rsiVal > _prevRsi && rsiVal < RsiUpper)
rsiSignal = 1;
else if (rsiVal < _prevRsi && rsiVal > RsiLower)
rsiSignal = -1;
// MA signal: price above rising MA = bullish, below falling MA = bearish
var maSignal = 0;
if (maVal > _prevMa && close > maVal)
maSignal = 1;
else if (maVal < _prevMa && close < maVal)
maSignal = -1;
// Both signals must agree
if (rsiSignal > 0 && maSignal > 0)
{
_buyCount++;
_sellCount = 0;
}
else if (rsiSignal < 0 && maSignal < 0)
{
_sellCount++;
_buyCount = 0;
}
else
{
_buyCount = 0;
_sellCount = 0;
}
// Exit on opposite signal
if (Position > 0 && _sellCount >= SignalsRepeat)
{
SellMarket();
_entryPrice = 0;
_buyCount = 0;
_sellCount = 0;
}
else if (Position < 0 && _buyCount >= SignalsRepeat)
{
BuyMarket();
_entryPrice = 0;
_buyCount = 0;
_sellCount = 0;
}
// Entry after required confirmations
if (Position == 0)
{
if (_buyCount >= SignalsRepeat)
{
_entryPrice = close;
BuyMarket();
_buyCount = 0;
_sellCount = 0;
}
else if (_sellCount >= SignalsRepeat)
{
_entryPrice = close;
SellMarket();
_buyCount = 0;
_sellCount = 0;
}
}
_prevRsi = rsiVal;
_prevMa = maVal;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
class glfx_strategy(Strategy):
def __init__(self):
super(glfx_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._rsi_upper = self.Param("RsiUpper", 65.0) \
.SetDisplay("RSI Upper", "Overbought level", "Indicators")
self._rsi_lower = self.Param("RsiLower", 35.0) \
.SetDisplay("RSI Lower", "Oversold level", "Indicators")
self._ma_period = self.Param("MaPeriod", 60) \
.SetDisplay("MA Period", "SMA period", "Indicators")
self._signals_repeat = self.Param("SignalsRepeat", 2) \
.SetDisplay("Signals Repeat", "Consecutive confirmations needed", "Signals")
self._prev_rsi = 0.0
self._prev_ma = 0.0
self._buy_count = 0
self._sell_count = 0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def RsiUpper(self):
return self._rsi_upper.Value
@property
def RsiLower(self):
return self._rsi_lower.Value
@property
def MaPeriod(self):
return self._ma_period.Value
@property
def SignalsRepeat(self):
return self._signals_repeat.Value
def OnStarted2(self, time):
super(glfx_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._prev_ma = 0.0
self._buy_count = 0
self._sell_count = 0
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
self._ma = SimpleMovingAverage()
self._ma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._ma, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, ma_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
mv = float(ma_val)
if self._prev_rsi == 0 or self._prev_ma == 0:
self._prev_rsi = rv
self._prev_ma = mv
return
close = float(candle.ClosePrice)
rsi_upper = float(self.RsiUpper)
rsi_lower = float(self.RsiLower)
# RSI signal
rsi_signal = 0
if rv > self._prev_rsi and rv < rsi_upper:
rsi_signal = 1
elif rv < self._prev_rsi and rv > rsi_lower:
rsi_signal = -1
# MA signal
ma_signal = 0
if mv > self._prev_ma and close > mv:
ma_signal = 1
elif mv < self._prev_ma and close < mv:
ma_signal = -1
# Both signals must agree
if rsi_signal > 0 and ma_signal > 0:
self._buy_count += 1
self._sell_count = 0
elif rsi_signal < 0 and ma_signal < 0:
self._sell_count += 1
self._buy_count = 0
else:
self._buy_count = 0
self._sell_count = 0
signals_needed = self.SignalsRepeat
# Exit on opposite signal
if self.Position > 0 and self._sell_count >= signals_needed:
self.SellMarket()
self._entry_price = 0.0
self._buy_count = 0
self._sell_count = 0
elif self.Position < 0 and self._buy_count >= signals_needed:
self.BuyMarket()
self._entry_price = 0.0
self._buy_count = 0
self._sell_count = 0
# Entry after required confirmations
if self.Position == 0:
if self._buy_count >= signals_needed:
self._entry_price = close
self.BuyMarket()
self._buy_count = 0
self._sell_count = 0
elif self._sell_count >= signals_needed:
self._entry_price = close
self.SellMarket()
self._buy_count = 0
self._sell_count = 0
self._prev_rsi = rv
self._prev_ma = mv
def OnReseted(self):
super(glfx_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._prev_ma = 0.0
self._buy_count = 0
self._sell_count = 0
self._entry_price = 0.0
def CreateClone(self):
return glfx_strategy()