Ver en GitHub

Estrategia del arco iris del seguidor de tendencias

Descripción general

Trend Follower Rainbow Strategy es una adaptación de C# del asesor experto MetaTrader 4 "TrendFollowerRainbowMethodkyast773". La estrategia combina varias capas de confirmación para operar en la dirección de tendencias fuertes mientras filtra períodos dentro de un rango. Se basa en la alineación de un arco iris de promedios móviles exponenciales, impulso MACD, umbrales del oscilador de Laguerre, lecturas del índice de flujo de dinero y un cruce EMA rápido/lento para activar posiciones.

Lógica de trading

  1. Ventana de negociación: las señales se evalúan solo cuando el tiempo de cierre de la vela actual está estrictamente entre las horas de inicio y finalización configurables. Esto imita el filtro de tiempo del EA original que evitaba la primera y la última hora de negociación de la sesión.
  2. EMA Activador de cruce: una configuración larga requiere que el EMA rápido (longitud predeterminada 4) cruce por encima del EMA lento (longitud predeterminada 8). Una configuración corta requiere el cruce opuesto.
  3. MACD Confirmación: la línea MACD y la línea de señal (predeterminada 5/35/5) deben estar por encima de cero para operaciones largas o por debajo de cero para operaciones cortas para confirmar la alineación del impulso.
  4. Filtro Laguerre: el valor del filtro Laguerre debe superar 0,15 para operaciones largas o menos de 0,75 para operaciones cortas, reproduciendo las comprobaciones de umbral originales realizadas en el indicador personalizado.
  5. Alineación del arco iris: se deben ordenar monótonamente cinco paquetes de medias móviles exponenciales (cuatro EMA por paquete) para confirmar la estructura del arco iris. Los paquetes se evalúan en busca de un orden no creciente en escenarios alcistas y un orden no decreciente en escenarios bajistas.
  6. Filtro de índice de flujo de dinero: el índice de flujo de dinero (período predeterminado 14) debe estar por debajo de 40 para entradas largas y por encima de 60 para entradas cortas para evitar operar contra el flujo impulsado por el volumen.
  7. Gestión de posiciones: se utilizan órdenes de mercado. Cuando aparece una señal opuesta, la exposición existente se cierra y se abre una nueva posición en la dirección opuesta.

Gestión del riesgo

La estrategia admite protecciones integradas a través del asistente StartProtection de StockSharp:

  • Las distancias de Take Profit y Stop Loss se expresan en pasos de precio para reflejar la configuración basada en puntos de EA.
  • La distancia Trailing Stop también utiliza pasos de precio y se activa una vez que se inicia el bloqueo de protección.

Parámetros

Parámetro Descripción Predeterminado
OrderVolume Volumen de orden de mercado base. 1
TakeProfitPoints Tome la distancia de beneficio en pasos de precio. 17
StopLossPoints Distancia de stop loss en pasos de precio. 30
TrailingStopPoints Distancia del trailing stop en pasos de precio. 45
TradingStartHour Primera hora (inclusive) que se salta antes de evaluar señales. 1
TradingEndHour Última hora (inclusive) que se salta tras evaluar señales. 23
FastEmaLength Longitud del EMA rápido utilizado en el activador de cruce. 4
SlowEmaLength Longitud del EMA lento utilizado en el activador de cruce. 8
MacdFastLength MACD EMA rápida longitud. 5
MacdSlowLength MACD EMA lenta longitud. 35
MacdSignalLength MACD señal EMA longitud. 5
LaguerreGamma Factor de suavizado del filtro de Laguerre. 0,7
LaguerreBuyThreshold El umbral de Laguerre cruzó hacia arriba para operaciones largas. 0,15
LaguerreSellThreshold El umbral de Laguerre cruzó a la baja para operaciones cortas. 0,75
MfiPeriod Período de cálculo del Índice de Flujo de Dinero. 14
MfiBuyLevel Nivel máximo de IMF que aún permite entradas largas. 40
MfiSellLevel Nivel mínimo de IMF que aún permite entradas cortas. 60
RainbowGroup{1..5}Base Longitud base EMA para cada paquete de arcoíris. Se crean cuatro EMA consecutivos a partir de cada valor base agregando compensaciones (0, 2, 4, 6). 5 / 13 / 21 / 34 / 55
CandleType Serie de velas primaria utilizada por la estrategia. El valor predeterminado es velas de 5 minutos. marco de tiempo de 5 minutos

