加重オシレーター直接戦略
概要
この戦略はMetaTraderエキスパート Exp_WeightOscillator_Direct をStockSharpの高レベルAPI内で再現します。4つの古典的なオシレーター(RSI、Money Flow Index、Williams %R、DeMarker)を単一の加重コンポジットにブレンドします。コンポジットシグナルは設定可能な移動平均によって平滑化され、モメンタムのスイングを検出するために使用されます。コンポジットが上昇すると、戦略が「Direct」モードで動作する場合はロング取引を開く(またはショートをクローズする)一方、「Against」モードでは逆張り取引のためにロジックを反転させます。
インジケーターパイプライン
- Relative Strength Index (RSI) – 正規化された0..100スケール。
- Money Flow Index (MFI) – 0..100の範囲の流動性に敏感なオシレーター。
- Williams %R (WPR) – 0..100スケールに合わせるために+100だけシフト。
- DeMarker – 他のオシレーターに合わせるために100倍。
- 平滑化平均 – サポートされている移動平均の1つ(シンプル、指数、スムーズ、加重、Jurik、Kaufman)。
- コンポジットオシレーター – ノイズを除去するために平滑化された正規化入力の加重平均。
加重オシレーター値は完成した各ローソク足のために保存されます。シグナルは最後の3つの保存された値を分析し、元のエキスパートの動作を模倣するためにSignal Barパラメーターを介してオプションで最新のバーの数をスキップします。
取引ロジック
- すべてのインジケーターと平滑化移動平均が完全に形成されるまで待機します。
- 現在の完成したバーの平滑化コンポジットオシレーターを計算し、履歴に追加します。
- 3つの履歴値を取得します:
current、previous、prior、インデックスはSignal Barによって制御されます。 - 傾斜変化を検出します:
- 上昇
previous < priorかつcurrent > previousの場合。 - 下降
previous > priorかつcurrent < previousの場合。
- 上昇
- 選択したTrend Modeに応じて:
- Direct:傾斜に沿って取引(
上昇→ ロングシグナル、下降→ ショートシグナル)。 - Against:傾斜に逆らって取引(
上昇→ ショート、下降→ ロング)。
- Direct:傾斜に沿って取引(
- エントリー/エグジットスイッチを適用します:
- 対応するCloseスイッチが有効な場合、反対方向のエクスポージャーをクローズします。
- 各Allowスイッチが有効な場合のみ新しいポジションを開きます。注文サイズは
Volume + |Position|で、戦略が単一の成行注文でショートからロング(またはその逆)に切り替えられるようにします。
- オプションのストップロスとテイクプロフィットの保護は、価格ステップで表された距離を使用して
StartProtectionを通じてアクティブ化されます。
パラメーター
| グループ | 名前 | 説明 |
|---|---|---|
| General | Candle Type | データ購読とインジケーター計算の時間軸。 |
| Trading | Trend Mode | Directはオシレーターの傾斜に従い、Againstは逆張り取引をします。 |
| Trading | Signal Bar | スキップする最新の閉じたバーの数(1 = 最後に閉じたバー)。 |
| Oscillator | RSI / MFI / WPR / DeMarker Weight | 加重ブレンドにおける各オシレーターの相対的な貢献度。ゼロはコンポーネントを無効にします。 |
| Oscillator | RSI / MFI / WPR / DeMarker Period | 各オシレーターのルックバック長さ。 |
| Oscillator | Smoothing Method | コンポジットに適用される移動平均(シンプル、指数、スムーズ、加重、Jurik、Kaufman)。 |
| Oscillator | Smoothing Length | 平滑化平均の期間。 |
| Risk Management | Stop Loss Points | 価格ステップでの距離;0でストップを無効にします。 |
| Risk Management | Take Profit Points | 価格ステップでの距離;0で目標を無効にします。 |
| Trading | Allow Long/Short Entries | 新しいロング/ショートポジションの開設を有効または無効にします。 |
| Trading | Close Shorts/Longs on Signal | 反対のシグナルが来たときに既存のエクスポージャーをクローズすることを許可します。 |
すべての数値パラメーターはStrategyParamオブジェクトとして公開され、StockSharp Designer内での最適化が可能です。
使用上の注意
- 戦略を開始する前にベースの
Volumeプロパティを設定します。ポジションを反転するときに成行注文が自動的にスケールします。 - 戦略は
GetWorkingSecurities()が返す1つのローソク足シリーズのみを購読します。 - 保護ストップはポイント距離を絶対価格値に変換するために銘柄の
PriceStepを使用します。 - Trend Modeが
Againstに設定されている場合、シグナルの極性のみが変わります;他のすべてのメカニクスは元のエキスパートアドバイザーと同一です。 - Williams %RとDeMarkerは元のインジケーターロジックに合わせてRSI/MFIと同じ0..100スケールを共有するように正規化されます。
MQLエキスパートとの違い
- 元のインジケーターは追加の平滑化タイプ(
ParMA、JurX、VIDYA、T3)をサポートしていました。StockSharpでは戦略は高品質な対応物(JurikとKaufman)を提供し、互換性のためにJurikをデフォルトとして使用します。 - Money Flow Indexは常にローソク足の集計ボリュームを使用します。MetaTraderはティックボリュームと実際のボリュームを切り替えられましたが、この選択はStockSharpではデータソースに依存します。
- リスク管理はポイントベースのリクエストの代わりに
StartProtection(価格ステップベース)を通じて実装されますが、PriceStepが銘柄の契約サイズと一致する場合は同じ動作を提供します。
開始方法
- 設定されたローソク足タイプをサポートするポートフォリオとセキュリティに戦略をアタッチします。
- インジケーターの重み/期間を調整し、エントリースイッチを有効または無効にします。
- 銘柄のボラティリティに最も適した平滑化メソッドと長さを選択します。
- 保護が必要な場合は価格ステップでストップロス/テイクプロフィット距離を設定します。
- 戦略を実行します;シグナルは完成したローソク足のみで実行され、決定論的な動作を保証します。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trading strategy that combines several oscillators into a weighted composite signal.
/// </summary>
public class WeightOscillatorDirectStrategy : Strategy
{
/// <summary>
/// Defines how the strategy reacts to the oscillator slope.
/// </summary>
public enum WeightOscillatorTrendModes
{
/// <summary>
/// Trade in the direction of the oscillator slope.
/// </summary>
Direct,
/// <summary>
/// Trade against the oscillator slope.
/// </summary>
Against,
}
/// <summary>
/// Available smoothing methods for the blended oscillator.
/// </summary>
public enum WeightOscillatorSmoothingMethods
{
/// <summary>
/// Simple moving average.
/// </summary>
Simple,
/// <summary>
/// Exponential moving average.
/// </summary>
Exponential,
/// <summary>
/// Smoothed (RMA) moving average.
/// </summary>
Smoothed,
/// <summary>
/// Linear weighted moving average.
/// </summary>
Weighted,
/// <summary>
/// Jurik moving average.
/// </summary>
Jurik,
/// <summary>
/// Kaufman adaptive moving average.
/// </summary>
Kaufman,
}
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<WeightOscillatorTrendModes> _trendMode;
private readonly StrategyParam<int> _signalBar;
private readonly StrategyParam<decimal> _rsiWeight;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _mfiWeight;
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<decimal> _wprWeight;
private readonly StrategyParam<int> _wprPeriod;
private readonly StrategyParam<decimal> _deMarkerWeight;
private readonly StrategyParam<int> _deMarkerPeriod;
private readonly StrategyParam<WeightOscillatorSmoothingMethods> _smoothingMethod;
private readonly StrategyParam<int> _smoothingLength;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private readonly StrategyParam<bool> _buyOpenEnabled;
private readonly StrategyParam<bool> _sellOpenEnabled;
private readonly StrategyParam<bool> _buyCloseEnabled;
private readonly StrategyParam<bool> _sellCloseEnabled;
private RelativeStrengthIndex _rsi = null!;
private MoneyFlowIndex _mfi = null!;
private WilliamsR _wpr = null!;
private DeMarker _deMarker = null!;
private IIndicator _smoothing = null!;
private readonly List<decimal> _oscillatorHistory = new();
/// <summary>
/// Initializes a new instance of the <see cref="WeightOscillatorDirectStrategy"/> class.
/// </summary>
public WeightOscillatorDirectStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for indicator calculations", "General");
_trendMode = Param(nameof(TrendMode), WeightOscillatorTrendModes.Direct)
.SetDisplay("Trend Mode", "Trade with the oscillator slope or against it", "Trading");
_signalBar = Param(nameof(SignalBar), 2)
.SetDisplay("Signal Bar", "Number of closed bars to skip before evaluating signals", "Trading")
.SetRange(1, 5)
;
_rsiWeight = Param(nameof(RsiWeight), 1m)
.SetDisplay("RSI Weight", "Weight of RSI in the composite score", "Oscillator")
.SetRange(0m, 5m)
;
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "Number of bars used for RSI", "Oscillator")
.SetRange(2, 200)
;
_mfiWeight = Param(nameof(MfiWeight), 1m)
.SetDisplay("MFI Weight", "Weight of Money Flow Index", "Oscillator")
.SetRange(0m, 5m)
;
_mfiPeriod = Param(nameof(MfiPeriod), 14)
.SetDisplay("MFI Period", "Number of bars used for MFI", "Oscillator")
.SetRange(2, 200)
;
_wprWeight = Param(nameof(WprWeight), 1m)
.SetDisplay("WPR Weight", "Weight of Williams %R", "Oscillator")
.SetRange(0m, 5m)
;
_wprPeriod = Param(nameof(WprPeriod), 14)
.SetDisplay("WPR Period", "Number of bars used for Williams %R", "Oscillator")
.SetRange(2, 200)
;
_deMarkerWeight = Param(nameof(DeMarkerWeight), 1m)
.SetDisplay("DeMarker Weight", "Weight of DeMarker oscillator", "Oscillator")
.SetRange(0m, 5m)
;
_deMarkerPeriod = Param(nameof(DeMarkerPeriod), 14)
.SetDisplay("DeMarker Period", "Number of bars used for DeMarker", "Oscillator")
.SetRange(2, 200)
;
_smoothingMethod = Param(nameof(SmoothingMethod), WeightOscillatorSmoothingMethods.Jurik)
.SetDisplay("Smoothing Method", "Moving average applied to the blended oscillator", "Oscillator");
_smoothingLength = Param(nameof(SmoothingLength), 10)
.SetDisplay("Smoothing Length", "Length of the smoothing moving average", "Oscillator")
.SetRange(1, 200)
;
_stopLossPoints = Param(nameof(StopLossPoints), 1000)
.SetDisplay("Stop Loss Points", "Protective stop in price steps (0 disables)", "Risk Management")
.SetRange(0, 10000)
;
_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000)
.SetDisplay("Take Profit Points", "Profit target in price steps (0 disables)", "Risk Management")
.SetRange(0, 20000)
;
_buyOpenEnabled = Param(nameof(BuyOpenEnabled), true)
.SetDisplay("Allow Long Entries", "Enable opening long positions", "Trading");
_sellOpenEnabled = Param(nameof(SellOpenEnabled), true)
.SetDisplay("Allow Short Entries", "Enable opening short positions", "Trading");
_buyCloseEnabled = Param(nameof(BuyCloseEnabled), true)
.SetDisplay("Close Shorts on Long Signal", "Allow closing shorts when a long signal appears", "Trading");
_sellCloseEnabled = Param(nameof(SellCloseEnabled), true)
.SetDisplay("Close Longs on Short Signal", "Allow closing longs when a short signal appears", "Trading");
}
/// <summary>
/// Candle type used for the calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Defines whether the strategy trades with or against the oscillator direction.
/// </summary>
public WeightOscillatorTrendModes TrendMode
{
get => _trendMode.Value;
set => _trendMode.Value = value;
}
/// <summary>
/// Number of closed bars to skip when evaluating the composite oscillator.
/// </summary>
public int SignalBar
{
get => _signalBar.Value;
set => _signalBar.Value = value;
}
/// <summary>
/// Weight assigned to RSI.
/// </summary>
public decimal RsiWeight
{
get => _rsiWeight.Value;
set => _rsiWeight.Value = value;
}
/// <summary>
/// RSI lookback period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Weight assigned to MFI.
/// </summary>
public decimal MfiWeight
{
get => _mfiWeight.Value;
set => _mfiWeight.Value = value;
}
/// <summary>
/// MFI lookback period.
/// </summary>
public int MfiPeriod
{
get => _mfiPeriod.Value;
set => _mfiPeriod.Value = value;
}
/// <summary>
/// Weight assigned to Williams %R.
/// </summary>
public decimal WprWeight
{
get => _wprWeight.Value;
set => _wprWeight.Value = value;
}
/// <summary>
/// Williams %R lookback period.
/// </summary>
public int WprPeriod
{
get => _wprPeriod.Value;
set => _wprPeriod.Value = value;
}
/// <summary>
/// Weight assigned to DeMarker oscillator.
/// </summary>
public decimal DeMarkerWeight
{
get => _deMarkerWeight.Value;
set => _deMarkerWeight.Value = value;
}
/// <summary>
/// DeMarker lookback period.
/// </summary>
public int DeMarkerPeriod
{
get => _deMarkerPeriod.Value;
set => _deMarkerPeriod.Value = value;
}
/// <summary>
/// Smoothing method applied to the blended oscillator.
/// </summary>
public WeightOscillatorSmoothingMethods SmoothingMethod
{
get => _smoothingMethod.Value;
set => _smoothingMethod.Value = value;
}
/// <summary>
/// Length of the smoothing moving average.
/// </summary>
public int SmoothingLength
{
get => _smoothingLength.Value;
set => _smoothingLength.Value = value;
}
/// <summary>
/// Stop loss distance expressed in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take profit distance expressed in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Enables opening long positions.
/// </summary>
public bool BuyOpenEnabled
{
get => _buyOpenEnabled.Value;
set => _buyOpenEnabled.Value = value;
}
/// <summary>
/// Enables opening short positions.
/// </summary>
public bool SellOpenEnabled
{
get => _sellOpenEnabled.Value;
set => _sellOpenEnabled.Value = value;
}
/// <summary>
/// Enables closing short positions on a long signal.
/// </summary>
public bool BuyCloseEnabled
{
get => _buyCloseEnabled.Value;
set => _buyCloseEnabled.Value = value;
}
/// <summary>
/// Enables closing long positions on a short signal.
/// </summary>
public bool SellCloseEnabled
{
get => _sellCloseEnabled.Value;
set => _sellCloseEnabled.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_oscillatorHistory.Clear();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_mfi = new MoneyFlowIndex { Length = MfiPeriod };
_wpr = new WilliamsR { Length = WprPeriod };
_deMarker = new DeMarker { Length = DeMarkerPeriod };
_smoothing = CreateSmoothingIndicator();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, _mfi, _wpr, _deMarker, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
var step = Security?.PriceStep ?? 1m;
var takeProfit = TakeProfitPoints > 0 ? new Unit(TakeProfitPoints * step, UnitTypes.Absolute) : null;
var stopLoss = StopLossPoints > 0 ? new Unit(StopLossPoints * step, UnitTypes.Absolute) : null;
StartProtection(stopLoss, takeProfit);
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal mfiValue, decimal wprValue, decimal deMarkerValue)
{
if (candle.State != CandleStates.Finished)
return;
var totalWeight = RsiWeight + MfiWeight + WprWeight + DeMarkerWeight;
if (totalWeight <= 0)
{
this.LogInfo("Total oscillator weight must be positive to generate signals.");
return;
}
// Williams %R is negative in StockSharp, so shift it into the 0..100 range.
var normalizedWpr = wprValue + 100m;
// DeMarker returns 0..1; scale to match other oscillators.
var normalizedDeMarker = deMarkerValue * 100m;
var blended = (RsiWeight * rsiValue + MfiWeight * mfiValue + WprWeight * normalizedWpr + DeMarkerWeight * normalizedDeMarker) / totalWeight;
var smoothedValue = _smoothing.Process(new DecimalIndicatorValue(_smoothing, blended, candle.OpenTime) { IsFinal = true });
if (!smoothedValue.IsFinal)
return;
var oscillator = smoothedValue.ToDecimal();
_oscillatorHistory.Add(oscillator);
if (_oscillatorHistory.Count > 512)
_oscillatorHistory.RemoveAt(0);
var requiredCount = SignalBar + 2;
if (_oscillatorHistory.Count < requiredCount)
return;
var current = GetHistoryValue(SignalBar);
var previous = GetHistoryValue(SignalBar + 1);
var prior = GetHistoryValue(SignalBar + 2);
// Rising when slope turns up over the last two steps.
var rising = previous < prior && current > previous;
// Falling when slope turns down over the last two steps.
var falling = previous > prior && current < previous;
bool longSignal;
bool shortSignal;
if (TrendMode == WeightOscillatorTrendModes.Direct)
{
longSignal = rising;
shortSignal = falling;
}
else
{
longSignal = falling;
shortSignal = rising;
}
if (longSignal)
{
if (BuyCloseEnabled && Position < 0)
{
BuyMarket(Math.Abs(Position));
}
if (BuyOpenEnabled && Position <= 0)
{
BuyMarket(Volume > 0m ? Volume : 1m);
}
}
if (shortSignal)
{
if (SellCloseEnabled && Position > 0)
{
SellMarket(Math.Abs(Position));
}
if (SellOpenEnabled && Position >= 0)
{
SellMarket(Volume > 0m ? Volume : 1m);
}
}
}
private IIndicator CreateSmoothingIndicator()
{
return SmoothingMethod switch
{
WeightOscillatorSmoothingMethods.Simple => new SMA { Length = SmoothingLength },
WeightOscillatorSmoothingMethods.Exponential => new EMA { Length = SmoothingLength },
WeightOscillatorSmoothingMethods.Smoothed => new SmoothedMovingAverage { Length = SmoothingLength },
WeightOscillatorSmoothingMethods.Weighted => new WeightedMovingAverage { Length = SmoothingLength },
WeightOscillatorSmoothingMethods.Kaufman => new KaufmanAdaptiveMovingAverage { Length = SmoothingLength },
_ => new JurikMovingAverage { Length = SmoothingLength },
};
}
private decimal GetHistoryValue(int shift)
{
return _oscillatorHistory[_oscillatorHistory.Count - shift];
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import (RelativeStrengthIndex, MoneyFlowIndex, WilliamsR, DeMarker,
SimpleMovingAverage, ExponentialMovingAverage, SmoothedMovingAverage,
WeightedMovingAverage, JurikMovingAverage, KaufmanAdaptiveMovingAverage)
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
TREND_DIRECT = 0
TREND_AGAINST = 1
SMOOTH_SIMPLE = 0
SMOOTH_EXPONENTIAL = 1
SMOOTH_SMOOTHED = 2
SMOOTH_WEIGHTED = 3
SMOOTH_JURIK = 4
SMOOTH_KAUFMAN = 5
class weight_oscillator_direct_strategy(Strategy):
def __init__(self):
super(weight_oscillator_direct_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._trend_mode = self.Param("TrendMode", TREND_DIRECT)
self._signal_bar = self.Param("SignalBar", 2)
self._rsi_weight = self.Param("RsiWeight", 1.0)
self._rsi_period = self.Param("RsiPeriod", 14)
self._mfi_weight = self.Param("MfiWeight", 1.0)
self._mfi_period = self.Param("MfiPeriod", 14)
self._wpr_weight = self.Param("WprWeight", 1.0)
self._wpr_period = self.Param("WprPeriod", 14)
self._demarker_weight = self.Param("DeMarkerWeight", 1.0)
self._demarker_period = self.Param("DeMarkerPeriod", 14)
self._smoothing_method = self.Param("SmoothingMethod", SMOOTH_JURIK)
self._smoothing_length = self.Param("SmoothingLength", 10)
self._stop_loss_points = self.Param("StopLossPoints", 1000)
self._take_profit_points = self.Param("TakeProfitPoints", 2000)
self._buy_open_enabled = self.Param("BuyOpenEnabled", True)
self._sell_open_enabled = self.Param("SellOpenEnabled", True)
self._buy_close_enabled = self.Param("BuyCloseEnabled", True)
self._sell_close_enabled = self.Param("SellCloseEnabled", True)
self._oscillator_history = []
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def TrendMode(self):
return self._trend_mode.Value
@TrendMode.setter
def TrendMode(self, value):
self._trend_mode.Value = value
@property
def SignalBar(self):
return self._signal_bar.Value
@SignalBar.setter
def SignalBar(self, value):
self._signal_bar.Value = value
@property
def RsiWeight(self):
return self._rsi_weight.Value
@RsiWeight.setter
def RsiWeight(self, value):
self._rsi_weight.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def MfiWeight(self):
return self._mfi_weight.Value
@MfiWeight.setter
def MfiWeight(self, value):
self._mfi_weight.Value = value
@property
def MfiPeriod(self):
return self._mfi_period.Value
@MfiPeriod.setter
def MfiPeriod(self, value):
self._mfi_period.Value = value
@property
def WprWeight(self):
return self._wpr_weight.Value
@WprWeight.setter
def WprWeight(self, value):
self._wpr_weight.Value = value
@property
def WprPeriod(self):
return self._wpr_period.Value
@WprPeriod.setter
def WprPeriod(self, value):
self._wpr_period.Value = value
@property
def DeMarkerWeight(self):
return self._demarker_weight.Value
@DeMarkerWeight.setter
def DeMarkerWeight(self, value):
self._demarker_weight.Value = value
@property
def DeMarkerPeriod(self):
return self._demarker_period.Value
@DeMarkerPeriod.setter
def DeMarkerPeriod(self, value):
self._demarker_period.Value = value
@property
def SmoothingMethod(self):
return self._smoothing_method.Value
@SmoothingMethod.setter
def SmoothingMethod(self, value):
self._smoothing_method.Value = value
@property
def SmoothingLength(self):
return self._smoothing_length.Value
@SmoothingLength.setter
def SmoothingLength(self, value):
self._smoothing_length.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
@property
def BuyOpenEnabled(self):
return self._buy_open_enabled.Value
@BuyOpenEnabled.setter
def BuyOpenEnabled(self, value):
self._buy_open_enabled.Value = value
@property
def SellOpenEnabled(self):
return self._sell_open_enabled.Value
@SellOpenEnabled.setter
def SellOpenEnabled(self, value):
self._sell_open_enabled.Value = value
@property
def BuyCloseEnabled(self):
return self._buy_close_enabled.Value
@BuyCloseEnabled.setter
def BuyCloseEnabled(self, value):
self._buy_close_enabled.Value = value
@property
def SellCloseEnabled(self):
return self._sell_close_enabled.Value
@SellCloseEnabled.setter
def SellCloseEnabled(self, value):
self._sell_close_enabled.Value = value
def _create_smoothing_indicator(self):
method = int(self.SmoothingMethod)
length = int(self.SmoothingLength)
if method == SMOOTH_SIMPLE:
ind = SimpleMovingAverage()
ind.Length = length
return ind
elif method == SMOOTH_EXPONENTIAL:
ind = ExponentialMovingAverage()
ind.Length = length
return ind
elif method == SMOOTH_SMOOTHED:
ind = SmoothedMovingAverage()
ind.Length = length
return ind
elif method == SMOOTH_WEIGHTED:
ind = WeightedMovingAverage()
ind.Length = length
return ind
elif method == SMOOTH_KAUFMAN:
ind = KaufmanAdaptiveMovingAverage()
ind.Length = length
return ind
else:
ind = JurikMovingAverage()
ind.Length = length
return ind
def OnStarted2(self, time):
super(weight_oscillator_direct_strategy, self).OnStarted2(time)
self._oscillator_history = []
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
self._mfi = MoneyFlowIndex()
self._mfi.Length = self.MfiPeriod
self._wpr = WilliamsR()
self._wpr.Length = self.WprPeriod
self._demarker = DeMarker()
self._demarker.Length = self.DeMarkerPeriod
self._smoothing = self._create_smoothing_indicator()
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._mfi, self._wpr, self._demarker, self.ProcessCandle).Start()
step = self.Security.PriceStep if self.Security is not None and self.Security.PriceStep is not None else Decimal(1)
if step <= Decimal(0):
step = Decimal(1)
tp = int(self.TakeProfitPoints)
sl = int(self.StopLossPoints)
tp_unit = Unit(Decimal(tp) * step, UnitTypes.Absolute) if tp > 0 else None
sl_unit = Unit(Decimal(sl) * step, UnitTypes.Absolute) if sl > 0 else None
self.StartProtection(sl_unit, tp_unit)
def ProcessCandle(self, candle, rsi_value, mfi_value, wpr_value, demarker_value):
if candle.State != CandleStates.Finished:
return
rsi_w = float(self.RsiWeight)
mfi_w = float(self.MfiWeight)
wpr_w = float(self.WprWeight)
dm_w = float(self.DeMarkerWeight)
total_weight = rsi_w + mfi_w + wpr_w + dm_w
if total_weight <= 0.0:
return
rsi_val = float(rsi_value)
mfi_val = float(mfi_value)
wpr_val = float(wpr_value)
dm_val = float(demarker_value)
normalized_wpr = wpr_val + 100.0
normalized_dm = dm_val * 100.0
blended = (rsi_w * rsi_val + mfi_w * mfi_val + wpr_w * normalized_wpr + dm_w * normalized_dm) / total_weight
smoothed_result = process_float(self._smoothing, Decimal(blended), candle.OpenTime, True)
if not smoothed_result.IsFinal:
return
oscillator = float(smoothed_result)
self._oscillator_history.append(oscillator)
if len(self._oscillator_history) > 512:
self._oscillator_history.pop(0)
signal_bar = int(self.SignalBar)
required_count = signal_bar + 2
if len(self._oscillator_history) < required_count:
return
current = self._oscillator_history[len(self._oscillator_history) - signal_bar]
previous = self._oscillator_history[len(self._oscillator_history) - (signal_bar + 1)]
prior = self._oscillator_history[len(self._oscillator_history) - (signal_bar + 2)]
rising = previous < prior and current > previous
falling = previous > prior and current < previous
trend_mode = int(self.TrendMode)
if trend_mode == TREND_DIRECT:
long_signal = rising
short_signal = falling
else:
long_signal = falling
short_signal = rising
if long_signal:
if self.BuyCloseEnabled and self.Position < 0:
self.BuyMarket()
if self.BuyOpenEnabled and self.Position <= 0:
self.BuyMarket()
if short_signal:
if self.SellCloseEnabled and self.Position > 0:
self.SellMarket()
if self.SellOpenEnabled and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(weight_oscillator_direct_strategy, self).OnReseted()
self._oscillator_history = []
def CreateClone(self):
return weight_oscillator_direct_strategy()