A Cryptos Strategy é uma versão StockSharp de alto nível do consultor especialista MetaTrader4 original cryptos.mq4. Ele se concentra no par ETH/USD, combinando bandas Bollinger com uma média móvel ponderada linear (LWMA) para capturar rompimentos da compressão de volatilidade. A estratégia rastreia altos e baixos em um número configurável de velas e calcula dinamicamente as metas de lucro como um múltiplo do intervalo detectado.
Lógica de negociação
Detecção de tendência – quando o preço de fechamento toca a banda superior Bollinger, a estratégia muda para uma tendência curta, e quando a banda inferior é tocada, ela muda para uma tendência longa. O toque da banda também congela os valores de swing atuais, desativando as atualizações automáticas de altos/baixos.
Condições de entrada –
Abra uma posição curta quando o preço de fechamento cair abaixo do LWMA, a tendência for curta e não houver posição curta ativa.
Abra uma posição longa quando o preço de fechamento subir acima do LWMA, o viés for longo e não houver posição longa ativa.
Projeção de alcance – oscilações máximas e mínimas (automáticas ou congeladas manualmente) definem a distância do LWMA. Esta distância, expressa em ticks, é multiplicada pelo índice de take-profit para calcular as metas de lucro e o tamanho da posição com base no risco.
Controle de risco – a estratégia define níveis de take-profit e stop-loss por negociação. Para posições compradas, o stop é colocado abaixo do swing low; para shorts, acima do balanço alto. Stops e metas são recalculados para cada entrada e aplicados dentro do ciclo estratégico.
Saídas finais – se uma posição longa fechar abaixo da banda inferior Bollinger (ou uma posição curta acima da banda superior), a posição aberta será achatada imediatamente, imitando o comportamento final do EA original.
Parâmetros
Parâmetro
Descrição
CandleType
Tipo de dados da série de velas usada para todos os cálculos de indicadores.
BollingerPeriod, BollingerWidth
Multiplicador de comprimento e desvio padrão das bandas Bollinger.
MaPeriod
Período da média móvel ponderada linear com base nos preços medianos.
LookbackCandles
Número de velas examinadas para determinar a oscilação automática de alta/baixa.
TakeProfitRatio
Multiplicador de intervalo usado para metas de lucro ao negociar ETH/USD.
AlternativeTakeProfitRatio
Multiplicador de alcance aplicado a todos os outros símbolos.
RiskPerTrade
Quantidade de capital (na moeda de cotação) que a calculadora de volume tenta arriscar em cada negociação.
ValueIndex, CryptoValueIndex
Multiplicadores convertendo risco em volume para símbolos não criptográficos e criptográficos, respectivamente.
MinVolume, MaxVolume
Limites rígidos para o tamanho da posição após o alinhamento para trocar etapas de volume.
MinRangeTicks
Faixa projetada mínima permitida em ticks para evitar paradas de distância zero.
SpreadPoints
Substituição manual do spread em ticks (detectado automaticamente a partir do melhor lance/pergunta, se disponível).
GlobalTrend
Substituição manual de polarização: 1 força uma configuração curta, 2 força uma configuração longa, 0 deixa a estratégia decidir.
AutoHighLow
Quando habilitado, os pontos de oscilação são recalculados em cada vela; quando desativados, eles ficam congelados até o próximo toque na banda.
ManualBuyTrigger, ManualSellTrigger
Defina como true para solicitar uma entrada longa ou curta imediata (redefinida após a execução).
SkipBuys, SkipSells
Desative a abertura de novas posições longas ou curtas.
Dimensionamento de posições
A estratégia replica a lógica MT4: volume = RiskPerTrade / rangeTicks * valueIndex. O resultado é alinhado a VolumeStep e, em seguida, recortado entre MinVolume/MaxVolume e os limites impostos pela exchange do instrumento.
Notas de uso
A estratégia verifica o valor do portfólio no início. Se o saldo for inferior a RiskPerTrade * 3, a negociação será desativada e um aviso será registrado, correspondendo à verificação de segurança de EA.
Os gatilhos manuais e os controles de polarização possibilitam a sincronização com decisões discricionárias durante a negociação ao vivo.
ETH/USD usa automaticamente CryptoValueIndex e TakeProfitRatio; outros instrumentos recorrem aos parâmetros alternativos.
As paradas e os alvos são aplicados dentro do ciclo estratégico, portanto, nenhum módulo de proteção adicional é necessário.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Cryptos" MetaTrader expert.
/// Uses Bollinger Bands with a WMA trend filter. Buys when price is below WMA
/// and touches lower band; sells when price is above WMA and touches upper band.
/// </summary>
public class CryptosStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _wmaPeriod;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private ExponentialMovingAverage _bandEma;
private ExponentialMovingAverage _trendEma;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int WmaPeriod
{
get => _wmaPeriod.Value;
set => _wmaPeriod.Value = value;
}
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerWidth
{
get => _bollingerWidth.Value;
set => _bollingerWidth.Value = value;
}
public CryptosStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signals", "General");
_wmaPeriod = Param(nameof(WmaPeriod), 55)
.SetGreaterThanZero()
.SetDisplay("WMA Period", "Weighted moving average period", "Indicators");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 2m)
.SetGreaterThanZero()
.SetDisplay("BB Width", "Bollinger Bands deviation", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bandEma = new ExponentialMovingAverage { Length = BollingerPeriod };
_trendEma = new ExponentialMovingAverage { Length = WmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_bandEma, _trendEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bandEma);
DrawIndicator(area, _trendEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal bandValue, decimal trendValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bandEma.IsFormed || !_trendEma.IsFormed)
return;
var close = candle.ClosePrice;
var bandOffset = bandValue * (BollingerWidth / 100m);
var upperBand = bandValue + bandOffset;
var lowerBand = bandValue - bandOffset;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Buy: price below WMA, touches lower band
if (close < trendValue && close <= lowerBand)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
// Sell: price above WMA, touches upper band
else if (close > trendValue && close >= upperBand)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
// Exit at WMA cross
if (Position > 0 && close >= upperBand)
SellMarket(Position);
else if (Position < 0 && close <= lowerBand)
BuyMarket(Math.Abs(Position));
}
/// <inheritdoc />
protected override void OnReseted()
{
_bandEma = null;
_trendEma = null;
base.OnReseted();
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class cryptos_strategy(Strategy):
def __init__(self):
super(cryptos_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._wma_period = self.Param("WmaPeriod", 55)
self._bollinger_period = self.Param("BollingerPeriod", 20)
self._bollinger_width = self.Param("BollingerWidth", 2.0)
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def WmaPeriod(self):
return self._wma_period.Value
@WmaPeriod.setter
def WmaPeriod(self, value):
self._wma_period.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
@BollingerWidth.setter
def BollingerWidth(self, value):
self._bollinger_width.Value = value
def OnReseted(self):
super(cryptos_strategy, self).OnReseted()
def OnStarted2(self, time):
super(cryptos_strategy, self).OnStarted2(time)
band_ema = ExponentialMovingAverage()
band_ema.Length = self.BollingerPeriod
trend_ema = ExponentialMovingAverage()
trend_ema.Length = self.WmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(band_ema, trend_ema, self._process_candle).Start()
def _process_candle(self, candle, band_value, trend_value):
if candle.State != CandleStates.Finished:
return
band_val = float(band_value)
trend_val = float(trend_value)
close = float(candle.ClosePrice)
band_offset = band_val * (float(self.BollingerWidth) / 100.0)
upper_band = band_val + band_offset
lower_band = band_val - band_offset
# Buy: price below WMA, touches lower band
if close < trend_val and close <= lower_band:
if self.Position <= 0:
self.BuyMarket()
# Sell: price above WMA, touches upper band
elif close > trend_val and close >= upper_band:
if self.Position >= 0:
self.SellMarket()
# Exit at opposite band
if self.Position > 0 and close >= upper_band:
self.SellMarket()
elif self.Position < 0 and close <= lower_band:
self.BuyMarket()
def CreateClone(self):
return cryptos_strategy()