GitHub で見る
預言者の戦略
概要
この戦略は、MetaTrader 4 エキスパート アドバイザー「PROphet」の StockSharp 移植です。元の EA は最近の取引実行を評価します
4 つの過去のローソク足を分析し、それらの加重範囲を使用して新しい取引をトリガーします。ポジションをオープン状態に保ちます。
ヨーロッパと米国では、価格が取引に有利に一定距離動くたびにセッションが行われ、ストップロスを追跡します。 StockSharp
実装では、これらの仕組みをすべて維持しながら、StockSharp ポートフォリオで使用されるネッティング モデルに適応させます。
取引ロジック
- 設定されたタイムフレーム (
CandleType、デフォルトは M5) をサブスクライブし、終了したローソク足のみを処理します。
- 最近完了した 3 つのローソク足を維持して、MQL バージョンで使用される
High[i] および Low[i] のインデックス付けを再現します。
- すべてのバーでロング トリガー
Qu(X1, X2, X3, X4) とショート トリガー Qu(Y1, Y2, Y3, Y4) を計算します。各項は次の値を乗算します。
元のコードとまったく同じように、対応する重みから 100 を引いた重み付き範囲 (例: |High[1] - Low[2]|)。
- 現在の時間が
TradeStartHour と TradeEndHour (両端の値を含む) の間にある場合にのみ、新しいエントリを許可します。これは男の真似をしている
MQL のエキスパートによる通常の取引ウィンドウ (デフォルトでは 10:00 ~ 18:00)。
- 新しいポジションを開く前に、ボリュームが反対のエクスポージャーを中和する単一の成行注文を使用します。これはマグを反映しています
MetaTrader 実装からの ic 番号フィルター。
リスク管理とトレーリング
- この戦略は、MetaTrader ポイントベースの停止距離を、商品
PriceStep を介して価格単位に変換します。デフォルト (B uyStopLossPoints = 68, SellStopLossPoints = 72) は、MQL 外部変数と一致します。
- 買値(ロング取引の場合)または売値(ショート取引の場合)が
spread + 2 * stopDistance までに既存のストップを超えると、
トレーリングストップは、利用可能な場合はライブレベル 1 データを使用して、currentPrice ± stopDistance まで進められます。
- 開いている取引は、
ExitHour の後に強制的に閉じられます。デフォルト値 (18) は、ポジションを閉じるという元の動作を再現します。
サーバー時間の 18:00 以降。
- StockSharp の高レベルの API は逆指値注文を自動的に生成しないため、保護的出口では成行注文が使用されます。これにより、
ブローカー全体での動作は決定的です。
パラメーター
| パラメータ |
説明 |
AllowBuy |
ロングトレードが可能になります。 |
AllowSell |
ショートトレードを可能にします。 |
X1, X2, X3, X4 |
Qu 式内の長辺範囲コンポーネントに適用される重み。 |
BuyStopLossPoints |
ロングトレードのストップロス距離は、MetaTrader ポイントで表されます。 |
Y1, Y2, Y3, Y4 |
Qu 式内の短辺範囲コンポーネントに適用される重み。 |
SellStopLossPoints |
短期取引のストップロス距離は MetaTrader ポイントで表されます。 |
TradeVolume |
新しいエントリに使用される基本ボリューム (ロット)。反対側の露出を閉じるために、余分なボリュームが自動的に追加されます。 |
TradeStartHour |
取引ウィンドウの最初の 1 時間 (これを含む)。 |
TradeEndHour |
取引ウィンドウの最後の 1 時間 (両端を含む)。 |
ExitHour |
すべての開いている取引が終了するまでの 1 時間。 |
CandleType |
分析に使用されるローソク足のタイムフレーム。 |
注意事項
- StockSharp ポートフォリオはデフォルトでネッティングしています。新しいシグナルが現れると、戦略は元シグナルをフラットにするために必要なボリュームを追加します。
新しい取引を開始する前の現在のポジション。これにより、MetaTrader のエクスペからの方向ごとに 1 つのポジションの設計が再現されます。
RT。
- MQL スクリプトは、
MarketInfo によって報告されたシンボル スプレッドを使用しました。ポートは、利用可能な場合、レベル 1 データからスプレッドを取得します。
それ以外の場合は単一の価格ステップに戻ります。
- トレーリングストップは終了した各ローソク足の終値で評価されるため、ティックレベルのストップと比較してスリッページが発生する可能性があります。
元の EA によって実行される更新。
using System;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Translation of the MetaTrader "PROphet" expert advisor.
/// Uses a range-weighted signal from previous candles to enter trades.
/// </summary>
public class ProphetStrategy : Strategy
{
private readonly StrategyParam<int> _x1;
private readonly StrategyParam<int> _x2;
private readonly StrategyParam<int> _x3;
private readonly StrategyParam<int> _x4;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _candle1;
private ICandleMessage _candle2;
private ICandleMessage _candle3;
private decimal _entryPrice;
public ProphetStrategy()
{
_x1 = Param(nameof(X1), 9)
.SetDisplay("X1", "Weight applied to |High[1] - Low[2]|.", "Signal");
_x2 = Param(nameof(X2), 29)
.SetDisplay("X2", "Weight applied to |High[3] - Low[2]|.", "Signal");
_x3 = Param(nameof(X3), 94)
.SetDisplay("X3", "Weight applied to |High[2] - Low[1]|.", "Signal");
_x4 = Param(nameof(X4), 125)
.SetDisplay("X4", "Weight applied to |High[2] - Low[3]|.", "Signal");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations.", "General");
}
public int X1 { get => _x1.Value; set => _x1.Value = value; }
public int X2 { get => _x2.Value; set => _x2.Value = value; }
public int X3 { get => _x3.Value; set => _x3.Value = value; }
public int X4 { get => _x4.Value; set => _x4.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candle1 = null;
_candle2 = null;
_candle3 = null;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Shift history
_candle3 = _candle2;
_candle2 = _candle1;
_candle1 = candle;
if (_candle1 == null || _candle2 == null || _candle3 == null)
return;
// Manage position - simple exit on reversal signal
if (Position > 0)
{
var sellSignal = CalculateSignal(true);
if (sellSignal > 0)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
var buySignal = CalculateSignal(false);
if (buySignal > 0)
{
BuyMarket();
_entryPrice = 0;
}
}
// Entry
if (Position == 0)
{
var buySignal = CalculateSignal(false);
var sellSignal = CalculateSignal(true);
if (buySignal > 0 && buySignal > sellSignal)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (sellSignal > 0 && sellSignal > buySignal)
{
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
}
private decimal CalculateSignal(bool isSell)
{
var term1 = Math.Abs(_candle1.HighPrice - _candle2.LowPrice);
var term2 = Math.Abs(_candle3.HighPrice - _candle2.LowPrice);
var term3 = Math.Abs(_candle2.HighPrice - _candle1.LowPrice);
var term4 = Math.Abs(_candle2.HighPrice - _candle3.LowPrice);
if (isSell)
{
// For sell, use inverted weights
return (100 - X1) * term1 + (100 - X2) * term2 + (X3 - 100) * term3 + (X4 - 100) * term4;
}
// For buy, use standard weights
return (X1 - 100) * term1 + (X2 - 100) * term2 + (100 - X3) * term3 + (100 - X4) * term4;
}
}
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, CandleStates
from StockSharp.Algo.Strategies import Strategy
class prophet_strategy(Strategy):
def __init__(self):
super(prophet_strategy, self).__init__()
self._x1 = self.Param("X1", 9) \
.SetDisplay("X1", "Weight applied to |High[1] - Low[2]|", "Signal")
self._x2 = self.Param("X2", 29) \
.SetDisplay("X2", "Weight applied to |High[3] - Low[2]|", "Signal")
self._x3 = self.Param("X3", 94) \
.SetDisplay("X3", "Weight applied to |High[2] - Low[1]|", "Signal")
self._x4 = self.Param("X4", 125) \
.SetDisplay("X4", "Weight applied to |High[2] - Low[3]|", "Signal")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._candle1 = None
self._candle2 = None
self._candle3 = None
self._entry_price = 0.0
@property
def X1(self):
return self._x1.Value
@property
def X2(self):
return self._x2.Value
@property
def X3(self):
return self._x3.Value
@property
def X4(self):
return self._x4.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(prophet_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
# Shift history
self._candle3 = self._candle2
self._candle2 = self._candle1
self._candle1 = {
'high': float(candle.HighPrice),
'low': float(candle.LowPrice),
'close': float(candle.ClosePrice),
}
if self._candle1 is None or self._candle2 is None or self._candle3 is None:
return
# Manage position - exit on reversal signal
if self.Position > 0:
sell_signal = self._calculate_signal(True)
if sell_signal > 0:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
buy_signal = self._calculate_signal(False)
if buy_signal > 0:
self.BuyMarket()
self._entry_price = 0.0
# Entry
if self.Position == 0:
buy_signal = self._calculate_signal(False)
sell_signal = self._calculate_signal(True)
if buy_signal > 0 and buy_signal > sell_signal:
self.BuyMarket()
self._entry_price = self._candle1['close']
elif sell_signal > 0 and sell_signal > buy_signal:
self.SellMarket()
self._entry_price = self._candle1['close']
def _calculate_signal(self, is_sell):
c1 = self._candle1
c2 = self._candle2
c3 = self._candle3
term1 = abs(c1['high'] - c2['low'])
term2 = abs(c3['high'] - c2['low'])
term3 = abs(c2['high'] - c1['low'])
term4 = abs(c2['high'] - c3['low'])
x1 = int(self.X1)
x2 = int(self.X2)
x3 = int(self.X3)
x4 = int(self.X4)
if is_sell:
return (100 - x1) * term1 + (100 - x2) * term2 + (x3 - 100) * term3 + (x4 - 100) * term4
else:
return (x1 - 100) * term1 + (x2 - 100) * term2 + (100 - x3) * term3 + (100 - x4) * term4
def OnReseted(self):
super(prophet_strategy, self).OnReseted()
self._candle1 = None
self._candle2 = None
self._candle3 = None
self._entry_price = 0.0
def CreateClone(self):
return prophet_strategy()