Estratégia de filtro de faixa de investidores Up3x1
Visão geral
Esta estratégia é uma porta direta do consultor especialista MetaTrader 4 up3x1_Investor. Ele negocia um único instrumento usando velas concluídas em um período configurável (H1 por padrão). A porta replica a lógica original com StockSharp APIs de alto nível e adiciona parâmetros claros de gerenciamento de risco.
Lógica de negociação
A estratégia avalia a última vela totalmente fechada e verifica se:
A faixa da vela (máxima menos mínima) excede 0.0060 unidades de preço.
O corpo da vela (diferença absoluta entre abertura e fechamento) excede 0.0050 unidades de preço.
Se a vela fechar em alta e as condições acima forem atendidas, a estratégia abre uma posição de mercado longa.
Se a vela fechar em baixa e as condições forem atendidas, a estratégia abre uma posição de mercado curta.
A negociação é completamente desativada às segundas-feiras (para espelhar a proteção DayOfWeek()==1 do código MQL).
Gerenciamento de posição
Após a entrada, a estratégia define metas internas usando as distâncias configuradas baseadas em etapas:
TakeProfitPoints → distância até a meta de lucro.
StopLossPoints → distância de parada protetora.
TrailingStopPoints → distância usada para rastrear o stop quando o preço se move a favor.
Stops e alvos são avaliados em cada vela finalizada:
Se o preço atingir o alvo, a posição será fechada ao preço alvo.
Se o preço atingir o stop, a posição será fechada para limitar a perda.
Uma vez que o preço avança além da distância de fuga, o stop é movido para mais perto do preço de mercado para garantir o lucro.
Além disso, se as médias móveis simples de 24 e 60 períodos calculadas nas mesmas velas se tornarem iguais (dentro de uma etapa de preço), a posição será fechada imediatamente. Isso imita a lógica MQL em que o pedido é fechado quando ambas as médias correspondem exatamente.
Gestão de Volume e Risco
BaseVolume define o tamanho do lote substituto quando nenhum ajuste baseado em conta pode ser calculado.
MaximumRisk replica a fórmula AccountFreeMargin()*MaximumRisk/1000 original. Se o valor do portfólio estiver disponível, a estratégia dimensiona a posição como value * MaximumRisk / 1000, arredondada para uma casa decimal.
DecreaseFactor imita a redução da sequência de perdas: após mais de uma perda consecutiva, o volume diminui proporcionalmente para losses / DecreaseFactor.
MinimumVolume garante que o volume nunca caia abaixo do menor tamanho negociável usado no script MQL (0,1 lote).
Parâmetros
Nome
Padrão
Descrição
BaseVolume
0.1
Tamanho base da posição em lotes quando nenhum ajuste de risco é aplicado.
MaximumRisk
0.2
Fator de risco usado para derivar o volume do patrimônio da conta (igual ao EA original).
DecreaseFactor
3
Reduz o tamanho da posição após perdas consecutivas.
MinimumVolume
0.1
Menor volume permitido.
TakeProfitPoints
20
Distância da meta de lucro medida em etapas de preço.
StopLossPoints
50
Distância de stop-loss medida em etapas de preço.
TrailingStopPoints
10
Distância do trailing stop medida em etapas de preço.
SkipMondays
true
Desative todas as atividades de negociação às segundas-feiras.
CandleType
1 hour
Prazo para assinatura da vela.
Notas
A estratégia mantém apenas uma posição aberta por vez, correspondendo à guarda CalculateCurrentOrders original.
O rastreamento de perdas consecutivas é puramente interno porque os corretores StockSharp não expõem o histórico de pedidos de MetaTrader.
Nenhuma ordem pendente é usada; todas as negociações são enviadas como ordens de mercado via BuyMarket e SellMarket.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Up3x1InvestorRangeFilterStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;
private int _cooldown;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Up3x1InvestorRangeFilterStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevEma = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevClose = close; _prevEma = ema;
return;
}
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 6;
}
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 6;
}
_prevClose = close; _prevEma = ema;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class up3x1_investor_range_filter_strategy(Strategy):
def __init__(self):
super(up3x1_investor_range_filter_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 14).SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0; self._prev_ema = 0.0; self._has_prev = False; self._cooldown = 0
@property
def ema_period(self): return self._ema_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(up3x1_investor_range_filter_strategy, self).OnReseted()
self._prev_close = 0.0; self._prev_ema = 0.0; self._has_prev = False; self._cooldown = 0
def OnStarted2(self, time):
super(up3x1_investor_range_filter_strategy, self).OnStarted2(time)
self._has_prev = False; self._cooldown = 0
ema = ExponentialMovingAverage(); ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema):
if candle.State != CandleStates.Finished: return
if not self.IsFormedAndOnlineAndAllowTrading(): return
close = float(candle.ClosePrice); ema_val = float(ema)
if not self._has_prev:
self._prev_close = close; self._prev_ema = ema_val; self._has_prev = True; return
if self._cooldown > 0:
self._cooldown -= 1; self._prev_close = close; self._prev_ema = ema_val; return
if self._prev_close <= self._prev_ema and close > ema_val and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume); self._cooldown = 6
elif self._prev_close >= self._prev_ema and close < ema_val and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume); self._cooldown = 6
self._prev_close = close; self._prev_ema = ema_val
def CreateClone(self): return up3x1_investor_range_filter_strategy()