ホーム
/
戦略のサンプル
GitHub で見る
Williams AO + AC戦略
概要
Williams AO + AC戦略 は、MetaTrader 4 エキスパート "Williams_AOAC" を StockSharp の高レベル戦略 API へ変換します。このアプローチは、Bill Williams の複数のツールを組み合わせ、時間足チャート (デフォルト時間枠) で momentum の急増を見つけます。
Bollinger Bandフィルター - バンド幅が設定可能なポイント範囲内にある場合にのみ取引し、横ばい市場と過度なボラティリティの両方を避けやすくします。
Relative Strength Index確認 - RSI はロングでは強気しきい値を上回り、ショートでは弱気しきい値を下回る必要があります。
Awesome Oscillatorのゼロラインクロス - オシレーターは取引方向にゼロ軸をクロスする必要があり、momentum の変化を示します。
Accelerator Oscillatorの加速 - 直近 3 つの Accelerator 値がゼロの同じ側にあり、最新バーがその動きを伸ばしている必要があり、加速を確認します。
取引セッションフィルター - エントリーは、日の時刻で表される設定可能な時間窓内でのみ許可されます。
確定した各ローソク足で、戦略は Bind パイプラインから渡されるインジケーター値を処理します。すべてのフィルターがそろうと、必要に応じて反対ポジションを閉じ、要求されたロットサイズで新しい成行注文を開きます。stop-loss と take-profit は価格ポイントの距離で適用され、任意の trailing stop は取引が利益化した後に保護ストップを引き締めます。
エントリールール
ロング条件
Bollinger スプレッド (上側バンドから下側バンドを引き、ポイントに変換したもの) が BollingerSpreadLower と BollingerSpreadUpper の間にあります。
RSI 読み取り値が RsiBuyThreshold より厳密に大きいです。
Awesome Oscillator が現在バーでマイナスからプラスへクロスします。
直近 3 本のローソク足の Accelerator Oscillator 値がすべてプラスで、最新値が前の値より高く、強気 momentum の増加を示します。
現在バーの始値時刻が、EntryHour に始まり TradingWindowHours 時間続く取引窓内にあります (必要なら日付をまたぎます)。
戦略はまだロングポジションを持っていません (フラットまたはショートの可能性があります)。
ロジックが満たされると、戦略はすべてのショートエクスポージャーを閉じ、TradeVolume でロング成行注文を開き、設定された stop-loss / take-profit 距離を適用します。取引が少なくとも TrailingStopPoints だけ有利に動いた後、trailing stop の追跡が始まります。
ショート条件
Bollinger スプレッドが許可範囲内にあります。
RSI 読み取り値が RsiSellThreshold より厳密に小さいです。
Awesome Oscillator が現在バーでプラスからマイナスへクロスします。
直近 3 本のローソク足の Accelerator Oscillator 値がすべてマイナスで、最新値が前の値より低く、弱気圧力の増加を示します。
ローソク足の始値時刻が取引セッション窓内にあります。
戦略はまだショートポジションを持っていません (フラットまたはロングの可能性があります)。
発動すると、モジュールはロングエクスポージャーを閉じ、TradeVolume でショート成行注文に入り、保護注文を再割り当てします。
エグジット管理
Take-profit - TakeProfitPoints がゼロより大きい場合、エントリー価格からその数の価格ポイントだけ離れた利益目標を各新規ポジションに付与します。
Stop-loss - StopLossPoints がゼロより大きい場合、エントリー価格を基準に固定ストップを適用します。
Trailing stop - TrailingStopPoints がゼロより大きい場合、利益が trailing 距離を超えると stop-loss を市場へ近づけます。ロング取引ではストップを Close - TrailingStopPoints * pip へ引き上げ、ショートでは Close + TrailingStopPoints * pip へ引き下げます。trailing は一方向です。ストップは戻りません。
ユーザーによる手動ポジション変更は尊重されます。trailing ロジックは、エンジンが報告する現在の集計ポジションに反応します。
パラメーター
名前
説明
デフォルト
CandleType
計算に使う主要ローソク足系列。
1 時間足
BollingerPeriod
Bollinger Bands のルックバック期間。
20
BollingerDeviation
標準偏差乗数。
2.0
BollingerSpreadLower
取引を有効にするために必要な最小バンド幅 (ポイント)。
40
BollingerSpreadUpper
取引に許可される最大バンド幅 (ポイント)。
210
AoFastPeriod
Awesome Oscillator の短期期間。
11
AoSlowPeriod
Awesome Oscillator の長期期間。
40
RsiPeriod
RSI 計算長。
20
RsiBuyThreshold
ロング取引の最小 RSI 値。
46
RsiSellThreshold
ショート取引の最大 RSI 値。
40
EntryHour
取引窓が始まる時刻 (0-23)。
0
TradingWindowHours
許可される取引窓の長さ (時間)。0 は開始時刻のみを保持します。
20
TradeVolume
各新規ポジションのロットサイズ。
0.01
StopLossPoints
価格ポイント単位の stop-loss 距離。
60
TakeProfitPoints
価格ポイント単位の take-profit 距離。
90
TrailingStopPoints
価格ポイント単位の trailing stop 距離。
30
追加の注意事項
Accelerator Oscillator 値は、現在の AO 読み取り値から Awesome Oscillator の 5 期間単純移動平均を引くことで内部的に導出され、元エキスパートが使用した MetaTrader 実装と一致します。
バンドスプレッド計算は商品の PriceStep に依存します。利用できない場合、戦略は生の価格差にフォールバックします。
EntryHour + TradingWindowHours が 23 を超える場合、取引セッション窓は日付をまたぎ、MetaTrader の時間フィルターを再現します。
戦略は新しいポジションを開く前に反対エクスポージャーを自動的に閉じ、元の MQL4 コードの単一注文制限を再現します。
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;
public class WilliamsAoAcStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public WilliamsAoAcStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class williams_ao_ac_strategy(Strategy):
def __init__(self):
super(williams_ao_ac_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(williams_ao_ac_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(williams_ao_ac_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return williams_ao_ac_strategy()