Ver no GitHub

Estratégia Universal MA Cross V4

Visão geral

A Estratégia Universal MA Cross V4 é uma versão StockSharp de alto nível do consultor especialista MetaTrader 4 "Universal MACross EA v4". O algoritmo segue a interação entre uma média móvel rápida configurável e uma média móvel lenta. Ele suporta vários tipos de média móvel, fontes de preços selecionáveis, uma janela de negociação de hora em hora e gerenciamento de posição flexível, incluindo comportamento stop-and-reverse, metas de proteção e trailing stops. A estratégia é projetada para execução baseada em barras usando o StockSharp API de alto nível com assinaturas de velas.

Lógica de negociação

Processamento de indicadores

  • Duas médias móveis são avaliadas em cada vela finalizada. Cada média móvel pode usar seu próprio comprimento, método de suavização (Simples, Exponencial, Suavizado ou Linear Ponderado) e fonte de preço (fechamento, abertura, máximo, mínimo, mediano, típico ou ponderado).
  • O filtro MinCrossDistancePoints exige que as médias rápidas e lentas diverjam em pelo menos o número especificado de etapas de preço na barra de cruzamento. Quando ConfirmedOnEntry está habilitado, a divergência é validada na vela concluída anterior, reproduzindo o modo "confirmado" do EA original.
  • A configuração ReverseCondition troca sinais de alta e baixa sem alterar a configuração do indicador.

Regras de entrada

  1. Uma entrada longa ocorre quando a média rápida ultrapassa a média lenta em pelo menos MinCrossDistancePoints. Uma entrada curta requer a cruz oposta.
  2. Quando StopAndReverse for verdadeiro, um sinal oposto fecha a posição ativa antes que novas entradas sejam consideradas.
  3. OneEntryPerBar evita múltiplas entradas dentro da mesma vela rastreando o carimbo de data/hora do pedido mais recente.
  4. O tamanho do pedido é controlado por TradeVolume. StockSharp aplica automaticamente este volume às ordens de mercado geradas.

Gestão de posição

  • As distâncias de stop-loss e take-profit são definidas em pontos por meio de StopLossPoints e TakeProfitPoints. Eles são convertidos em preços absolutos usando a etapa de preço do instrumento. Quando PureSar está ativo, toda a lógica de proteção é desativada, assim como a opção "Pure SAR" na versão MQL.
  • O gerenciamento de trailing stop reflete a implementação MQL: quando o preço se move além de TrailingStopPoints em relação ao nível de entrada, o stop é puxado para trás do mercado pela mesma distância. As paradas finais são ignoradas quando PureSar está habilitado.
  • Os níveis de proteção são monitorados em cada vela fechada. Se o intervalo da vela violar o stop ou alvo ativo, a estratégia fecha a posição por ordem de mercado para manter o comportamento determinístico nos dados históricos.

Filtro de sessão

  • O sinalizador UseHourTrade restringe a negociação à janela inclusiva entre StartHour e EndHour (0–23). Os limites da sessão terminam por volta da meia-noite quando a hora final é menor que a hora inicial. O gerenciamento de posições, incluindo trailing stops, permanece ativo fora da sessão, mas nenhuma nova entrada é permitida.

Parâmetros

Parâmetro Descrição
FastMaPeriod, SlowMaPeriod Comprimentos das médias móveis rápidas e lentas.
FastMaType, SlowMaType Métodos de média móvel: Simples, Exponencial, Suavizada ou Linear Ponderada.
FastPriceType, SlowPriceType Fontes de preços alimentadas em cada média móvel.
StopLossPoints, TakeProfitPoints Distâncias de proteção nas etapas de preços. Defina como 0 para desativar.
TrailingStopPoints Distância do trailing stop em etapas de preço. Defina como 0 para desativar o rastreamento.
MinCrossDistancePoints Separação mínima entre as médias necessária para validar um cruzamento.
ReverseCondition Troque as regras de alta e de baixa sem alterar os indicadores.
ConfirmedOnEntry Valide os sinais na barra fechada anterior. Desative para confirmação imediata.
OneEntryPerBar Permita no máximo uma nova posição por vela.
StopAndReverse Feche e inverta a posição atual quando o sinal oposto aparecer.
PureSar Desative a lógica de stop-loss, take-profit e trailing stop.
UseHourTrade, StartHour, EndHour Filtro de sessão que restringe entradas a um intervalo de horas específico.
TradeVolume Volume de pedidos usado por BuyMarket e SellMarket.
CandleType Série de velas inscritas para cálculos de indicadores.

