GitHub で見る
Reversing Martingale戦略
概要
Reversing Martingale戦略は、MetaTraderエキスパートアドバイザー「Reversing Martingale EA」の直接的なC#移植版です。常に単一の成行ポジションを維持し、各決済後に取引方向を交互に切り替えます。損失取引はマーチンゲール数量進行を起動し、利益取引はサイクルを初期ロットサイズへ戻します。すべてのポジションは、価格ポイントで表した対称的なストップロスとテイクプロフィット水準で保護されます。
この戦略は指標や市場構造に依存しません。完了したポジションに反応し、取引が無効でない限り常に資本エクスポージャーを維持します。
コアロジック
- 初期設定
- 戦略開始時、
Start Volumeパラメーターと設定されたFirst Trade Sideを使って、ただちに成行注文を送信します。
Target (points)で指定された距離を使って、ストップロスとテイクプロフィットの保護注文を付与します。
- ポジション管理
- 一度に開けるポジションは1つだけです。戦略は、現在のポジションが保護注文または外部操作で完全に閉じるまで待ちます。
- 各決済後、戦略は取引方向を反転します(買い -> 売り、または売り -> 買い)。
- 最後の取引が損失だった場合、次の注文数量は前回ポジションサイズに
Lot Multiplierを掛けた値になります。それ以外の場合、数量はStart Volumeへ戻ります。
- サイクル継続
- 新しい数量と方向が決まると、次の成行注文を即座に送信し、交互マーチンゲールサイクルを継続します。
パラメーター
| 名前 |
説明 |
| Start Volume |
各勝ちサイクルの開始時に使う初期取引数量。 |
| Lot Multiplier |
損失取引後に適用する数量乗数。1より大きい必要があります。 |
| First Trade Side |
戦略セッション開始時の最初の取引方向。 |
| Target (points) |
ストップロスとテイクプロフィット注文の両方に使う価格ステップ距離。 |
| Order Comment |
生成される各成行注文に割り当てる任意のテキストタグ。 |
追加メモ
- 価格ステップ距離は
UnitTypes.Stepへ変換されStartProtectionへ渡されるため、ストップロスとテイクプロフィットは常に有効です。
- 数量調整は
NormalizeVolumeヘルパーを通じて、銘柄の数量ステップ、最小、最大境界を尊重します。
- 戦略はコネクターからの約定イベントを期待します。取引が一時停止したりコネクターがオフラインになった場合、取引が再び許可されるとマーチンゲールサイクルが再開します。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Reversing Martingale strategy: WMA crossover.
/// Buys when fast WMA crosses above slow WMA. Sells on cross below.
/// </summary>
public class ReversingMartingaleStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public ReversingMartingaleStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, fastVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class reversing_martingale_strategy(Strategy):
def __init__(self):
super(reversing_martingale_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetGreaterThanZero().SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetGreaterThanZero().SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(reversing_martingale_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
def OnStarted2(self, time):
super(reversing_martingale_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
fast = WeightedMovingAverage()
fast.Length = self._fast_period.Value
slow = WeightedMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return reversing_martingale_strategy()