A Estratégia GPF TCPivotLimit recria o MetaTrader 4 consultor especialista gpfTCPivotLimit.mq4 dentro da estrutura StockSharp. O sistema negocia em velas horárias e reage a reversões em torno dos clássicos níveis de pivô diários. A cada novo dia de negociação, a estratégia calcula o pivô, três níveis de resistência (R1–R3) e três níveis de suporte (S1–S3) da máxima, mínima e fechamento do dia anterior. Assim que o dia seguinte começa, ele avalia as duas últimas velas horárias concluídas para decidir se o preço rejeitou uma zona de resistência ou suporte e abre uma ordem de mercado na direção oposta.
Lógica de negociação
Cálculo de pivô – quando uma nova sessão diária começa, a estratégia armazena a máxima, a mínima e o fechamento do dia anterior e, em seguida, calcula:
Confirmação de entrada – com o novo dia em andamento as duas últimas velas horárias fechadas (t-2 e t-1) são inspecionadas.
Uma venda será aberta se a vela t-2 for sondada acima da resistência selecionada (alta acima ou perto do nível), aberta abaixo dela e a vela t-1 fechar abaixo do nível.
Uma longa será aberta se a vela t-2 cair abaixo do suporte selecionado (baixo abaixo ou fechar no nível), abrir acima dele e a vela t-1 fechar novamente acima do nível.
Predefinições de metas – o consultor especialista original expõe cinco layouts de lucro/stop. A tabela abaixo mostra o mapeamento exato preservado nesta porta.
TargetMode
Gatilho longo
Parada longa
Alvo longo
Gatilho curto
Parada curta
Alvo curto
1
S1
S2
R1
R1
R2
S1
2
S1
S2
R2
R1
R2
S2
3
S2
S3
R1
R2
R3
S1
4
S2
S3
R2
R2
R3
S2
5
S2
S3
R3
R2
R3
S3
Gerenciamento de risco – verificações protetoras de stop-loss e take-profit são executadas em cada vela concluída. A lógica opcional de trailing stop emula o comportamento do MT4: quando o lucro não realizado excede a distância configurada, o stop é movido em favor da negociação. Uma saída opcional no final do dia nivela a posição às 23h, horário da plataforma.
Adaptação de volume – a entrada MetaTrader isFloatLots é espelhada pelo botão de alternância UseDynamicVolume. Quando ativado, o tamanho da posição é reduzido após negociações consecutivas com perdas, usando as entradas DrawdownFactor e RiskPercentage.
Parâmetros
Nome
Descrição
Padrão
BaseVolume
Volume base enviado com cada ordem de mercado antes dos ajustes de risco.
1
UseDynamicVolume
Reduz o tamanho da negociação após mais de uma perda consecutiva.
false
RiskPercentage
Razão de risco por negociação de referência usada para dimensionar o volume base (MetaTrader MaxR).
0.02
DrawdownFactor
Divisor aplicado ao diminuir o volume após uma seqüência de derrotas (MetaTrader DcF).
3
TargetMode
Seleciona a combinação de resistência/suporte listada acima (MetaTrader TgtProfit).
1
TrailingPoints
Distância de parada móvel expressa em pontos do instrumento. Defina como 0 para desativar.
30
CloseAtSessionEnd
Quando true todas as posições são fechadas no fechamento da vela das 23:00.
false
LogSignals
Imprime valores pivô, entradas e saídas no log de estratégia.
false
CandleType
Tipo de dados de vela usado para análise (o padrão é velas de 1 hora).
TimeFrameCandleMessage(1h)
Notas
A estratégia emite ordens de mercado assim como o EA original e não coloca ordens pendentes.
Os eventos stop-loss e take-profit são executados com saídas de mercado para permanecerem compatíveis com todos os conectores StockSharp.
As distâncias finais dependem do instrumento PriceStep. Se a etapa estiver faltando, o mecanismo de rastreamento será automaticamente desativado.
O sinalizador de notificação por e-mail da versão MT4 é representado por LogSignals, produzindo mensagens de log em vez de e-mails.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class GpfTcpPivotLimitStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevMid; private bool _hasPrev;
private int _cooldown;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public GpfTcpPivotLimitStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 20).SetDisplay("Channel Period", "Pivot lookback", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevMid = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevClose = close; _prevMid = mid;
return;
}
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevClose = close; _prevMid = mid;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class gpf_tcp_pivot_limit_strategy(Strategy):
"""
GPF TCP Pivot Limit: Donchian channel midline crossover.
Buys when close crosses above channel midpoint.
Sells when close crosses below channel midpoint.
"""
def __init__(self):
super(gpf_tcp_pivot_limit_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 20) \
.SetDisplay("Channel Period", "Pivot lookback", "Indicators")
self._ema_period = self.Param("EmaPeriod", 14) \
.SetDisplay("EMA Period", "EMA filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(gpf_tcp_pivot_limit_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(gpf_tcp_pivot_limit_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self._channel_period.Value
lowest = Lowest()
lowest.Length = self._channel_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, highest_val, lowest_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
h = float(highest_val)
l = float(lowest_val)
mid = (h + l) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_close = close
self._prev_mid = mid
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
self.BuyMarket()
self._cooldown = 2
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
self.SellMarket()
self._cooldown = 2
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return gpf_tcp_pivot_limit_strategy()