Notas de conversão

  • As distâncias baseadas em preços são expressas em MetaTrader pontos. O auxiliar GetPriceOffset converte esses valores em preços StockSharp usando a etapa de preço do título ou precisão decimal. Isso mantém o comportamento da estratégia alinhado com o EA original, independentemente do instrumento.
  • Os trailing stops são gerenciados internamente porque StockSharp estratégias de alto nível operam em velas finalizadas. Essa abordagem determinística garante que os backtests usando velas reproduzam a lógica de rastreamento MT4 pretendida.
  • Nenhuma porta Python está incluída, correspondendo à solicitação de conversão. Somente a implementação do C# e a documentação multilíngue são fornecidas neste pacote.
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>
/// Port of the "Universal MACross EA v4" MetaTrader expert advisor.
/// The strategy trades the crossover between configurable fast and slow moving averages
/// with optional session filters, stop-and-reverse behaviour and trailing stop management.
/// </summary>
public class UniversalMaCrossV4Strategy : Strategy
{
	public enum MovingAverageMethods
	{
		Simple,
		Exponential,
		Smoothed,
		LinearWeighted
	}

	public enum AppliedPrices
	{
		Close,
		Open,
		High,
		Low,
		Median,
		Typical,
		Weighted
	}

	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;
	private readonly StrategyParam<MovingAverageMethods> _fastMaType;
	private readonly StrategyParam<MovingAverageMethods> _slowMaType;
	private readonly StrategyParam<AppliedPrices> _fastPriceType;
	private readonly StrategyParam<AppliedPrices> _slowPriceType;
	private readonly StrategyParam<decimal> _stopLossPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<decimal> _trailingStopPoints;
	private readonly StrategyParam<decimal> _minCrossDistancePoints;
	private readonly StrategyParam<bool> _reverseCondition;
	private readonly StrategyParam<bool> _confirmedOnEntry;
	private readonly StrategyParam<bool> _oneEntryPerBar;
	private readonly StrategyParam<bool> _stopAndReverse;
	private readonly StrategyParam<bool> _pureSar;
	private readonly StrategyParam<bool> _useHourTrade;
	private readonly StrategyParam<int> _startHour;
	private readonly StrategyParam<int> _endHour;
	private readonly StrategyParam<decimal> _volume;
	private readonly StrategyParam<DataType> _candleType;

	private IIndicator _fastMa;
	private IIndicator _slowMa;

	private decimal? _fastPrev;
	private decimal? _fastPrevPrev;
	private decimal? _slowPrev;
	private decimal? _slowPrevPrev;

	private DateTimeOffset? _lastEntryBar;
	private TradeDirections _lastTrade = TradeDirections.None;

	private decimal? _entryPrice;
	private decimal? _stopPrice;
	private decimal? _takeProfitPrice;

	/// <summary>
	/// Fast moving average period.
	/// </summary>
	public int FastMaPeriod
	{
		get => _fastMaPeriod.Value;
		set => _fastMaPeriod.Value = value;
	}

	/// <summary>
	/// Slow moving average period.
	/// </summary>
	public int SlowMaPeriod
	{
		get => _slowMaPeriod.Value;
		set => _slowMaPeriod.Value = value;
	}