Trazar

La estrategia dibuja automáticamente:

  • Velas de precio para la serie suscrita.
  • EMA rápidas y lentas para confirmación visual de cruces.
  • Laguerre filtra valores para observar cruces de umbrales.
  • Operaciones propias trazadas en el área del gráfico.

Notas

  • La lógica del arco iris se aproxima a los indicadores personalizados originales de RainbowMMA mediante la creación de paquetes EMA configurables. Ajuste las longitudes de la base para que coincidan con una plantilla de arcoíris específica si es necesario.
  • Todos los comentarios de código, registros y documentación se proporcionan en inglés según sea necesario.
  • La estrategia se centra únicamente en la implementación de C#. No se genera ningún puerto Python en esta tarea.
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>
/// Trend following strategy that combines EMA crossover, MACD confirmation,
/// Laguerre filter thresholds, rainbow moving average structure and MFI filter.
/// </summary>
public class TrendFollowerRainbowStrategy : Strategy
{
	private readonly StrategyParam<decimal> _orderVolume;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<decimal> _stopLossPoints;
	private readonly StrategyParam<decimal> _trailingStopPoints;
	private readonly StrategyParam<int> _tradingStartHour;
	private readonly StrategyParam<int> _tradingEndHour;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _macdFastLength;
	private readonly StrategyParam<int> _macdSlowLength;
	private readonly StrategyParam<int> _macdSignalLength;
	private readonly StrategyParam<decimal> _laguerreGamma;
	private readonly StrategyParam<decimal> _laguerreBuyThreshold;
	private readonly StrategyParam<decimal> _laguerreSellThreshold;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<decimal> _mfiBuyLevel;
	private readonly StrategyParam<decimal> _mfiSellLevel;
	private readonly StrategyParam<int> _rainbowGroup1Base;
	private readonly StrategyParam<int> _rainbowGroup2Base;
	private readonly StrategyParam<int> _rainbowGroup3Base;
	private readonly StrategyParam<int> _rainbowGroup4Base;
	private readonly StrategyParam<int> _rainbowGroup5Base;
	private readonly StrategyParam<DataType> _candleType;

	private ExponentialMovingAverage _emaFast = null!;
	private ExponentialMovingAverage _emaSlow = null!;
	private MovingAverageConvergenceDivergenceSignal _macd = null!;
	private AdaptiveLaguerreFilter _laguerre = null!;
	private MoneyFlowIndex _mfi = null!;
	private ExponentialMovingAverage[][] _rainbowGroups = [];

	private decimal? _previousFastEma;
	private decimal? _previousSlowEma;
	private decimal? _previousLaguerre;
	private decimal _pointValue;

	/// <summary>
	/// Initializes a new instance of the <see cref="TrendFollowerRainbowStrategy"/> class.
	/// </summary>
	public TrendFollowerRainbowStrategy()
	{
		_orderVolume = Param(nameof(OrderVolume), 1m)
		.SetDisplay("Order Volume", "Base order volume", "Trading")
		;

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 17m)
		.SetDisplay("Take Profit (pts)", "Distance in price steps for take profit", "Risk Management")
		;

		_stopLossPoints = Param(nameof(StopLossPoints), 30m)
		.SetDisplay("Stop Loss (pts)", "Distance in price steps for stop loss", "Risk Management")
		;

		_trailingStopPoints = Param(nameof(TrailingStopPoints), 45m)
		.SetDisplay("Trailing Stop (pts)", "Distance in price steps for trailing stop", "Risk Management")
		;

