Estrategia EA Template
Esta estrategia se origina en una plantilla de EA de MetaTrader. Analiza la vela finalizada anterior y abre una posición en la dirección del cuerpo de la vela. Una vela alcista activa una operación larga, mientras que una vela bajista activa una corta. El modo de reversión invierte la interpretación de la vela para que la estrategia opere contra el color de la barra.
La estrategia admite tamaño de posición fijo o cálculo basado en el capital. Los niveles de stop-loss y take-profit se establecen en puntos desde el precio de entrada. La operación se omite cuando el spread supera el umbral permitido.
Detalles
- Criterios de entrada:
- Largo: el cierre de la vela anterior > apertura y
ReverseTradedeshabilitado. - Corto: el cierre de la vela anterior < apertura y
ReverseTradedeshabilitado. - Cuando
ReverseTradeestá habilitado, las señales se invierten. - El spread debe estar por debajo de
SpreadLimitpuntos.
- Largo: el cierre de la vela anterior > apertura y
- Criterios de salida:
- Color de vela opuesto o activación de stop-loss/take-profit.
- Tamaño de posición:
- Tamaño fijo
Lotso tamaño basado en capital usandoRiskPercentcuandoUseMoneyManagementes true.
- Tamaño fijo
- Stops:
StopLossyTakeProfiten puntos relativos al precio de entrada.
- Largo/Corto: Ambas direcciones.
- Indicadores: Ninguno.
- Nivel de riesgo: Medio.
Los parámetros permiten ajustar el tipo de vela, el modo de reversión, las reglas de gestión del dinero y los límites de riesgo.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simple candle color strategy converted from a MetaTrader expert advisor.
/// Opens a long position after a bullish candle and a short position after a bearish one.
/// Optional reverse mode flips entry and exit signals.
/// </summary>
public class EaTemplateStrategy : Strategy
{
private readonly StrategyParam<bool> _reverseTrade;
private readonly StrategyParam<bool> _useMoneyManagement;
private readonly StrategyParam<decimal> _riskPercent;
private readonly StrategyParam<decimal> _lots;
private readonly StrategyParam<int> _stopLoss;
private readonly StrategyParam<int> _takeProfit;
private readonly StrategyParam<int> _spreadLimit;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _prevClose;
private decimal _prevSma;
private int _barsSinceTrade;
/// <summary>
/// Invert entry and exit signals.
/// </summary>
public bool ReverseTrade
{
get => _reverseTrade.Value;
set => _reverseTrade.Value = value;
}
/// <summary>
/// Use equity based volume calculation.
/// </summary>
public bool UseMoneyManagement
{
get => _useMoneyManagement.Value;
set => _useMoneyManagement.Value = value;
}
/// <summary>
/// Percent of equity to risk per trade.
/// </summary>
public decimal RiskPercent
{
get => _riskPercent.Value;
set => _riskPercent.Value = value;
}
/// <summary>
/// Fixed order size.
/// </summary>
public decimal Lots
{
get => _lots.Value;
set => _lots.Value = value;
}
/// <summary>
/// Stop loss in points.
/// </summary>
public int StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit in points.
/// </summary>
public int TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Maximum allowed spread in points.
/// </summary>
public int SpreadLimit
{
get => _spreadLimit.Value;
set => _spreadLimit.Value = value;
}
/// <summary>
/// Minimum number of bars between entries.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="EaTemplateStrategy"/>.
/// </summary>
public EaTemplateStrategy()
{
_reverseTrade = Param(nameof(ReverseTrade), false)
.SetDisplay("Reverse Trade", "Invert entry and exit signals", "Trading");
_useMoneyManagement = Param(nameof(UseMoneyManagement), false)
.SetDisplay("Use Money Management", "Use risk based volume calculation", "Risk Management");
_riskPercent = Param(nameof(RiskPercent), 30m)
.SetRange(1m, 100m)
.SetDisplay("Risk Percent", "Percent of equity to risk", "Risk Management");
_lots = Param(nameof(Lots), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Fixed Lot Size", "Fixed order size", "Risk Management");
_stopLoss = Param(nameof(StopLoss), 50)
.SetDisplay("Stop Loss", "Stop loss in points", "Risk Management");
_takeProfit = Param(nameof(TakeProfit), 70)
.SetDisplay("Take Profit", "Take profit in points", "Risk Management");
_spreadLimit = Param(nameof(SpreadLimit), 10)
.SetDisplay("Spread Limit", "Maximum spread in points", "Trading");
_cooldownBars = Param(nameof(CooldownBars), 8)
.SetDisplay("Cooldown Bars", "Minimum number of bars between entries", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_prevClose = 0m;
_prevSma = 0m;
_barsSinceTrade = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(null, null);
var sma = new SimpleMovingAverage { Length = 50 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal sma)
{
if (candle.State != CandleStates.Finished)
return;
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
_barsSinceTrade++;
if (sma == 0m)
return;
if (Position == 0)
{
var crossAbove = _prevClose != 0m && _prevSma != 0m && _prevClose <= _prevSma && candle.ClosePrice > sma;
var crossBelow = _prevClose != 0m && _prevSma != 0m && _prevClose >= _prevSma && candle.ClosePrice < sma;
var buySignal = _barsSinceTrade >= CooldownBars && ((isBullish && crossAbove && !ReverseTrade) || (isBearish && crossBelow && ReverseTrade));
var sellSignal = _barsSinceTrade >= CooldownBars && ((isBearish && crossBelow && !ReverseTrade) || (isBullish && crossAbove && ReverseTrade));
if (buySignal)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_barsSinceTrade = 0;
}
else if (sellSignal)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_barsSinceTrade = 0;
}
_prevClose = candle.ClosePrice;
_prevSma = sma;
return;
}
var exitLong = (isBearish && !ReverseTrade) || (isBullish && ReverseTrade);
var exitShort = (isBullish && !ReverseTrade) || (isBearish && ReverseTrade);
if (Position > 0 && exitLong)
SellMarket();
if (Position < 0 && exitShort)
BuyMarket();
if (Position > 0)
CheckStopsForLong(candle.ClosePrice);
else if (Position < 0)
CheckStopsForShort(candle.ClosePrice);
_prevClose = candle.ClosePrice;
_prevSma = sma;
}
private decimal GetOrderVolume(decimal price)
{
if (UseMoneyManagement)
{
var portfolioValue = Portfolio.CurrentValue ?? 0m;
var size = portfolioValue * (RiskPercent / 100m) / price;
return size > 0 ? size : Lots;
}
return Lots;
}
private void CheckStopsForLong(decimal price)
{
var stop = StopLoss * (Security.PriceStep ?? 1m);
if (stop > 0 && price <= _entryPrice - stop)
{
SellMarket();
return;
}
var profit = TakeProfit * (Security.PriceStep ?? 1m);
if (profit > 0 && price >= _entryPrice + profit)
SellMarket();
}
private void CheckStopsForShort(decimal price)
{
var stop = StopLoss * (Security.PriceStep ?? 1m);
if (stop > 0 && price >= _entryPrice + stop)
{
BuyMarket();
return;
}
var profit = TakeProfit * (Security.PriceStep ?? 1m);
if (profit > 0 && price <= _entryPrice - profit)
BuyMarket();
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ea_template_strategy(Strategy):
def __init__(self):
super(ea_template_strategy, self).__init__()
self._reverse_trade = self.Param("ReverseTrade", False) \
.SetDisplay("Reverse Trade", "Invert entry and exit signals", "Trading")
self._use_money_management = self.Param("UseMoneyManagement", False) \
.SetDisplay("Use Money Management", "Use risk based volume calculation", "Risk Management")
self._risk_percent = self.Param("RiskPercent", 30.0) \
.SetDisplay("Risk Percent", "Percent of equity to risk", "Risk Management")
self._lots = self.Param("Lots", 0.1) \
.SetGreaterThanZero() \
.SetDisplay("Fixed Lot Size", "Fixed order size", "Risk Management")
self._stop_loss_param = self.Param("StopLoss", 50) \
.SetDisplay("Stop Loss", "Stop loss in points", "Risk Management")
self._take_profit_param = self.Param("TakeProfit", 70) \
.SetDisplay("Take Profit", "Take profit in points", "Risk Management")
self._spread_limit = self.Param("SpreadLimit", 10) \
.SetDisplay("Spread Limit", "Maximum spread in points", "Trading")
self._cooldown_bars = self.Param("CooldownBars", 8) \
.SetDisplay("Cooldown Bars", "Minimum number of bars between entries", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
self._prev_close = 0.0
self._prev_sma = 0.0
self._bars_since_trade = 0
@property
def reverse_trade(self):
return self._reverse_trade.Value
@property
def use_money_management(self):
return self._use_money_management.Value
@property
def risk_percent(self):
return self._risk_percent.Value
@property
def lots(self):
return self._lots.Value
@property
def stop_loss(self):
return self._stop_loss_param.Value
@property
def take_profit(self):
return self._take_profit_param.Value
@property
def spread_limit(self):
return self._spread_limit.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ea_template_strategy, self).OnReseted()
self._entry_price = 0.0
self._prev_close = 0.0
self._prev_sma = 0.0
self._bars_since_trade = self.cooldown_bars
def OnStarted2(self, time):
super(ea_template_strategy, self).OnStarted2(time)
self.StartProtection(None, None)
sma = SimpleMovingAverage()
sma.Length = 50
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, sma):
if candle.State != CandleStates.Finished:
return
sma_val = float(sma)
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
is_bullish = close > open_price
is_bearish = close < open_price
self._bars_since_trade += 1
if sma_val == 0.0:
return
rev = self.reverse_trade
if self.Position == 0:
cross_above = (self._prev_close != 0.0 and self._prev_sma != 0.0 and
self._prev_close <= self._prev_sma and close > sma_val)
cross_below = (self._prev_close != 0.0 and self._prev_sma != 0.0 and
self._prev_close >= self._prev_sma and close < sma_val)
buy_signal = (self._bars_since_trade >= self.cooldown_bars and
((is_bullish and cross_above and not rev) or (is_bearish and cross_below and rev)))
sell_signal = (self._bars_since_trade >= self.cooldown_bars and
((is_bearish and cross_below and not rev) or (is_bullish and cross_above and rev)))
if buy_signal:
self.BuyMarket()
self._entry_price = close
self._bars_since_trade = 0
elif sell_signal:
self.SellMarket()
self._entry_price = close
self._bars_since_trade = 0
self._prev_close = close
self._prev_sma = sma_val
return
exit_long = (is_bearish and not rev) or (is_bullish and rev)
exit_short = (is_bullish and not rev) or (is_bearish and rev)
if self.Position > 0 and exit_long:
self.SellMarket()
if self.Position < 0 and exit_short:
self.BuyMarket()
step = self.Security.PriceStep if self.Security.PriceStep is not None else 1.0
step = float(step)
if self.Position > 0:
stop = self.stop_loss * step
if stop > 0 and close <= self._entry_price - stop:
self.SellMarket()
else:
profit = self.take_profit * step
if profit > 0 and close >= self._entry_price + profit:
self.SellMarket()
elif self.Position < 0:
stop = self.stop_loss * step
if stop > 0 and close >= self._entry_price + stop:
self.BuyMarket()
else:
profit = self.take_profit * step
if profit > 0 and close <= self._entry_price - profit:
self.BuyMarket()
self._prev_close = close
self._prev_sma = sma_val
def CreateClone(self):
return ea_template_strategy()