	/// <summary>
	/// Method applied to the fast moving average.
	/// </summary>
	public MovingAverageMethods FastMaType
	{
		get => _fastMaType.Value;
		set => _fastMaType.Value = value;
	}

	/// <summary>
	/// Method applied to the slow moving average.
	/// </summary>
	public MovingAverageMethods SlowMaType
	{
		get => _slowMaType.Value;
		set => _slowMaType.Value = value;
	}

	/// <summary>
	/// Price source for the fast moving average.
	/// </summary>
	public AppliedPrices FastPriceType
	{
		get => _fastPriceType.Value;
		set => _fastPriceType.Value = value;
	}

	/// <summary>
	/// Price source for the slow moving average.
	/// </summary>
	public AppliedPrices SlowPriceType
	{
		get => _slowPriceType.Value;
		set => _slowPriceType.Value = value;
	}

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

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

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

	/// <summary>
	/// Minimum distance between moving averages to validate a crossover.
	/// </summary>
	public decimal MinCrossDistancePoints
	{
		get => _minCrossDistancePoints.Value;
		set => _minCrossDistancePoints.Value = value;
	}

	/// <summary>
	/// Swap bullish and bearish signals when set to <c>true</c>.
	/// </summary>
	public bool ReverseCondition
	{
		get => _reverseCondition.Value;
		set => _reverseCondition.Value = value;
	}

	/// <summary>
	/// Require the crossover to be confirmed on the previous closed bar.
	/// </summary>
	public bool ConfirmedOnEntry
	{
		get => _confirmedOnEntry.Value;
		set => _confirmedOnEntry.Value = value;
	}

	/// <summary>
	/// Allow only one new position per candle.
	/// </summary>
	public bool OneEntryPerBar
	{
		get => _oneEntryPerBar.Value;
		set => _oneEntryPerBar.Value = value;
	}

	/// <summary>
	/// Close and reverse the active position when the opposite signal appears.
	/// </summary>
	public bool StopAndReverse
	{
		get => _stopAndReverse.Value;
		set => _stopAndReverse.Value = value;
	}

	/// <summary>
	/// Disable stop-loss, take-profit and trailing stop logic.
	/// </summary>
	public bool PureSar
	{
		get => _pureSar.Value;
		set => _pureSar.Value = value;
	}

	/// <summary>
	/// Enable the hour-based trading session filter.
	/// </summary>
	public bool UseHourTrade
	{
		get => _useHourTrade.Value;
		set => _useHourTrade.Value = value;
	}

	/// <summary>
	/// Start hour of the trading window (0-23).
	/// </summary>
	public int StartHour
	{
		get => _startHour.Value;
		set => _startHour.Value = value;
	}

	/// <summary>
	/// End hour of the trading window (0-23).
	/// </summary>
	public int EndHour
	{
		get => _endHour.Value;
		set => _endHour.Value = value;
	}

	/// <summary>
	/// Order volume applied to each market order.
	/// </summary>
	public decimal TradeVolume
	{
		get => _volume.Value;
		set => _volume.Value = value;
	}

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