		_tradingStartHour = Param(nameof(TradingStartHour), 1)
		.SetDisplay("Start Hour", "Hour (0-23) when trading window opens", "Trading Schedule")
		;

		_tradingEndHour = Param(nameof(TradingEndHour), 23)
		.SetDisplay("End Hour", "Hour (0-23) when trading window closes", "Trading Schedule")
		;

		_fastEmaLength = Param(nameof(FastEmaLength), 4)
		.SetRange(2, 20)
		.SetDisplay("Fast EMA", "Length of the fast EMA", "Indicators")
		;

		_slowEmaLength = Param(nameof(SlowEmaLength), 8)
		.SetRange(3, 50)
		.SetDisplay("Slow EMA", "Length of the slow EMA", "Indicators")
		;

		_macdFastLength = Param(nameof(MacdFastLength), 5)
		.SetDisplay("MACD Fast", "Fast EMA length for MACD", "Indicators")
		;

		_macdSlowLength = Param(nameof(MacdSlowLength), 35)
		.SetDisplay("MACD Slow", "Slow EMA length for MACD", "Indicators")
		;

		_macdSignalLength = Param(nameof(MacdSignalLength), 5)
		.SetDisplay("MACD Signal", "Signal EMA length for MACD", "Indicators")
		;

		_laguerreGamma = Param(nameof(LaguerreGamma), 0.7m)
		.SetRange(0.1m, 0.9m)
		.SetDisplay("Laguerre Gamma", "Smoothing factor for Laguerre filter", "Indicators")
		;

		_laguerreBuyThreshold = Param(nameof(LaguerreBuyThreshold), 0.15m)
		.SetDisplay("Laguerre Buy", "Threshold crossed upward for long signals", "Indicators")
		;

		_laguerreSellThreshold = Param(nameof(LaguerreSellThreshold), 0.75m)
		.SetDisplay("Laguerre Sell", "Threshold crossed downward for short signals", "Indicators")
		;

		_mfiPeriod = Param(nameof(MfiPeriod), 14)
		.SetDisplay("MFI Period", "Money Flow Index calculation period", "Indicators")
		;

		_mfiBuyLevel = Param(nameof(MfiBuyLevel), 40m)
		.SetDisplay("MFI Buy", "Upper bound for oversold check", "Indicators")
		;

		_mfiSellLevel = Param(nameof(MfiSellLevel), 60m)
		.SetDisplay("MFI Sell", "Lower bound for overbought check", "Indicators")
		;

		_rainbowGroup1Base = Param(nameof(RainbowGroup1Base), 5)
		.SetDisplay("Rainbow Group 1", "Base length for the fastest rainbow bundle", "Rainbow")
		;

		_rainbowGroup2Base = Param(nameof(RainbowGroup2Base), 13)
		.SetDisplay("Rainbow Group 2", "Base length for the second rainbow bundle", "Rainbow")
		;

		_rainbowGroup3Base = Param(nameof(RainbowGroup3Base), 21)
		.SetDisplay("Rainbow Group 3", "Base length for the middle rainbow bundle", "Rainbow")
		;

		_rainbowGroup4Base = Param(nameof(RainbowGroup4Base), 34)
		.SetDisplay("Rainbow Group 4", "Base length for the fourth rainbow bundle", "Rainbow")
		;

