Esta estrategia es un port del experto MetaTrader Exp_ColorBulls. Se basa en el indicador Color Bulls, que calcula la diferencia entre el precio máximo de la vela y una media móvil. El valor resultante se suaviza con otra media móvil y se muestra como un histograma con diferentes colores para valores en alza y en baja.
La estrategia reacciona a los cambios de color de este histograma:
Cuando el indicador pasa de subir (verde) a bajar (magenta), se abre una posición larga.
Cuando el indicador pasa de bajar a subir, se abre una posición corta.
Las posiciones opuestas se cierran automáticamente antes de abrir nuevas.
Solo se procesan velas completadas y se usan órdenes de mercado para entradas y salidas.
Parámetros
Fast MA Length – período de la media móvil aplicada a los precios máximos.
Smooth Length – período de la media móvil utilizada para suavizar el valor bulls.
Candle Type – marco temporal de las velas utilizadas para los cálculos.
Notas
Este ejemplo demuestra la integración de un indicador personalizado con la API de alto nivel de StockSharp. La gestión de stop-loss y take-profit no está incluida.
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 Color Bulls indicator.
/// Opens long when bulls value switches from rising to falling.
/// Opens short when value switches from falling to rising.
/// </summary>
public class ColorBullsStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _smoothLength;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevValue;
private int _prevColor;
/// <summary>
/// Period for moving average applied to high prices.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// Period for smoothing bulls value.
/// </summary>
public int SmoothLength
{
get => _smoothLength.Value;
set => _smoothLength.Value = value;
}
/// <summary>
/// Candle type used for calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes parameters.
/// </summary>
public ColorBullsStrategy()
{
_fastLength = Param(nameof(FastLength), 12)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Period of high price moving average", "Indicator")
.SetOptimize(5, 20, 1);
_smoothLength = Param(nameof(SmoothLength), 5)
.SetGreaterThanZero()
.SetDisplay("Smooth Length", "Period of smoothing moving average", "Indicator")
.SetOptimize(3, 15, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevValue = 0m;
_prevColor = 1;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highMa = new ExponentialMovingAverage { Length = FastLength };
var bullsMa = new ExponentialMovingAverage { Length = SmoothLength };
Indicators.Add(highMa);
Indicators.Add(bullsMa);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var highInput = new DecimalIndicatorValue(highMa, candle.HighPrice, candle.OpenTime) { IsFinal = true };
var maValue = highMa.Process(highInput);
if (!highMa.IsFormed)
return;
var bulls = candle.HighPrice - maValue.ToDecimal();
var bullsInput = new DecimalIndicatorValue(bullsMa, bulls, candle.OpenTime) { IsFinal = true };
var smooth = bullsMa.Process(bullsInput).ToDecimal();
if (!bullsMa.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var color = smooth > _prevValue ? 0 : smooth < _prevValue ? 2 : 1;
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 = smooth;
}
}
}
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_bulls_strategy(Strategy):
def __init__(self):
super(color_bulls_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 12) \
.SetDisplay("Fast MA Length", "Period of high price moving average", "Indicator")
self._smooth_length = self.Param("SmoothLength", 5) \
.SetDisplay("Smooth Length", "Period of smoothing moving average", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_value = 0.0
self._prev_color = 1
self._high_ma = None
self._bulls_ma = None
@property
def fast_length(self):
return self._fast_length.Value
@property
def smooth_length(self):
return self._smooth_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_bulls_strategy, self).OnReseted()
self._prev_value = 0.0
self._prev_color = 1
self._high_ma = None
self._bulls_ma = None
def OnStarted2(self, time):
super(color_bulls_strategy, self).OnStarted2(time)
self._high_ma = ExponentialMovingAverage()
self._high_ma.Length = self.fast_length
self._bulls_ma = ExponentialMovingAverage()
self._bulls_ma.Length = self.smooth_length
self.Indicators.Add(self._high_ma)
self.Indicators.Add(self._bulls_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
ma_value = process_float(self._high_ma, candle.HighPrice, candle.OpenTime, True)
if not self._high_ma.IsFormed:
return
bulls = float(candle.HighPrice) - float(ma_value)
smooth = float(process_float(self._bulls_ma, bulls, candle.OpenTime, True))
if not self._bulls_ma.IsFormed:
return
if smooth > self._prev_value:
color = 0
elif smooth < self._prev_value:
color = 2
else:
color = 1
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 = smooth
def CreateClone(self):
return color_bulls_strategy()