RobotPower M5 Strategy
This strategy combines the Bulls Power and Bears Power indicators on a 5-minute chart.
It opens positions when the combined momentum of bulls and bears crosses zero and manages exits with fixed targets and a trailing stop.
How It Works
- Indicators: Bulls Power and Bears Power with a shared period
BullBearPeriod.
- Timeframe: 5-minute candles by default (
CandleType).
Entry Rules
- Long Entry: When
BullsPower + BearsPower > 0 and no position is open, buy at market.
- Short Entry: When
BullsPower + BearsPower < 0 and no position is open, sell at market.
Exit Rules
- Take Profit: Close the position when price moves
TakeProfit units in the trade direction.
- Stop Loss: Close the position if price moves against the position by
StopLoss units.
- Trailing Stop: After entry, the stop loss trails by
TrailingStep once price advances more than twice that distance.
Parameters
BullBearPeriod – period for both Bulls Power and Bears Power calculations.
TrailingStep – step size used when adjusting the trailing stop.
TakeProfit – distance from entry to the take-profit level.
StopLoss – distance from entry to the stop-loss level.
CandleType – candle timeframe for signal calculation.
Position Size
Uses the strategy's Volume property for order size.
Notes
Designed for educational purposes and serves as an example of converting an MQL strategy to the StockSharp API.
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>
/// Bulls and Bears Power crossover strategy with trailing stop.
/// Buys when Bulls Power plus Bears Power is positive and sells when negative.
/// Applies fixed take profit and stop loss with trailing adjustment.
/// </summary>
public class RobotPowerM5Strategy : Strategy
{
private readonly StrategyParam<int> _bullBearPeriod;
private readonly StrategyParam<decimal> _trailingStep;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Period for Bulls Power and Bears Power.
/// </summary>
public int BullBearPeriod
{
get => _bullBearPeriod.Value;
set => _bullBearPeriod.Value = value;
}
/// <summary>
/// Trailing step distance.
/// </summary>
public decimal TrailingStep
{
get => _trailingStep.Value;
set => _trailingStep.Value = value;
}
/// <summary>
/// Take profit distance in price units.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Stop loss distance in price units.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RobotPowerM5Strategy"/>.
/// </summary>
public RobotPowerM5Strategy()
{
_bullBearPeriod = Param(nameof(BullBearPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Bull/Bear Period", "Bulls and Bears Power period", "Indicators");
_trailingStep = Param(nameof(TrailingStep), 10m)
.SetGreaterThanZero()
.SetDisplay("Trailing Step", "Trailing stop step size", "Risk");
_takeProfit = Param(nameof(TakeProfit), 150m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Take profit distance", "Risk");
_stopLoss = Param(nameof(StopLoss), 105m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop loss distance", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_stopPrice = 0m;
_takePrice = 0m;
var bulls = new BullPower { Length = BullBearPeriod };
var bears = new BearPower { Length = BullBearPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(bulls, bears, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bulls);
DrawIndicator(area, bears);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal bullsValue, decimal bearsValue)
{
if (candle.State != CandleStates.Finished)
return;
var sum = bullsValue + bearsValue;
if (Position == 0)
{
if (sum > 0)
{
BuyMarket();
_stopPrice = candle.ClosePrice - StopLoss;
_takePrice = candle.ClosePrice + TakeProfit;
}
else if (sum < 0)
{
SellMarket();
_stopPrice = candle.ClosePrice + StopLoss;
_takePrice = candle.ClosePrice - TakeProfit;
}
return;
}
if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
{
SellMarket();
_stopPrice = 0m;
_takePrice = 0m;
return;
}
if (candle.ClosePrice - _stopPrice > 2 * TrailingStep)
_stopPrice = candle.ClosePrice - TrailingStep;
}
else if (Position < 0)
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
{
BuyMarket();
_stopPrice = 0m;
_takePrice = 0m;
return;
}
if (_stopPrice - candle.ClosePrice > 2 * TrailingStep)
_stopPrice = candle.ClosePrice + TrailingStep;
}
}
}
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 BullPower, BearPower
from StockSharp.Algo.Strategies import Strategy
class robot_power_m5_strategy(Strategy):
def __init__(self):
super(robot_power_m5_strategy, self).__init__()
self._bb_period = self.Param("BullBearPeriod", 5).SetGreaterThanZero().SetDisplay("Bull/Bear Period", "Bulls and Bears Power period", "Indicators")
self._trailing_step = self.Param("TrailingStep", 10.0).SetGreaterThanZero().SetDisplay("Trailing Step", "Trailing stop step", "Risk")
self._tp = self.Param("TakeProfit", 150.0).SetGreaterThanZero().SetDisplay("Take Profit", "TP distance", "Risk")
self._sl = self.Param("StopLoss", 105.0).SetGreaterThanZero().SetDisplay("Stop Loss", "SL distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(robot_power_m5_strategy, self).OnReseted()
self._stop_price = 0
self._take_price = 0
def OnStarted2(self, time):
super(robot_power_m5_strategy, self).OnStarted2(time)
self._stop_price = 0
self._take_price = 0
bulls = BullPower()
bulls.Length = self._bb_period.Value
bears = BearPower()
bears.Length = self._bb_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(bulls, bears, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, bulls)
self.DrawIndicator(area, bears)
self.DrawOwnTrades(area)
def OnProcess(self, candle, bulls_val, bears_val):
if candle.State != CandleStates.Finished:
return
total = bulls_val + bears_val
close = candle.ClosePrice
if self.Position == 0:
if total > 0:
self.BuyMarket()
self._stop_price = close - self._sl.Value
self._take_price = close + self._tp.Value
elif total < 0:
self.SellMarket()
self._stop_price = close + self._sl.Value
self._take_price = close - self._tp.Value
return
if self.Position > 0:
if candle.LowPrice <= self._stop_price or candle.HighPrice >= self._take_price:
self.SellMarket()
self._stop_price = 0
self._take_price = 0
return
if close - self._stop_price > 2 * self._trailing_step.Value:
self._stop_price = close - self._trailing_step.Value
elif self.Position < 0:
if candle.HighPrice >= self._stop_price or candle.LowPrice <= self._take_price:
self.BuyMarket()
self._stop_price = 0
self._take_price = 0
return
if self._stop_price - close > 2 * self._trailing_step.Value:
self._stop_price = close + self._trailing_step.Value
def CreateClone(self):
return robot_power_m5_strategy()