GitHub で見る
WPR カスタム クラウドのシンプルな戦略
概要
WPR Custom Cloud Simple Strategy は、MetaTrader エキスパート アドバイザー WPR Custom Cloud Simple.mq5 の StockSharp 移植です。 EA はラリー Williams の %R オシレーターを監視し、インジケーターが売られすぎまたは買われすぎの領域を抜けたときに取引を開始します。この C# バージョンは、新しいローソク足でのみ取引するという元の設計を維持し、反対のシグナルが現れたときにポジションを反転し、リファレンス実装とまったく同様にストップロスまたはテイクプロフィット注文を回避します。
取引ロジック
- 構成されたタイムフレーム (
CandleType) をサブスクライブし、受信ローソクを WilliamsR インジケーターにフィードします。
- ろうそくの火が消えるまで待ちます。ストラテジーは不完全なバーには決して作用しません。
- 最後に完了した 2 つの %R 値を保存します。これらは、MetaTrader からの
wpr[1] と wpr[2] の読み取り値を反映しています。
- クロスオーバーで信号を生成します。
- ロングセットアップ: 前のバーは
OversoldLevel の上で閉じますが、その前のバーはレベルを下回っています。これにより、EA の「売られ過ぎからの出口」状態 (wpr[2] < level および wpr[1] > level) が再現されます。
- 簡単なセットアップ: 前のバーは
OverboughtLevel の下で閉じますが、前のバーはその上にあり、元の wpr[2] > level および wpr[1] < level チェックと一致します。
- 長いセットアップが表示された場合は、短いエクスポージャをフラットにして、正味ボリュームを 1 つ購入します。ショートセットアップが発動したら、ロングサイドを平らにして正味1ボリュームを売ります。 StockSharp はネット ポジションで動作するため、
Volume + |Position| で BuyMarket/SellMarket を送信すると、MetaTrader のヘッジ口座からの決済と反転のフローが完全に複製されます。
- 追加の出口は使用されません。元のアドバイザーと同様に、新しい反対のクロスオーバーが取引を終了する唯一の方法です。
パラメーター
| 名前 |
種類 |
デフォルト |
MetaTraderの相手方 |
説明 |
WprPeriod |
int |
14 |
Inp_WPR_Period |
Williams %R 計算のルックバックの長さ。 |
OverboughtLevel |
decimal |
-20 |
Inp_WPR_Level1 |
買われすぎの領域を定義するしきい値。それより下を通過するとショートがトリガーされます。 |
OversoldLevel |
decimal |
-80 |
Inp_WPR_Level2 |
売られ過ぎの領域を定義するしきい値。それを超えるとロングがトリガーされます。 |
CandleType |
DataType |
1時間枠 |
InpWorkingPeriod |
インジケーターの更新とシグナルの評価に使用されるローソク足シリーズ。 |
Volume |
decimal |
戦略ベースボリューム |
InpLots |
成行注文のロットサイズ。この戦略は、新しい取引を開始する前に、現在のネットポジションを自動的に相殺します。 |
オリジナルの EA との違い
- StockSharp はネット ポジションで動作します。逆エクスポージャーの決済は成行注文量を増やすことで処理されるため、その動作は
STRUCT_POSITION のような追加の簿記構造を必要とせずにヘッジ モデルと一致します。
- すべての注文管理ヘルパー クラス (
CTrade、CPositionInfo、マージン チェックなど) は、StockSharp の組み込みリスク管理によって置き換えられます。この戦略は、手動によるフリーマージンの計算ではなく、Strategy.Volume と取引所のメタデータに依存しています。
- ロギングが簡素化されます。 StockSharp バージョンでは、高レベルの API が注文ステータスの更新をすでに提供しているため、冗長な
Print ステートメントが回避されます。
- 保護命令は、情報源 EA の「反対側シグナルに接近」設計を反映するために意図的に省略されています。
使い方のヒント
- クロスオーバー周波数を同等に保つために、
CandleType を MetaTrader で使用したのと同じ時間枠に調整します。
- Williams %R しきい値は負の値です。
OverboughtLevel をゼロに近づけるとショートエントリーが少なくなり、OversoldLevel を -100 に近づけるとロングエントリーが少なくなります。
- この戦略は、
Volume がブローカーの最小ステップとネッティング ルールにすでに準拠していることを前提としています。ライブ取引を開始する前に、UI またはコードを通じて基本ボリュームを調整します。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Williams %R cloud breakout strategy converted from the MetaTrader expert advisor.
/// Looks for %R crossings above -80 to go long and below -20 to go short.
/// Positions are reversed when an opposite signal appears.
/// </summary>
public class WprCustomCloudSimpleStrategy : Strategy
{
private readonly StrategyParam<int> _wprPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<DataType> _candleType;
private WilliamsR _williamsR;
private decimal? _previousWpr;
private decimal? _olderWpr;
public int WprPeriod
{
get => _wprPeriod.Value;
set => _wprPeriod.Value = value;
}
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public WprCustomCloudSimpleStrategy()
{
_wprPeriod = Param(nameof(WprPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("WPR Period", "Williams %R lookback length", "Williams %R");
_overboughtLevel = Param(nameof(OverboughtLevel), -10m)
.SetDisplay("Overbought Level", "%R level that marks overbought conditions", "Williams %R");
_oversoldLevel = Param(nameof(OversoldLevel), -90m)
.SetDisplay("Oversold Level", "%R level that marks oversold conditions", "Williams %R");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for Williams %R", "Data");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_williamsR = new WilliamsR { Length = WprPeriod };
_previousWpr = null;
_olderWpr = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_williamsR, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _williamsR);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal wprValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_williamsR.IsFormed)
{
_olderWpr = _previousWpr;
_previousWpr = wprValue;
return;
}
if (_previousWpr is not null && _olderWpr is not null)
{
var prev = _previousWpr.Value;
var prevPrev = _olderWpr.Value;
var crossedAboveOversold = prevPrev < OversoldLevel && prev > OversoldLevel;
var crossedBelowOverbought = prevPrev > OverboughtLevel && prev < OverboughtLevel;
var volume = Volume;
if (volume <= 0)
volume = 1;
if (crossedAboveOversold)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossedBelowOverbought)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
}
_olderWpr = _previousWpr;
_previousWpr = wprValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_williamsR = null;
_previousWpr = null;
_olderWpr = null;
base.OnReseted();
}
}
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 WilliamsR
from StockSharp.Algo.Strategies import Strategy
class wpr_custom_cloud_simple_strategy(Strategy):
def __init__(self):
super(wpr_custom_cloud_simple_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._wpr_period = self.Param("WprPeriod", 20)
self._overbought_level = self.Param("OverboughtLevel", -10.0)
self._oversold_level = self.Param("OversoldLevel", -90.0)
self._prev_wpr = 0.0
self._older_wpr = 0.0
self._count = 0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def WprPeriod(self):
return self._wpr_period.Value
@WprPeriod.setter
def WprPeriod(self, value):
self._wpr_period.Value = value
@property
def OverboughtLevel(self):
return self._overbought_level.Value
@OverboughtLevel.setter
def OverboughtLevel(self, value):
self._overbought_level.Value = value
@property
def OversoldLevel(self):
return self._oversold_level.Value
@OversoldLevel.setter
def OversoldLevel(self, value):
self._oversold_level.Value = value
def OnReseted(self):
super(wpr_custom_cloud_simple_strategy, self).OnReseted()
self._prev_wpr = 0.0
self._older_wpr = 0.0
self._count = 0
def OnStarted2(self, time):
super(wpr_custom_cloud_simple_strategy, self).OnStarted2(time)
self._prev_wpr = 0.0
self._older_wpr = 0.0
self._count = 0
wpr = WilliamsR()
wpr.Length = self.WprPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(wpr, self._process_candle).Start()
def _process_candle(self, candle, wpr_value):
if candle.State != CandleStates.Finished:
return
wpr_val = float(wpr_value)
self._count += 1
if self._count >= 3:
oversold = float(self.OversoldLevel)
overbought = float(self.OverboughtLevel)
crossed_above_oversold = self._older_wpr < oversold and self._prev_wpr > oversold
crossed_below_overbought = self._older_wpr > overbought and self._prev_wpr < overbought
if crossed_above_oversold and self.Position <= 0:
self.BuyMarket()
elif crossed_below_overbought and self.Position >= 0:
self.SellMarket()
self._older_wpr = self._prev_wpr
self._prev_wpr = wpr_val
def CreateClone(self):
return wpr_custom_cloud_simple_strategy()