Estrategia Simple FX
Descripción general
Esta estrategia usa dos medias móviles exponenciales para detectar cambios de tendencia. Se abre una posición larga cuando la EMA corta cruza por encima de la EMA larga, mientras que se abre una posición corta cuando la EMA corta cruza por debajo de la EMA larga.
Parámetros
- Long MA Period – período de la EMA larga.
- Short MA Period – período de la EMA corta.
- Stop Loss (points) – stop de protección en pasos de precio.
- Take Profit (points) – objetivo de ganancia en pasos de precio.
- Candle Type – marco temporal para las velas.
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 trend following strategy based on two exponential moving averages.
/// Opens a long position when the short EMA crosses above the long EMA and a short position when it crosses below.
/// Optional stop loss and take profit are specified in price steps.
/// </summary>
public class SimpleFxStrategy : Strategy
{
private readonly StrategyParam<int> _longMaPeriod;
private readonly StrategyParam<int> _shortMaPeriod;
private readonly StrategyParam<int> _stopLoss;
private readonly StrategyParam<int> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private int _lastTrend; // 1 for bull, -1 for bear, 0 for none
/// <summary>
/// Period of the long EMA.
/// </summary>
public int LongMaPeriod
{
get => _longMaPeriod.Value;
set => _longMaPeriod.Value = value;
}
/// <summary>
/// Period of the short EMA.
/// </summary>
public int ShortMaPeriod
{
get => _shortMaPeriod.Value;
set => _shortMaPeriod.Value = value;
}
/// <summary>
/// Stop loss in price steps.
/// </summary>
public int StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit in price steps.
/// </summary>
public int TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Type of candles to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes parameters.
/// </summary>
public SimpleFxStrategy()
{
_longMaPeriod = Param(nameof(LongMaPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("Long MA Period", "Period of the long EMA", "Parameters")
.SetOptimize(100, 300, 50);
_shortMaPeriod = Param(nameof(ShortMaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Short MA Period", "Period of the short EMA", "Parameters")
.SetOptimize(10, 100, 10);
_stopLoss = Param(nameof(StopLoss), 30)
.SetDisplay("Stop Loss", "Stop loss in price steps", "Risk");
_takeProfit = Param(nameof(TakeProfit), 50)
.SetDisplay("Take Profit", "Take profit in price steps", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_lastTrend = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var longMa = new ExponentialMovingAverage { Length = LongMaPeriod };
var shortMa = new ExponentialMovingAverage { Length = ShortMaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(longMa, shortMa, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, longMa);
DrawIndicator(area, shortMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal longValue, decimal shortValue)
{
// Only process finished candles
if (candle.State != CandleStates.Finished)
return;
var trend = 0;
if (shortValue > longValue)
trend = 1;
else if (shortValue < longValue)
trend = -1;
if (trend == 0)
return;
if (trend != _lastTrend)
{
if (trend == 1)
{
// Bullish trend - open long
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else
{
// Bearish trend - open short
SellMarket();
_entryPrice = candle.ClosePrice;
}
_lastTrend = trend;
return;
}
if (Position == 0 || _entryPrice == 0m)
return;
var step = Security?.PriceStep ?? 1m;
var stopDelta = StopLoss * step;
var takeDelta = TakeProfit * step;
if (Position > 0)
{
// Manage long position
if (StopLoss > 0 && candle.ClosePrice <= _entryPrice - stopDelta)
{
SellMarket();
_lastTrend = 0;
_entryPrice = 0m;
return;
}
if (TakeProfit > 0 && candle.ClosePrice >= _entryPrice + takeDelta)
{
SellMarket();
_lastTrend = 0;
_entryPrice = 0m;
}
}
else if (Position < 0)
{
// Manage short position
if (StopLoss > 0 && candle.ClosePrice >= _entryPrice + stopDelta)
{
BuyMarket();
_lastTrend = 0;
_entryPrice = 0m;
return;
}
if (TakeProfit > 0 && candle.ClosePrice <= _entryPrice - takeDelta)
{
BuyMarket();
_lastTrend = 0;
_entryPrice = 0m;
}
}
}
}
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 simple_fx_strategy(Strategy):
def __init__(self):
super(simple_fx_strategy, self).__init__()
self._long_ma = self.Param("LongMaPeriod", 200).SetGreaterThanZero().SetDisplay("Long MA Period", "Period of long EMA", "Parameters")
self._short_ma = self.Param("ShortMaPeriod", 50).SetGreaterThanZero().SetDisplay("Short MA Period", "Period of short EMA", "Parameters")
self._sl = self.Param("StopLoss", 30).SetDisplay("Stop Loss", "SL in price steps", "Risk")
self._tp = self.Param("TakeProfit", 50).SetDisplay("Take Profit", "TP in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "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(simple_fx_strategy, self).OnReseted()
self._entry_price = 0
self._last_trend = 0
def OnStarted2(self, time):
super(simple_fx_strategy, self).OnStarted2(time)
self._entry_price = 0
self._last_trend = 0
self._step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
self._step = float(self.Security.PriceStep)
long_ema = ExponentialMovingAverage()
long_ema.Length = self._long_ma.Value
short_ema = ExponentialMovingAverage()
short_ema.Length = self._short_ma.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(long_ema, short_ema, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, long_ema)
self.DrawIndicator(area, short_ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, long_val, short_val):
if candle.State != CandleStates.Finished:
return
trend = 0
if short_val > long_val:
trend = 1
elif short_val < long_val:
trend = -1
if trend == 0:
return
close = float(candle.ClosePrice)
if trend != self._last_trend:
if trend == 1:
self.BuyMarket()
self._entry_price = close
else:
self.SellMarket()
self._entry_price = close
self._last_trend = trend
return
if self.Position == 0 or self._entry_price == 0:
return
step = self._step
sl_delta = self._sl.Value * step
tp_delta = self._tp.Value * step
if self.Position > 0:
if self._sl.Value > 0 and close <= self._entry_price - sl_delta:
self.SellMarket()
self._last_trend = 0
self._entry_price = 0
return
if self._tp.Value > 0 and close >= self._entry_price + tp_delta:
self.SellMarket()
self._last_trend = 0
self._entry_price = 0
elif self.Position < 0:
if self._sl.Value > 0 and close >= self._entry_price + sl_delta:
self.BuyMarket()
self._last_trend = 0
self._entry_price = 0
return
if self._tp.Value > 0 and close <= self._entry_price - tp_delta:
self.BuyMarket()
self._last_trend = 0
self._entry_price = 0
def CreateClone(self):
return simple_fx_strategy()