GitHub で見る
Awesome Oscillator Trader戦略
Awesome Oscillator Trader戦略は、MetaTraderのエキスパートアドバイザー「AwesomeOscTrader」を直接変換したものです。Bill WilliamsのAwesome Oscillatorに、ボリンジャーバンド幅とストキャスティクスのフィルターを組み合わせ、深いモメンタム収縮後のブレイクアウトを狙います。元の推奨を反映し、EURUSDなど流動性の高いFXペアの単一シンボル・1時間足取引用に設計されています。
戦略は、ボリンジャーバンドのスプレッドが設定可能な範囲に入るのを待ち、ボラティリティが消えずに収縮したことを示します。そのスクイーズ中、Awesome Oscillatorヒストグラムは特徴的な5本バー反転パターンを形成する必要があります。ゼロ未満に留まる4本連続の下降ヒストグラムバーに続き、新しいバーがまだ負のまま上昇色へ変わる構造です。この構造が形成され、ストキャスティクスが売られ過ぎ水準を上抜けると、スクイーズが上方向に解けることを期待してロングを開きます。逆に、ゼロを上回る4本の正の上昇ヒストグラムバーと、まだ正のまま下降色へ変わる新バーに、ストキャスティクスが上側しきい値を下回る動きが組み合わさると、ショートエントリーを発動します。
ポジションはATRベースのストップ距離で保護されます。各バーで3期間Average True Rangeを読み取り、設定可能な係数を掛け、銘柄のティックサイズに基づいてpipsへ変換します。その値が初期ストップロスとテイクプロフィット目標の両方を定義し、MetaTrader版の対称的な決済ロジックを再現します。任意のトレーリングストップは、価格が設定pipsだけ有利に動くと保護水準を引き締めます。CloseOnReversalは、反対のAwesome Oscillatorパターンまたは色変更が現れたときにポジションを閉じます。利益フィルターにより、反転シグナルで勝ちトレードのみ、負けトレードのみ、またはすべてを閉じることができ、EAのProfitTypeClTrd動作を再現します。
取引ルール
- 時間軸: 既定は1時間足(完全に設定可能)。
- フィルター:
- ボリンジャーバンド幅は
BollingerSpreadLowerからBollingerSpreadUpper pipsの間である必要があります。
- Stochastic %Kは、ロングでは
StochasticLowerLevel、ショートではStochasticUpperLevelと比較されます。
- Awesome Oscillatorは、最新バーが色を変えつつゼロの反対側に残る5本バー反転構造を作る必要があり、正規化された大きさが
AoStrengthLimitを超える必要があります。
- エントリー:
- ロング: 上記条件に加え、現在バーが許可された取引時間窓内にある。
- ショート: 反対条件。
- 決済:
- ATR由来のストップロスとテイクプロフィットをエントリー時に対称設定。
- トレーリングストップ(
TrailingStopPips > 0の場合)は利益方向へ切り上げ/切り下げ。
CloseOnReversalとProfitFilterに応じて、反対シグナルまたはオシレーター色変更で任意に決済。
主要パラメーター
| パラメーター |
既定値 |
説明 |
CandleType |
1時間 |
すべての指標で使う時間軸。 |
BollingerPeriod |
20 |
ボリンジャーバンド・ボラティリティフィルターの期間。 |
BollingerSigma |
2.0 |
ボリンジャーバンドの標準偏差乗数。 |
BollingerSpreadLower |
24 pips |
取引に必要な最小バンドスプレッド。 |
BollingerSpreadUpper |
230 pips |
許容される最大バンドスプレッド。 |
AoFastPeriod / AoSlowPeriod |
4 / 28 |
Awesome Oscillatorの高速/低速期間。 |
AoStrengthLimit |
0.0 |
エントリー確認に必要な最小正規化AO大きさ。 |
StochasticKPeriod / StochasticDPeriod / StochasticSlowing |
1 / 4 / 1 |
MetaTrader既定値を再現するストキャスティクス長。 |
StochasticLowerLevel / StochasticUpperLevel |
12 / 21 |
シグナル確認用の売られ過ぎ/買われ過ぎしきい値。 |
EntryHour / OpenHours |
16 / 13 |
取引時間窓の開始時刻と長さ。EA同様に深夜跨ぎを処理します。 |
RiskPercent |
0.5% |
口座データが利用可能な場合のポジションサイズ計算用リスク率。 |
AtrMultiplier |
4.5 |
ストップ距離算出のため3期間ATRに適用する乗数。 |
TrailingStopPips |
40 pips |
任意トレーリングストップ距離(0で無効)。 |
ProfitFilter |
OnlyProfitable |
反転決済で、任意/利益のみ/損失のみのどれを閉じるかを選択。 |
MaxOpenOrders |
1 |
同時ポジション最大数(EAに合わせて1)。 |
実装メモ
- StockSharpの
BollingerBands、StochasticOscillator、AwesomeOscillator、AverageTrueRange、Highest指標を使い、手動指標計算はありません。
- AO値は直近100バーで正規化され、MetaTrader指標バッファーを模倣し、カスタムコードなしで色ロジックを再現します。
- ポジションサイズは、利用可能な場合
Security.StepVolume、Security.MinVolume、Security.MaxVolume、Security.StepPriceを尊重し、そうでなければ戦略の既定数量へフォールバックします。
- 保護水準は完全に戦略内で管理されます。ストップとテイクプロフィットのチェックは各確定ローソク足で実行され、ブローカー側注文を必要とせずEAのティックレベル管理に合わせます。
- コード内のコメントはすべて英語で、インデントはプロジェクトガイドラインに従いタブを使用します。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Awesome Oscillator Trader strategy: SMA 5/20 crossover (AO concept).
/// Buys when fast SMA crosses above slow SMA, sells on cross below.
/// </summary>
public class AwesomeOscillatorTraderStrategy : 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 AwesomeOscillatorTraderStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { 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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class awesome_oscillator_trader_strategy(Strategy):
def __init__(self):
super(awesome_oscillator_trader_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 34) \
.SetGreaterThanZero() \
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(awesome_oscillator_trader_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(awesome_oscillator_trader_strategy, self).OnStarted2(time)
self._fast_ind = SimpleMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = SimpleMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._prev_fast is not None and self._prev_slow is not None:
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 awesome_oscillator_trader_strategy()