Five Ema NoTouch Breakout
Regras de negociação
Usar velas encerradas após formação da EMA. Vela inteiramente abaixo prepara compra acima da máxima; acima prepara venda abaixo da mínima. Verificar preparação anterior antes de substituí-la; tocar não rompe. Entrar apenas sem posição com Volume e limpar preparação durante a posição. Fixar stop no extremo oposto. A primeira execução real fixa risco até o stop e alvo a RewardRisk×risco. Proteção local nativa a mercado observa bid/ask entre velas. Execução além do stop é encerrada imediatamente. Sem espera nem aumento de posição.
Parâmetros
| Parâmetro | Padrão |
|---|---|
CandleType |
TimeSpan.FromMinutes(5).TimeFrame() |
EmaPeriod |
5 |
RewardRisk |
3 |
Verificação
Ambas as linguagens são verificadas com BTC/TON incluído, fórmulas independentes, direção/tamanho das ordens, execuções, posições e saídas. Dados datados de preços/fatores e calendário verificam mecânica; OHLC/volumes deslocados não são história plurianual. Dois grupos, TopN=1 e SMA=2 são perfis pequenos explícitos. Janelas longas e valores originais são verificados separadamente. Sem promessa de rentabilidade.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>Finished no-touch EMA setups with native protection fixed from actual entry risk.</summary>
public class FiveEmaNoTouchBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<decimal> _rewardRisk;
private Order _pending;
private ExponentialMovingAverage _ema;
private (decimal high, decimal low, Sides side)? _setup;
private decimal _setupStop;
private bool _isProtectionArmed;
/// <summary>Finished signal candle type.</summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>EMA length.</summary>
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
/// <summary>Take-profit distance divided by initial risk.</summary>
public decimal RewardRisk { get => _rewardRisk.Value; set => _rewardRisk.Value = value; }
/// <summary>Initialize the strategy parameters.</summary>
public FiveEmaNoTouchBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("CandleType", "Finished signal candle type.", "Parameters");
_emaPeriod = Param(nameof(EmaPeriod), 5).SetRange(1, int.MaxValue)
.SetDisplay("EmaPeriod", "EMA length.", "Parameters");
_rewardRisk = Param(nameof(RewardRisk), 3m).SetRange(0.000001m, decimal.MaxValue)
.SetDisplay("RewardRisk", "Take-profit distance divided by initial risk.", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_pending = null;
_ema = null;
_setup = null;
_setupStop = 0m;
_isProtectionArmed = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quote = new Subscription(DataType.Level1, Security);
quote.MarketData.BuildField = field;
SubscribeLevel1(quote).Start();
}
_ema = new ExponentialMovingAverage { Length = EmaPeriod };
SubscribeCandles(CandleType).Bind(_ema, ProcessCandle).Start();
}
private bool IsPending => _pending is not null && _pending.State is not (OrderStates.Done or OrderStates.Failed);
private void Submit(Sides side, decimal quantity, string comment)
{
_pending = CreateOrder(side, 0m, quantity);
_pending.Type = OrderTypes.Market;
_pending.Comment = comment;
RegisterOrder(_pending);
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished || !_ema.IsFormed || !IsFormedAndOnlineAndAllowTrading() || IsPending) return;
if (Position != 0m)
{
_setup = null;
return;
}
// Test the previous finished setup before a new candle can replace it.
if (_setup is { } setup && ((setup.side == Sides.Buy && candle.HighPrice > setup.high && candle.ClosePrice > setup.low)
|| (setup.side == Sides.Sell && candle.LowPrice < setup.low && candle.ClosePrice < setup.high)))
{
_setupStop = setup.side == Sides.Buy ? setup.low : setup.high;
_isProtectionArmed = false;
_setup = null;
Submit(setup.side, Volume, "0483Entry");
return;
}
if (candle.HighPrice < ema) _setup = (candle.HighPrice, candle.LowPrice, Sides.Buy);
else if (candle.LowPrice > ema) _setup = (candle.HighPrice, candle.LowPrice, Sides.Sell);
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
if (trade.Order.Comment != "0483Entry" || _isProtectionArmed) return;
_isProtectionArmed = true;
var risk = trade.Order.Side == Sides.Buy ? trade.Trade.Price - _setupStop : _setupStop - trade.Trade.Price;
if (risk <= 0m)
{
Submit(trade.Order.Side == Sides.Buy ? Sides.Sell : Sides.Buy, Math.Abs(Position), "0483InvalidFillExit");
return;
}
StartProtection(new Unit(risk * RewardRisk, UnitTypes.Absolute), new Unit(risk, UnitTypes.Absolute),
useMarketOrders: true, isLocalStop: true);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import DateTime, Decimal, Math, TimeSpan, InvalidOperationException
from System.Globalization import CultureInfo, DateTimeStyles
from System.IO import File
from StockSharp.Algo.Indicators import ExponentialMovingAverage, SimpleMovingAverage, AverageTrueRange, AlligatorLine, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from StockSharp.BusinessEntities import Subscription
from StockSharp.Messages import Level1Fields, ITickTradeMessage, CandleStates, DataType, OrderStates, OrderTypes, Sides, Unit, UnitTypes
class five_ema_no_touch_breakout_strategy(Strategy):
"""Finished no-touch EMA setups with native protection fixed from actual entry risk."""
def __init__(self):
super(five_ema_no_touch_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("CandleType", "Finished signal candle type.", "Parameters")
self._ema_period = self.Param("EmaPeriod", 5).SetRange(1, 2147483647) \
.SetDisplay("EmaPeriod", "EMA length.", "Parameters")
self._reward_risk = self.Param("RewardRisk", Decimal(3)).SetRange(Decimal(0.000001), Decimal.MaxValue) \
.SetDisplay("RewardRisk", "Take-profit distance divided by initial risk.", "Parameters")
self._clear_state()
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def RewardRisk(self):
return self._reward_risk.Value
@RewardRisk.setter
def RewardRisk(self, value):
self._reward_risk.Value = value
def _clear_state(self):
self._pending = None
self._ema = None
self._setup = None
self._setup_stop = Decimal(0)
self._is_protection_armed = False
def OnReseted(self):
super(five_ema_no_touch_breakout_strategy, self).OnReseted()
self._clear_state()
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnStarted2(self, time):
super(five_ema_no_touch_breakout_strategy, self).OnStarted2(time)
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quote = Subscription(DataType.Level1, self.Security)
quote.MarketData.BuildField = field
self.SubscribeLevel1(quote).Start()
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaPeriod
self.SubscribeCandles(self.CandleType).Bind(self._ema, self._process_candle).Start()
def _is_pending(self):
return self._pending is not None and self._pending.State not in (OrderStates.Done, OrderStates.Failed)
def _submit(self, side, quantity, comment):
self._pending = self.CreateOrder(side, Decimal(0), quantity)
self._pending.Type = OrderTypes.Market
self._pending.Comment = comment
self.RegisterOrder(self._pending)
@staticmethod
def _process(indicator, candle):
value = CandleIndicatorValue(indicator, candle)
value.IsFinal = True
result = indicator.Process(value)
return None if result.IsEmpty else result.GetValue[Decimal](None)
def _process_candle(self, candle, ema):
if candle.State != CandleStates.Finished or not self._ema.IsFormed or not self.IsFormedAndOnlineAndAllowTrading() or self._is_pending():
return
if self.Position != 0:
self._setup = None
return
if self._setup is not None:
high, low, side = self._setup
if (side == Sides.Buy and candle.HighPrice > high and candle.ClosePrice > low) or (side == Sides.Sell and candle.LowPrice < low and candle.ClosePrice < high):
self._setup_stop = low if side == Sides.Buy else high
self._is_protection_armed = False
self._setup = None
self._submit(side, self.Volume, "0483Entry")
return
if candle.HighPrice < ema:
self._setup = (candle.HighPrice, candle.LowPrice, Sides.Buy)
elif candle.LowPrice > ema:
self._setup = (candle.HighPrice, candle.LowPrice, Sides.Sell)
def OnOwnTradeReceived(self, trade):
super(five_ema_no_touch_breakout_strategy, self).OnOwnTradeReceived(trade)
if trade.Order.Comment != "0483Entry" or self._is_protection_armed:
return
self._is_protection_armed = True
risk = ITickTradeMessage.Price.__get__(trade.Trade) - self._setup_stop if trade.Order.Side == Sides.Buy else self._setup_stop - ITickTradeMessage.Price.__get__(trade.Trade)
if risk <= 0:
self._submit(Sides.Sell if trade.Order.Side == Sides.Buy else Sides.Buy, abs(self.Position), "0483InvalidFillExit")
return
self.StartProtection(Unit(risk * self.RewardRisk, UnitTypes.Absolute), Unit(risk, UnitTypes.Absolute), useMarketOrders=True, isLocalStop=True)
def CreateClone(self):
return five_ema_no_touch_breakout_strategy()