Esta estrategia porta el clásico asesor experto CCFp de MetaTrader a la API de alto nivel de StockSharp. Calcula una puntuación de fortaleza relativa para las ocho divisas principales (USD, EUR, GBP, CHF, JPY, AUD, CAD, NZD) usando ratios entre medias móviles simples rápidas y lentas en los siete pares principales basados en USD (EURUSD, GBPUSD, AUDUSD, NZDUSD, USDCAD, USDCHF, USDJPY). Cuando la diferencia entre dos fortalezas de divisas supera un umbral configurable, la estrategia abre posiciones de mercado que expresan la divisa más fuerte contra la más débil.
La implementación sigue la arquitectura de alto nivel recomendada: cada instrumento tiene su propia suscripción de velas, los indicadores se vinculan a través de Bind y la gestión de órdenes usa RegisterOrder con órdenes de mercado. Los comentarios en las órdenes ejecutadas reutilizan el formato (TOPDOWN) original para mantener el mismo estilo de contabilidad que la versión MQL.
Instrumentos requeridos
Adjuntar los siguientes valores a los parámetros de la estrategia:
EURUSD
GBPUSD
AUDUSD
NZDUSD
USDCAD
USDCHF
USDJPY
Los siete pares deben compartir el mismo marco temporal que se establece a través del parámetro Candle Type.
Parámetros
Parámetro
Descripción
Fast MA
Período de media móvil rápida usado en el cálculo de fortaleza.
Slow MA
Período de media móvil lenta usado en el cálculo de fortaleza.
Strength Step
Diferencia mínima entre dos divisas que debe superarse para desencadenar una nueva señal.
Close Opposite
Si está habilitado, la estrategia cierra las posiciones opuestas antes de enviar una nueva orden.
Candle Type
Serie de velas procesada por los indicadores.
Volume base
Tomado de la propiedad estándar Strategy.Volume y usado para cada orden de mercado enviada.
Lógica de trading
Cada uno de los siete pares principales USD está suscrito con su propio par de medias móviles simples (rápida y lenta).
Cada vez que llega una vela terminada, la estrategia convierte el ratio de los promedios lento y rápido en los mismos valores de fortaleza sintéticos producidos por el indicador CCFp original.
Después de que se actualicen los siete pares, se recalculan las ocho puntuaciones de fortaleza de divisas.
Cuando la diferencia entre una divisa "top" y una "down" cruza hacia arriba el nivel Strength Step, mientras la divisa top está subiendo y la divisa down está bajando, se detecta una oportunidad.
La estrategia abre órdenes de mercado que expresan exposición larga a la divisa fuerte y exposición corta a la divisa débil:
Si USD es la divisa fuerte, solo se coloca una orden en el par contraparte (por ejemplo, short EURUSD).
Si USD es la divisa débil, la estrategia compra el par donde la divisa fuerte es la base (por ejemplo, long EURUSD).
Cuando ambas divisas son no-USD, la estrategia envía dos órdenes: long la divisa top contra USD y short la divisa down contra USD.
Si Close Opposite está habilitado y una posición opuesta aún está abierta en un par objetivo, la estrategia envía una orden de mercado de cierre antes de entrar en un nuevo trade.
Gestión de riesgo
La estrategia no adjunta órdenes explícitas de stop-loss o take-profit; el control de riesgo es manejado por el indicador Close Opposite junto con herramientas de gestión de portafolio manual.
El tamaño de entrada es controlado por la propiedad Volume. Configurarlo de acuerdo al tamaño de la cuenta y la exposición deseada por segmento.
Diferencias vs la implementación MQL original
El cálculo de fortaleza de divisas usa indicadores SimpleMovingAverage de StockSharp en un único marco temporal. El apilamiento de coeficientes de múltiples marcos temporales del indicador MQL puede emularse ajustando los períodos Fast MA y Slow MA.
Los stops protectores no se trailingan automáticamente; en cambio, la estrategia se centra en reproducir la lógica de entrada/salida y deja el control avanzado de riesgo a la capa de portafolio de StockSharp.
El enrutamiento de órdenes usa el ayudante de alto nivel RegisterOrder y las referencias de seguridad de StockSharp en lugar de objetos de trade de MetaTrader.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// CCFp Currency Strength strategy (simplified). Uses fast/slow EMA crossover
/// to detect momentum shifts, inspired by currency strength comparison.
/// </summary>
public class CcfpCurrencyStrengthStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public CcfpCurrencyStrengthStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_fastLength = Param(nameof(FastLength), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "Fast EMA period", "Indicators");
_slowLength = Param(nameof(SlowLength), 20)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "Slow EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaFast = new ExponentialMovingAverage { Length = FastLength };
var emaSlow = new ExponentialMovingAverage { Length = SlowLength };
decimal prevFast = 0, prevSlow = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastVal;
prevSlow = slowVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastVal;
prevSlow = slowVal;
return;
}
// Fast EMA crosses above slow - bullish
if (prevFast <= prevSlow && fastVal > slowVal && Position <= 0)
BuyMarket();
// Fast EMA crosses below slow - bearish
else if (prevFast >= prevSlow && fastVal < slowVal && Position >= 0)
SellMarket();
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ccfp_currency_strength_strategy(Strategy):
def __init__(self):
super(ccfp_currency_strength_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._fast_length = self.Param("FastLength", 5) \
.SetDisplay("Fast Length", "Fast EMA period", "Indicators")
self._slow_length = self.Param("SlowLength", 20) \
.SetDisplay("Slow Length", "Slow EMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastLength(self):
return self._fast_length.Value
@property
def SlowLength(self):
return self._slow_length.Value
def OnReseted(self):
super(ccfp_currency_strength_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ccfp_currency_strength_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastLength
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return ccfp_currency_strength_strategy()