GitHub で見る
Bulls & Bears Power 平均戦略
概要
MQL/22016にあるMetaTrader 5エキスパートMySystem.mq5のポート。
- ローソク足の高値/安値とEMAから計算されたElder Bulls PowerとBears Powerの値を平均することでモメンタムリバーサルを検出します。
- 平均がまだゼロ以下にありながら増加する場合(弱気圧力が薄れている)にロング、平均がまだゼロ以上にありながら減少する場合(強気圧力が薄れている)にショートに参入します。
- 一度に1つのオープンポジションのために設計され、ストップロスとテイクプロフィットはオプションでピップで表現されます。
インジケーターのロジック
| コンポーネント |
説明 |
| Exponential Moving Average(EMA) |
ローソク足のクローズ価格に適用されます。MaPeriodパラメーターが平滑化ウィンドウを制御します(デフォルト5)。 |
| Bulls Power(派生) |
High - EMAとして計算されます。EMAに対する強気の強さを測定します。 |
| Bears Power(派生) |
Low - EMAとして計算されます。EMAに対する弱気の強さを測定します。 |
| 平均パワー |
(Bulls Power + Bears Power) / 2。この合成オシレーターはモメンタムの変化を検出するために前の値と比較されます。 |
戦略は最後の2つの完成したローソク足を評価します。新しいトレードはバー内のノイズを避けるためにローソク足が完全に完成した場合にのみ評価されます。
エントリールール
- EMAが完全に形成されるまで待ちます(つまり、少なくとも
MaPeriod個のローソク足を処理した)。
- その高値/安値とEMA値を使用して、ちょうどクローズしたローソク足のBulls PowerとBears Powerを計算します。
- 両方の力を平均して現在のオシレーター読み取り値を取得します。
- 前の平均と比較します:
- ロングセットアップ: 前の平均
<現在の平均 かつ現在の平均< 0。既存のポジションがなければロングに参入します。
- ショートセットアップ: 前の平均
>現在の平均 かつ現在の平均> 0。フラットならショートに参入します。
- トレードに入ったら、オプションの保護注文または手動管理に頼ります。アルゴリズムはストップロス/テイクプロフィット以外のエグジットシグナルを生成しません。
リスク管理
StopLossPips: ピップ単位のオプションの絶対ストップ距離(0でストップを無効化)。インストゥルメントのPriceStepを使用して変換されます。
TakeProfitPips: ピップ単位のオプションの絶対利益目標(0で目標を無効化)。
- 保護注文はマーケット実行で
StartProtectionを通じてポジションが開かれるとすぐに登録されます。
パラメーター
| 名前 |
デフォルト |
説明 |
OrderVolume |
0.1 |
マーケットエントリーの注文サイズ。 |
StopLossPips |
15 |
ピップ単位のストップロス距離。0に設定すると無効化。 |
TakeProfitPips |
95 |
ピップ単位のテイクプロフィット距離。0に設定すると無効化。 |
MaPeriod |
5 |
Bulls/Bears Power計算に使用されるEMAの長さ。 |
CandleType |
1時間の時間軸 |
すべての計算に使用されるローソク足シリーズ(データフィードに合わせて変更)。 |
使用上の注意
- 戦略をインストゥルメントに付属し、
CandleTypeが意図した時間軸と一致することを確認します。
- ブローカーの要件に合わせて
OrderVolume、StopLossPips、TakeProfitPipsを調整します。
- 戦略を実行します。ローソク足を自動的に購読し、EMAを更新し、適格なシグナルでマーケット注文を発行します。
- 一度に1つのポジションのみ存在できます。トレードがアクティブな場合、保護注文がポジションをクローズするか手動でクローズされるまで新しいシグナルは無視されます。
- 元のMQLバージョンが
InpBarCurrent = 1を使用していたため、このポートは常に完全にクローズしたローソク足で動作し、連続する値を比較します。バー内の再計算は行われません。
元のMQLエキスパートとの違い
- 手動バッファアクセスではなくローソク足購読とインジケーターバインディングを持つStockSharpハイレベル
Strategy APIを使用します。
- 手動の桁調整ではなく
PriceStepからピップを自動的に導出します。
- 元のコメントアウトされた注文管理をスキップし、組み込みのポジション保護に依存します。
- ポジションが存在する間シグナルを無視することでソースの単一ポジション制約を維持します。
テストの推奨事項
- Bulls/Bears計算の精度を確保するために高値/安値の価格を含む履歴データで意図したシンボル/時間軸でバックテストします。
- ライブ実行前にブローカーのティックサイズとボリュームステップで保護注文の動作を検証します。
- インストゥルメントのボラティリティに感度を適応させるために異なる
MaPeriod値を実験します。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bulls Bears Power Average strategy. Uses EMA with bulls/bears power crossover.
/// </summary>
public class BullsBearsPowerAverageStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal? _prevPower;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public BullsBearsPowerAverageStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 13).SetGreaterThanZero().SetDisplay("EMA Period", "EMA lookback for power calc", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevPower = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevPower = null;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished) return;
var bullsPower = candle.HighPrice - emaVal;
var bearsPower = candle.LowPrice - emaVal;
var avgPower = (bullsPower + bearsPower) / 2m;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevPower = avgPower; return; }
if (_prevPower == null) { _prevPower = avgPower; return; }
if (_prevPower.Value < 0m && avgPower >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevPower.Value > 0m && avgPower <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevPower = avgPower;
}
}
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 bulls_bears_power_average_strategy(Strategy):
"""
Bulls Bears Power Average strategy. Uses EMA with bulls/bears power crossover.
"""
def __init__(self):
super(bulls_bears_power_average_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ema_period = self.Param("EmaPeriod", 13) \
.SetDisplay("EMA Period", "EMA lookback for power calc", "Indicators")
self._prev_power = None
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def ema_period(self):
return self._ema_period.Value
@ema_period.setter
def ema_period(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(bulls_bears_power_average_strategy, self).OnReseted()
self._prev_power = None
def OnStarted2(self, time):
super(bulls_bears_power_average_strategy, self).OnStarted2(time)
self._prev_power = None
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def on_process(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
bulls_power = candle.HighPrice - ema_val
bears_power = candle.LowPrice - ema_val
avg_power = (bulls_power + bears_power) / 2.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_power = avg_power
return
if self._prev_power is None:
self._prev_power = avg_power
return
if self._prev_power < 0.0 and avg_power >= 0.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_power > 0.0 and avg_power <= 0.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_power = avg_power
def CreateClone(self):
return bulls_bears_power_average_strategy()