Die Strategie erstellt einen doppelt geglätteten Bears-Power-Oszillator und handelt bei Änderungen seiner Steigung.
Idee
Einen exponentiellen gleitenden Durchschnitt (MA1) der Schlusskurse berechnen.
Bears Power als Differenz zwischen dem Kerzentiefst und MA1 berechnen.
Bears Power mit einem weiteren exponentiellen gleitenden Durchschnitt (MA2) glätten.
Verfolgen, ob der geglättete Wert steigt oder fällt, und auf Steigungsumkehrungen reagieren.
Handelsregeln
Wenn der Indikator von steigend zu fallend wechselt (Farbe 0 → 2), Short-Positionen schließen und eine Long-Position eröffnen.
Wenn der Indikator von fallend zu steigend wechselt (Farbe 2 → 0), Long-Positionen schließen und eine Short-Position eröffnen.
Jede Position verwendet die Volume-Eigenschaft der Strategie als Ordergröße.
Parameter
Name
Beschreibung
Ma1Period
Periode des ersten EMA zur Berechnung von Bears Power.
Ma2Period
Periode des glättenden EMA.
CandleType
Kerzen-Zeitrahmen für Berechnungen.
Hinweise
Diese C#-Implementierung ist aus dem MQL-Experten „ColorBears" (Ordner MQL/14314) adaptiert.
Der Algorithmus basiert auf Standard-StockSharp-Indikatoren und High-Level-API-Bindings.
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>
/// Strategy based on a double-smoothed Bears Power indicator.
/// Opens a long position when the indicator turns down after rising,
/// and opens a short position when it turns up after falling.
/// </summary>
public class ColorBearsStrategy : Strategy
{
private readonly StrategyParam<int> _ma1Period;
private readonly StrategyParam<int> _ma2Period;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _ma1;
private ExponentialMovingAverage _ma2;
private decimal? _prevValue;
private int? _prevColor;
/// <summary>
/// Length of the first moving average.
/// </summary>
public int Ma1Period
{
get => _ma1Period.Value;
set => _ma1Period.Value = value;
}
/// <summary>
/// Length of the second moving average.
/// </summary>
public int Ma2Period
{
get => _ma2Period.Value;
set => _ma2Period.Value = value;
}
/// <summary>
/// Candle type used for indicator calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="ColorBearsStrategy"/>.
/// </summary>
public ColorBearsStrategy()
{
_ma1Period = Param(nameof(Ma1Period), 12)
.SetGreaterThanZero()
.SetDisplay("MA1", "First MA length", "Parameters")
.SetOptimize(5, 30, 1);
_ma2Period = Param(nameof(Ma2Period), 5)
.SetGreaterThanZero()
.SetDisplay("MA2", "Second MA length", "Parameters")
.SetOptimize(2, 20, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle", "Candle type", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ma1 = new ExponentialMovingAverage { Length = Ma1Period };
_ma2 = new ExponentialMovingAverage { Length = Ma2Period };
Indicators.Add(_ma1);
Indicators.Add(_ma2);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var ma1Input = new DecimalIndicatorValue(_ma1, candle.ClosePrice, candle.OpenTime) { IsFinal = true };
var ma1Value = _ma1.Process(ma1Input);
if (!_ma1.IsFormed)
return;
var bears = candle.LowPrice - ma1Value.ToDecimal();
var ma2Input = new DecimalIndicatorValue(_ma2, bears, candle.OpenTime) { IsFinal = true };
var ma2Value = _ma2.Process(ma2Input);
if (!_ma2.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var current = ma2Value.ToDecimal();
var color = 1;
if (_prevValue != null)
{
if (_prevValue < current)
color = 0;
else if (_prevValue > current)
color = 2;
if (_prevColor == 0 && color == 2)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (_prevColor == 2 && color == 0)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
_prevColor = color;
_prevValue = current;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ma1 = default;
_ma2 = default;
_prevValue = null;
_prevColor = null;
}
}
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
from indicator_extensions import *
class color_bears_strategy(Strategy):
def __init__(self):
super(color_bears_strategy, self).__init__()
self._ma1_period = self.Param("Ma1Period", 12) \
.SetDisplay("MA1", "First MA length", "Parameters")
self._ma2_period = self.Param("Ma2Period", 5) \
.SetDisplay("MA2", "Second MA length", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle", "Candle type", "Parameters")
self._ma1 = None
self._ma2 = None
self._prev_value = None
self._prev_color = None
@property
def ma1_period(self):
return self._ma1_period.Value
@property
def ma2_period(self):
return self._ma2_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_bears_strategy, self).OnReseted()
self._ma1 = None
self._ma2 = None
self._prev_value = None
self._prev_color = None
def OnStarted2(self, time):
super(color_bears_strategy, self).OnStarted2(time)
self._ma1 = ExponentialMovingAverage()
self._ma1.Length = self.ma1_period
self._ma2 = ExponentialMovingAverage()
self._ma2.Length = self.ma2_period
self.Indicators.Add(self._ma1)
self.Indicators.Add(self._ma2)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
ma1_result = process_float(self._ma1, candle.ClosePrice, candle.OpenTime, True)
if not self._ma1.IsFormed:
return
bears = float(candle.LowPrice) - float(ma1_result)
ma2_result = process_float(self._ma2, bears, candle.OpenTime, True)
if not self._ma2.IsFormed:
return
current = float(ma2_result)
color = 1
if self._prev_value is not None:
if self._prev_value < current:
color = 0
elif self._prev_value > current:
color = 2
if self._prev_color == 0 and color == 2:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif self._prev_color == 2 and color == 0:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._prev_color = color
self._prev_value = current
def CreateClone(self):
return color_bears_strategy()