	/// <summary>
	/// Initializes a new instance of the <see cref="UniversalMaCrossV4Strategy"/> class.
	/// </summary>
	public UniversalMaCrossV4Strategy()
	{
		_fastMaPeriod = Param(nameof(FastMaPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA Period", "Length of the fast moving average", "Indicators")
			
			.SetOptimize(5, 40, 1);

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 80)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA Period", "Length of the slow moving average", "Indicators")
			
			.SetOptimize(30, 200, 5);

		_fastMaType = Param(nameof(FastMaType), MovingAverageMethods.Exponential)
			.SetDisplay("Fast MA Method", "Smoothing method applied to the fast moving average", "Indicators");

		_slowMaType = Param(nameof(SlowMaType), MovingAverageMethods.Exponential)
			.SetDisplay("Slow MA Method", "Smoothing method applied to the slow moving average", "Indicators");

		_fastPriceType = Param(nameof(FastPriceType), AppliedPrices.Close)
			.SetDisplay("Fast MA Price", "Price source injected into the fast moving average", "Indicators");

		_slowPriceType = Param(nameof(SlowPriceType), AppliedPrices.Close)
			.SetDisplay("Slow MA Price", "Price source injected into the slow moving average", "Indicators");

		_stopLossPoints = Param(nameof(StopLossPoints), 100m)
			.SetNotNegative()
			.SetDisplay("Stop Loss (points)", "Stop-loss distance in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 200m)
			.SetNotNegative()
			.SetDisplay("Take Profit (points)", "Take-profit distance in price steps", "Risk");

		_trailingStopPoints = Param(nameof(TrailingStopPoints), 40m)
			.SetNotNegative()
			.SetDisplay("Trailing Stop (points)", "Trailing stop distance in price steps", "Risk");

		_minCrossDistancePoints = Param(nameof(MinCrossDistancePoints), 0m)
			.SetNotNegative()
			.SetDisplay("Min Cross Distance (points)", "Minimum separation between the moving averages", "Filters");

		_reverseCondition = Param(nameof(ReverseCondition), false)
			.SetDisplay("Reverse Signals", "Swap bullish and bearish conditions", "General");

		_confirmedOnEntry = Param(nameof(ConfirmedOnEntry), true)
			.SetDisplay("Confirmed On Entry", "Validate signals on the previous closed bar", "General");

		_oneEntryPerBar = Param(nameof(OneEntryPerBar), true)
			.SetDisplay("One Entry Per Bar", "Allow at most one entry per candle", "General");

		_stopAndReverse = Param(nameof(StopAndReverse), true)
			.SetDisplay("Stop And Reverse", "Close and reverse when the opposite signal appears", "Risk");

		_pureSar = Param(nameof(PureSar), false)
			.SetDisplay("Pure SAR", "Disable protective stops and trailing", "Risk");

		_useHourTrade = Param(nameof(UseHourTrade), false)
			.SetDisplay("Use Hour Filter", "Restrict trading to a specific session", "Session");

		_startHour = Param(nameof(StartHour), 10)
			.SetDisplay("Start Hour", "Trading window start hour", "Session");

		_endHour = Param(nameof(EndHour), 11)
			.SetDisplay("End Hour", "Trading window end hour", "Session");

		_volume = Param(nameof(TradeVolume), 1m)
			.SetGreaterThanZero()
			.SetDisplay("Trade Volume", "Order volume for each market entry", "Trading");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Primary candle subscription used by the strategy", "General");
	}

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

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

		_fastMa = null;
		_slowMa = null;
		_fastPrev = null;
		_fastPrevPrev = null;
		_slowPrev = null;
		_slowPrevPrev = null;
		_lastEntryBar = null;
		_lastTrade = TradeDirections.None;
		_entryPrice = null;
		_stopPrice = null;
		_takeProfitPrice = null;

		Volume = TradeVolume;
	}

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

		_fastMa = CreateMovingAverage(FastMaType, FastMaPeriod);
		_slowMa = CreateMovingAverage(SlowMaType, SlowMaPeriod);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _fastMa);
			DrawIndicator(area, _slowMa);
			DrawOwnTrades(area);
		}

		StartProtection(null, null);
	}

	private void ProcessCandle(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		ManageExistingPosition(candle);

		if (_fastMa is null || _slowMa is null)
			return;

		var fastPrice = GetPrice(candle, FastPriceType);
		var slowPrice = GetPrice(candle, SlowPriceType);

		var fastResult = _fastMa.Process(new DecimalIndicatorValue(_fastMa, fastPrice, candle.OpenTime) { IsFinal = true });
		if (fastResult.IsEmpty) return;
		var fastValue = fastResult.GetValue<decimal>();
		var slowResult = _slowMa.Process(new DecimalIndicatorValue(_slowMa, slowPrice, candle.OpenTime) { IsFinal = true });
		if (slowResult.IsEmpty) return;
		var slowValue = slowResult.GetValue<decimal>();

		var prevFast = _fastPrev;
		var prevSlow = _slowPrev;
		var prevFastPrev = _fastPrevPrev;
		var prevSlowPrev = _slowPrevPrev;

		_fastPrevPrev = prevFast;
		_slowPrevPrev = prevSlow;
		_fastPrev = fastValue;
		_slowPrev = slowValue;

		

		var minDistance = GetPriceOffset(MinCrossDistancePoints);

		var crossUp = false;
		var crossDown = false;

		if (ConfirmedOnEntry)
		{
			// Confirm signals using the previous completed bar (shift 2 -> 1 in MQL terms).
			if (prevFast.HasValue && prevSlow.HasValue && prevFastPrev.HasValue && prevSlowPrev.HasValue)
			{
				var diff = prevFast.Value - prevSlow.Value;
				crossUp = prevFastPrev.Value < prevSlowPrev.Value && prevFast.Value > prevSlow.Value && diff >= minDistance;
				crossDown = prevFastPrev.Value > prevSlowPrev.Value && prevFast.Value < prevSlow.Value && -diff >= minDistance;
			}
		}
		else
		{
			// Validate crossovers on the current finished bar.
			if (prevFast.HasValue && prevSlow.HasValue)
			{
				var diff = fastValue - slowValue;
				crossUp = prevFast.Value < prevSlow.Value && fastValue > slowValue && diff >= minDistance;
				crossDown = prevFast.Value > prevSlow.Value && fastValue < slowValue && -diff >= minDistance;
			}
		}

		bool buySignal;
		bool sellSignal;

		if (!ReverseCondition)
		{
			buySignal = crossUp;
			sellSignal = crossDown;
		}
		else
		{
			buySignal = crossDown;
			sellSignal = crossUp;
		}

		if (!IsWithinTradingHours(candle))
			return;

		if (StopAndReverse && Position != 0)
		{
			var reverseToShort = _lastTrade == TradeDirections.Long && sellSignal;
			var reverseToLong = _lastTrade == TradeDirections.Short && buySignal;

			if (reverseToLong || reverseToShort)
			{
				ClosePosition();
				ResetProtection();
				_lastTrade = TradeDirections.None;
			}
		}

		if (Position != 0)
			return;

		if (OneEntryPerBar && _lastEntryBar == candle.OpenTime)
			return;

		if (buySignal)
		{
			BuyMarket(TradeVolume);
			SetProtectionLevels(candle.ClosePrice, true);
			_lastTrade = TradeDirections.Long;
			_lastEntryBar = candle.OpenTime;
		}
		else if (sellSignal)
		{
			SellMarket(TradeVolume);
			SetProtectionLevels(candle.ClosePrice, false);
			_lastTrade = TradeDirections.Short;
			_lastEntryBar = candle.OpenTime;
		}
	}

	private void ManageExistingPosition(ICandleMessage candle)
	{
		if (Position == 0)
		{
			ResetProtection();
			return;
		}

		UpdateTrailingStop(candle);

		if (Position > 0)
		{
			if (_stopPrice.HasValue && candle.LowPrice <= _stopPrice.Value)
			{
				ClosePosition();
				ResetProtection();
				return;
			}

			if (_takeProfitPrice.HasValue && candle.HighPrice >= _takeProfitPrice.Value)
			{
				ClosePosition();
				ResetProtection();
			}
		}
		else if (Position < 0)
		{
			if (_stopPrice.HasValue && candle.HighPrice >= _stopPrice.Value)
			{
				ClosePosition();
				ResetProtection();
				return;
			}

			if (_takeProfitPrice.HasValue && candle.LowPrice <= _takeProfitPrice.Value)
			{
				ClosePosition();
				ResetProtection();
			}
		}
	}

	private void UpdateTrailingStop(ICandleMessage candle)
	{
		if (PureSar || TrailingStopPoints <= 0m || !_entryPrice.HasValue)
			return;

		var trailingDistance = GetPriceOffset(TrailingStopPoints);
		if (trailingDistance <= 0m)
			return;

		if (Position > 0)
		{
			var move = candle.ClosePrice - _entryPrice.Value;
			if (move > trailingDistance)
			{
				var candidate = candle.ClosePrice - trailingDistance;
				if (!_stopPrice.HasValue || candidate > _stopPrice.Value)
				{
					_stopPrice = candidate;
				}
			}
		}
		else if (Position < 0)
		{
			var move = _entryPrice.Value - candle.ClosePrice;
			if (move > trailingDistance)
			{
				var candidate = candle.ClosePrice + trailingDistance;
				if (!_stopPrice.HasValue || candidate < _stopPrice.Value)
				{
					_stopPrice = candidate;
				}
			}
		}
	}

	private bool IsWithinTradingHours(ICandleMessage candle)
	{
		if (!UseHourTrade)
			return true;

		var hour = candle.OpenTime.Hour;
		var start = StartHour;
		var end = EndHour;

		if (start <= end)
			return hour >= start && hour <= end;

		return hour >= start || hour <= end;
	}

	private static IIndicator CreateMovingAverage(MovingAverageMethods method, int period)
	{
		return method switch
		{
			MovingAverageMethods.Simple => new SimpleMovingAverage { Length = period },
			MovingAverageMethods.Exponential => new ExponentialMovingAverage { Length = period },
			MovingAverageMethods.Smoothed => new SmoothedMovingAverage { Length = period },
			MovingAverageMethods.LinearWeighted => new WeightedMovingAverage { Length = period },
			_ => new SimpleMovingAverage { Length = period }
		};
	}

	private static decimal GetPrice(ICandleMessage candle, AppliedPrices priceType)
	{
		return priceType switch
		{
			AppliedPrices.Open => candle.OpenPrice,
			AppliedPrices.High => candle.HighPrice,
			AppliedPrices.Low => candle.LowPrice,
			AppliedPrices.Median => (candle.HighPrice + candle.LowPrice) / 2m,
			AppliedPrices.Typical => (candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 3m,
			AppliedPrices.Weighted => (candle.HighPrice + candle.LowPrice + 2m * candle.ClosePrice) / 4m,
			_ => candle.ClosePrice,
		};
	}

	private void SetProtectionLevels(decimal entryPrice, bool isLong)
	{
		_entryPrice = entryPrice;

		if (PureSar)
		{
			_stopPrice = null;
			_takeProfitPrice = null;
			return;
		}

		var stopDistance = GetPriceOffset(StopLossPoints);
		var takeDistance = GetPriceOffset(TakeProfitPoints);

		_stopPrice = stopDistance > 0m ? (isLong ? entryPrice - stopDistance : entryPrice + stopDistance) : null;
		_takeProfitPrice = takeDistance > 0m ? (isLong ? entryPrice + takeDistance : entryPrice - takeDistance) : null;
	}

	private void ResetProtection()
	{
		_entryPrice = null;
		_stopPrice = null;
		_takeProfitPrice = null;
	}

	private decimal GetPriceOffset(decimal points)
	{
		if (points <= 0m)
			return 0m;

		var step = Security?.PriceStep ?? 0m;
		if (step > 0m)
			return points * step;

		var decimals = Security?.Decimals;
		if (decimals.HasValue && decimals.Value > 0)
		{
			decimal scale = 1m;
			for (var i = 0; i < decimals.Value; i++)
				scale /= 10m;

			return points * scale;
		}

		return points;
	}

	private void ClosePosition()
	{
		if (Position > 0)
			SellMarket();
		else if (Position < 0)
			BuyMarket();
	}

	private enum TradeDirections
	{
		None,
		Long,
		Short
	}
}