		_rainbowGroup5Base = Param(nameof(RainbowGroup5Base), 55)
		.SetDisplay("Rainbow Group 5", "Base length for the slowest rainbow bundle", "Rainbow")
		;

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
		.SetDisplay("Candle Type", "Primary candle series", "General");
	}

	/// <summary>
	/// Base order volume.
	/// </summary>
	public decimal OrderVolume
	{
		get => _orderVolume.Value;
		set => _orderVolume.Value = value;
	}

	/// <summary>
	/// Take profit distance expressed in price steps.
	/// </summary>
	public decimal TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Stop loss distance expressed in price steps.
	/// </summary>
	public decimal StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Trailing stop distance expressed in price steps.
	/// </summary>
	public decimal TrailingStopPoints
	{
		get => _trailingStopPoints.Value;
		set => _trailingStopPoints.Value = value;
	}

	/// <summary>
	/// First hour (0-23) when the strategy can evaluate entries.
	/// </summary>
	public int TradingStartHour
	{
		get => _tradingStartHour.Value;
		set => _tradingStartHour.Value = value;
	}

	/// <summary>
	/// Last hour (0-23) when the strategy can evaluate entries.
	/// </summary>
	public int TradingEndHour
	{
		get => _tradingEndHour.Value;
		set => _tradingEndHour.Value = value;
	}

	/// <summary>
	/// Fast EMA length used for the crossover signal.
	/// </summary>
	public int FastEmaLength
	{
		get => _fastEmaLength.Value;
		set => _fastEmaLength.Value = value;
	}

	/// <summary>
	/// Slow EMA length used for the crossover signal.
	/// </summary>
	public int SlowEmaLength
	{
		get => _slowEmaLength.Value;
		set => _slowEmaLength.Value = value;
	}

	/// <summary>
	/// MACD fast EMA length.
	/// </summary>
	public int MacdFastLength
	{
		get => _macdFastLength.Value;
		set => _macdFastLength.Value = value;
	}

	/// <summary>
	/// MACD slow EMA length.
	/// </summary>
	public int MacdSlowLength
	{
		get => _macdSlowLength.Value;
		set => _macdSlowLength.Value = value;
	}

	/// <summary>
	/// MACD signal EMA length.
	/// </summary>
	public int MacdSignalLength
	{
		get => _macdSignalLength.Value;
		set => _macdSignalLength.Value = value;
	}

	/// <summary>
	/// Laguerre filter smoothing factor.
	/// </summary>
	public decimal LaguerreGamma
	{
		get => _laguerreGamma.Value;
		set => _laguerreGamma.Value = value;
	}

	/// <summary>
	/// Laguerre threshold that needs to be crossed upward to allow long signals.
	/// </summary>
	public decimal LaguerreBuyThreshold
	{
		get => _laguerreBuyThreshold.Value;
		set => _laguerreBuyThreshold.Value = value;
	}

	/// <summary>
	/// Laguerre threshold that needs to be crossed downward to allow short signals.
	/// </summary>
	public decimal LaguerreSellThreshold
	{
		get => _laguerreSellThreshold.Value;
		set => _laguerreSellThreshold.Value = value;
	}

	/// <summary>
	/// Money Flow Index period.
	/// </summary>
	public int MfiPeriod
	{
		get => _mfiPeriod.Value;
		set => _mfiPeriod.Value = value;
	}

	/// <summary>
	/// Maximum MFI level that still allows long entries.
	/// </summary>
	public decimal MfiBuyLevel
	{
		get => _mfiBuyLevel.Value;
		set => _mfiBuyLevel.Value = value;
	}

	/// <summary>
	/// Minimum MFI level that still allows short entries.
	/// </summary>
	public decimal MfiSellLevel
	{
		get => _mfiSellLevel.Value;
		set => _mfiSellLevel.Value = value;
	}

	/// <summary>
	/// Base period for the fastest rainbow bundle.
	/// </summary>
	public int RainbowGroup1Base
	{
		get => _rainbowGroup1Base.Value;
		set => _rainbowGroup1Base.Value = value;
	}

	/// <summary>
	/// Base period for the second rainbow bundle.
	/// </summary>
	public int RainbowGroup2Base
	{
		get => _rainbowGroup2Base.Value;
		set => _rainbowGroup2Base.Value = value;
	}

	/// <summary>
	/// Base period for the third rainbow bundle.
	/// </summary>
	public int RainbowGroup3Base
	{
		get => _rainbowGroup3Base.Value;
		set => _rainbowGroup3Base.Value = value;
	}

	/// <summary>
	/// Base period for the fourth rainbow bundle.
	/// </summary>
	public int RainbowGroup4Base
	{
		get => _rainbowGroup4Base.Value;
		set => _rainbowGroup4Base.Value = value;
	}

	/// <summary>
	/// Base period for the fifth rainbow bundle.
	/// </summary>
	public int RainbowGroup5Base
	{
		get => _rainbowGroup5Base.Value;
		set => _rainbowGroup5Base.Value = value;
	}

	/// <summary>
	/// Candle type used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_previousFastEma = null;
		_previousSlowEma = null;
		_previousLaguerre = null;
		_pointValue = 0m;
		_rainbowGroups = [];
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_pointValue = Security?.PriceStep ?? 0m;
		Volume = OrderVolume;

		var takeProfit = ToAbsoluteUnit(TakeProfitPoints);
		var stopLoss = ToAbsoluteUnit(StopLossPoints);

		if (takeProfit != null || stopLoss != null)
		{
			StartProtection(
			takeProfit: takeProfit,
			stopLoss: stopLoss,
			isStopTrailing: TrailingStopPoints > 0m,
			useMarketOrders: true);
		}

		_emaFast = new EMA { Length = FastEmaLength };
		_emaSlow = new EMA { Length = SlowEmaLength };
		_macd = new MovingAverageConvergenceDivergenceSignal();
		_macd.Macd.ShortMa.Length = MacdFastLength;
		_macd.Macd.LongMa.Length = MacdSlowLength;
		_macd.SignalMa.Length = MacdSignalLength;
		_laguerre = new AdaptiveLaguerreFilter { Gamma = LaguerreGamma };
		_mfi = new MoneyFlowIndex { Length = MfiPeriod };
		_rainbowGroups = BuildRainbowGroups();

		var indicators = new List<IIndicator>
		{
			_emaFast,
			_emaSlow,
			_macd,
			_laguerre,
			_mfi
		};

		foreach (var group in _rainbowGroups)
		{
			indicators.AddRange(group);
		}

		var subscription = SubscribeCandles(CandleType);
		subscription
		.BindEx(indicators.ToArray(), ProcessCandle)
		.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _emaFast);
			DrawIndicator(area, _emaSlow);
			DrawIndicator(area, _laguerre);
			DrawOwnTrades(area);
		}
	}

	private ExponentialMovingAverage[][] BuildRainbowGroups()
	{
		var offsets = new[] { 0, 2, 4, 6 };

		return new[]
		{
			offsets.Select(o => new EMA { Length = Math.Max(1, RainbowGroup1Base + o) }).ToArray(),
			offsets.Select(o => new EMA { Length = Math.Max(1, RainbowGroup2Base + o) }).ToArray(),
			offsets.Select(o => new EMA { Length = Math.Max(1, RainbowGroup3Base + o) }).ToArray(),
			offsets.Select(o => new EMA { Length = Math.Max(1, RainbowGroup4Base + o) }).ToArray(),
			offsets.Select(o => new EMA { Length = Math.Max(1, RainbowGroup5Base + o) }).ToArray()
		};
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue[] values)
	{
		if (candle.State != CandleStates.Finished)
		return;

		var hour = candle.CloseTime.Hour;
		if (hour <= TradingStartHour || hour >= TradingEndHour)
		{
			UpdatePreviousValues(values);
			return;
		}

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			UpdatePreviousValues(values);
			return;
		}

		var index = 0;

		var hasFast = TryGetDecimal(values[index++], out var fastEma);
		var hasSlow = TryGetDecimal(values[index++], out var slowEma);
		if (!hasFast || !hasSlow)
		{
			UpdatePreviousValues(values, hasFast ? fastEma : null, hasSlow ? slowEma : null);
			return;
		}

		var macdValue = values[index++];
		if (!macdValue.IsFinal || macdValue is not MovingAverageConvergenceDivergenceSignalValue macdData ||
		macdData.Macd is not decimal macdMain || macdData.Signal is not decimal macdSignal)
		{
			UpdatePreviousValues(values, fastEma, slowEma);
			return;
		}

		if (!TryGetDecimal(values[index++], out var laguerre))
		{
			UpdatePreviousValues(values, fastEma, slowEma);
			return;
		}

		if (!TryGetDecimal(values[index++], out var mfi))
		{
			UpdatePreviousValues(values, fastEma, slowEma, laguerre);
			return;
		}

		var rainbowValues = new List<decimal[]>(_rainbowGroups.Length);
		for (var groupIndex = 0; groupIndex < _rainbowGroups.Length; groupIndex++)
		{
			var group = _rainbowGroups[groupIndex];
			var decimals = new decimal[group.Length];

			for (var i = 0; i < group.Length; i++)
			{
				if (!TryGetDecimal(values[index++], out var rainbow))
				{
					UpdatePreviousValues(values, fastEma, slowEma, laguerre);
					return;
				}

				decimals[i] = rainbow;
			}

			rainbowValues.Add(decimals);
		}

		var rainbowBullish = rainbowValues.All(bundle => IsMonotonic(bundle, descending: true));
		var rainbowBearish = rainbowValues.All(bundle => IsMonotonic(bundle, descending: false));

		var emaCrossUp = _previousFastEma is decimal prevFast && _previousSlowEma is decimal prevSlow &&
		prevFast < prevSlow && fastEma > slowEma;

		var emaCrossDown = _previousFastEma is decimal prevFastDown && _previousSlowEma is decimal prevSlowDown &&
		prevFastDown > prevSlowDown && fastEma < slowEma;

		var laguerreBullish = _previousLaguerre is decimal prevLagBull &&
		prevLagBull <= LaguerreBuyThreshold && laguerre > LaguerreBuyThreshold;

		var laguerreBearish = _previousLaguerre is decimal prevLagBear &&
		prevLagBear >= LaguerreSellThreshold && laguerre < LaguerreSellThreshold;

		var macdBullish = macdMain > 0m && macdSignal > 0m;
		var macdBearish = macdMain < 0m && macdSignal < 0m;

		var mfiBullish = mfi < MfiBuyLevel;
		var mfiBearish = mfi > MfiSellLevel;

		if (emaCrossUp && macdBullish && Position <= 0)
		{
			var volume = Volume + Math.Abs(Position);
			BuyMarket(volume);
		}
		else if (emaCrossDown && macdBearish && Position >= 0)
		{
			var volume = Volume + Math.Abs(Position);
			SellMarket(volume);
		}

		_previousFastEma = fastEma;
		_previousSlowEma = slowEma;
		_previousLaguerre = laguerre;
	}

	private void UpdatePreviousValues(IIndicatorValue[] values, decimal? fastEma = null, decimal? slowEma = null, decimal? laguerre = null)
	{
		var index = 0;

		fastEma ??= TryGetDecimal(values[index++], out var fast) ? fast : null;
		slowEma ??= TryGetDecimal(values[index++], out var slow) ? slow : null;
		index++;
		laguerre ??= TryGetDecimal(values[index++], out var lag) ? lag : null;

		_previousFastEma = fastEma ?? _previousFastEma;
		_previousSlowEma = slowEma ?? _previousSlowEma;
		_previousLaguerre = laguerre ?? _previousLaguerre;
	}

	private bool IsMonotonic(decimal[] values, bool descending)
	{
		for (var i = 0; i < values.Length - 1; i++)
		{
			if (descending)
			{
				if (values[i] < values[i + 1])
				return false;
			}
			else
			{
				if (values[i] > values[i + 1])
				return false;
			}
		}

		return true;
	}

	private static bool TryGetDecimal(IIndicatorValue value, out decimal result)
	{
		if (!value.IsFinal)
		{
			result = default;
			return false;
		}

		result = value.ToDecimal();
		return true;
	}

	private Unit ToAbsoluteUnit(decimal points)
	{
		if (points <= 0m || _pointValue <= 0m)
		return null;

		return new Unit(points * _pointValue, UnitTypes.Absolute);
	}
}