Esta estratégia é um port StockSharp do expert advisor "PSAR Trader EA" do MetaTrader. Ela observa como o preço interage com o indicador Parabolic SAR e reage apenas quando o campo de pontos vira de um lado do corpo do candle para o outro. A conversão preserva a lógica original de gestão monetária: a estratégia pode negociar com lote fixo ou ajustar dinamicamente o volume da ordem com base no saldo da conta, aplica stop-loss e take-profit fixos e ativa trailing stop quando uma operação acumula lucro suficiente.
Lógica da estratégia
Construir um indicador Parabolic SAR com aceleração e valores máximos definidos pelo usuário na série de candles selecionada (candles de 30 minutos por padrão).
Detectar uma virada altista quando o ponto SAR se move de acima do corpo do candle para abaixo dele. Se não houver posição aberta, enviar uma ordem de compra a mercado. Se existir uma posição vendida, fechá-la primeiro e aguardar o próximo sinal para reentrar comprado.
Detectar uma virada baixista quando o ponto SAR se move de abaixo do corpo do candle para acima dele. Se estiver zerado, abrir uma posição vendida. Se uma posição comprada estiver ativa, fechá-la e adiar a entrada até o sinal seguinte.
Monitorar operações abertas em cada candle concluído e executar saídas quando qualquer nível protetor (stop-loss, take-profit ou trailing stop) for alcançado pela máxima/mínima do candle atual.
Gestão de risco
Stop loss: expresso em pontos (passos de preço). Para compras, o stop é colocado abaixo do preço de entrada; para vendas, acima.
Take profit: também expresso em pontos. A meta espelha o stop na direção oposta e fecha a posição inteira quando alcançada.
Trailing stop: começa depois que o preço se move por um número configurável de pontos a favor da operação. O trailing stop aperta apenas na direção do lucro, replicando o comportamento "tighten stops only" do EA original.
Gestão de volume
Lote fixo: quando auto-lote está desabilitado, a estratégia envia ordens com o lote fixo configurado.
Lote baseado no saldo: quando auto-lote está habilitado, o volume é calculado como (Account Balance / 1000) * LotsPerThousand e alinhado ao passo de volume e volume mínimo do ativo.
Parâmetros e padrões
SarStep: fator de aceleração do Parabolic SAR. Padrão: 0.02.
SarMaximum: aceleração máxima do Parabolic SAR. Padrão: 0.2.
CandleType: timeframe para análise. Padrão: candles de 30 minutos.
UseAutoLot: habilita dimensionamento dinâmico de lote. Padrão: false.
FixedLot: volume usado quando auto lote está desligado. Padrão: 0.1.
LotsPerThousand: multiplicador para cálculos de auto-lote. Padrão: 0.05.
StopLossPoints: distância até o stop em pontos. Padrão: 500.
TakeProfitPoints: distância até o take profit em pontos. Padrão: 1000.
TrailingStartPoints: limiar de lucro que habilita trailing. Padrão: 500.
TrailingDistancePoints: offset de trailing quando habilitado. Padrão: 100.
Notas
A estratégia negocia direções comprada e vendida, mas mantém no máximo uma posição aberta por vez.
Ordens protetoras são simuladas em dados de candles; picos intrabar menores que o timeframe selecionado podem influenciar a qualidade de execução no trading ao vivo.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR Cross strategy: PSAR crossover.
/// Buys when close crosses above PSAR. Sells when close crosses below PSAR.
/// </summary>
public class ParabolicSarCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ParabolicSarCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sar = new ParabolicSar { Acceleration = 0.02m, AccelerationStep = 0.02m, AccelerationMax = 0.2m };
decimal? prevSar = null;
decimal? prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sar, (candle, sarVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevSar.HasValue && prevClose.HasValue)
{
var crossUp = prevClose.Value <= prevSar.Value && close > sarVal;
var crossDown = prevClose.Value >= prevSar.Value && close < sarVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevSar = sarVal;
prevClose = close;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
}
}
}
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 ParabolicSar
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class parabolic_sar_cross_strategy(Strategy):
def __init__(self):
super(parabolic_sar_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(parabolic_sar_cross_strategy, self).OnReseted()
self._prev_sar = None
self._prev_close = None
def OnStarted2(self, time):
super(parabolic_sar_cross_strategy, self).OnStarted2(time)
self._prev_sar = None
self._prev_close = None
sar = ParabolicSar()
sar.Acceleration = 0.02
sar.AccelerationStep = 0.02
sar.AccelerationMax = 0.2
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sar, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sar_val):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if self._prev_sar is not None and self._prev_close is not None:
cross_up = self._prev_close <= self._prev_sar and close > sar_val
cross_down = self._prev_close >= self._prev_sar and close < sar_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_sar = sar_val
self._prev_close = close
def CreateClone(self):
return parabolic_sar_cross_strategy()