Estratégia Color Trend CF
Esta estratégia é uma conversão do especialista MQL Exp_ColorTrend_CF. Utiliza duas médias móveis exponenciais para detectar mudanças de tendência. A EMA rápida reage rapidamente aos movimentos de preço, enquanto a EMA lenta atua como filtro de tendência. Uma posição comprada é aberta quando a EMA rápida cruza acima da EMA lenta. Uma posição vendida é aberta quando a EMA rápida cruza abaixo da EMA lenta.
Parâmetros
Period– período base para a EMA rápida; a EMA lenta usa o dobro deste valor.StopLoss– distância de stop-loss em unidades de preço.TakeProfit– distância de take-profit em unidades de preço.AllowBuyOpen– permissão para abrir posições compradas.AllowSellOpen– permissão para abrir posições vendidas.AllowBuyClose– permissão para fechar posições compradas em sinal de venda.AllowSellClose– permissão para fechar posições vendidas em sinal de compra.CandleType– período para cálculo de indicadores.
Lógica de trading
- Subscrever velas do período selecionado.
- Calcular as EMA rápida e lenta.
- Quando a EMA rápida cruza acima da EMA lenta:
- Fechar posições vendidas se permitido.
- Abrir posição comprada se permitido.
- Quando a EMA rápida cruza abaixo da EMA lenta:
- Fechar posições compradas se permitido.
- Abrir posição vendida se permitido.
- Para posições abertas, aplicar níveis de stop-loss e take-profit.
Esta implementação utiliza a API de alto nível do StockSharp com vinculação de indicadores.
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>
/// Strategy based on crossing of two exponential moving averages.
/// Shorter EMA represents rising pressure while longer EMA acts as trend
/// filter.
/// </summary>
public class ColorTrendCfStrategy : Strategy {
private readonly StrategyParam<int> _period;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<bool> _allowBuyOpen;
private readonly StrategyParam<bool> _allowSellOpen;
private readonly StrategyParam<bool> _allowBuyClose;
private readonly StrategyParam<bool> _allowSellClose;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private bool _isLong;
/// <summary>
/// Base period for the fast EMA. Slow EMA uses double value.
/// </summary>
public int Period {
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// Stop loss distance in price units.
/// </summary>
public decimal StopLoss {
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit distance in price units.
/// </summary>
public decimal TakeProfit {
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Whether long entries are allowed.
/// </summary>
public bool AllowBuyOpen {
get => _allowBuyOpen.Value;
set => _allowBuyOpen.Value = value;
}
/// <summary>
/// Whether short entries are allowed.
/// </summary>
public bool AllowSellOpen {
get => _allowSellOpen.Value;
set => _allowSellOpen.Value = value;
}
/// <summary>
/// Whether closing long positions on sell signals is allowed.
/// </summary>
public bool AllowBuyClose {
get => _allowBuyClose.Value;
set => _allowBuyClose.Value = value;
}
/// <summary>
/// Whether closing short positions on buy signals is allowed.
/// </summary>
public bool AllowSellClose {
get => _allowSellClose.Value;
set => _allowSellClose.Value = value;
}
/// <summary>
/// Candle type used for indicator calculation.
/// </summary>
public DataType CandleType {
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="ColorTrendCfStrategy"/>.
/// </summary>
public ColorTrendCfStrategy() {
_period = Param(nameof(Period), 30)
.SetGreaterThanZero()
.SetDisplay("CF Period", "Base period for fast EMA",
"Indicator")
.SetOptimize(10, 60, 10);
_stopLoss =
Param(nameof(StopLoss), 1000m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk")
.SetOptimize(100m, 2000m, 100m);
_takeProfit =
Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit in price units", "Risk")
.SetOptimize(100m, 4000m, 100m);
_allowBuyOpen = Param(nameof(AllowBuyOpen), true)
.SetDisplay("Allow Buy", "Permission to open long",
"Permissions");
_allowSellOpen =
Param(nameof(AllowSellOpen), true)
.SetDisplay("Allow Sell", "Permission to open short",
"Permissions");
_allowBuyClose =
Param(nameof(AllowBuyClose), true)
.SetDisplay("Close Long", "Allow closing long positions",
"Permissions");
_allowSellClose =
Param(nameof(AllowSellClose), true)
.SetDisplay("Close Short", "Allow closing short positions",
"Permissions");
_candleType =
Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for indicator",
"General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)>
GetWorkingSecurities() {
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted() {
base.OnReseted();
_entryPrice = 0m;
_isLong = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time) {
base.OnStarted2(time);
var fastEma = new EMA { Length = Period };
var slowEma = new EMA { Length = Period * 2 };
var subscription = SubscribeCandles(CandleType);
var prevFast = 0m;
var prevSlow = 0m;
var initialized = false;
subscription
.Bind(fastEma, slowEma,
(candle, fast, slow) => {
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!initialized) {
prevFast = fast;
prevSlow = slow;
initialized = true;
return;
}
var crossUp = prevFast <= prevSlow && fast > slow;
var crossDown = prevFast >= prevSlow && fast < slow;
prevFast = fast;
prevSlow = slow;
if (crossUp) {
if (AllowSellClose && Position < 0)
BuyMarket(Math.Abs(Position));
if (AllowBuyOpen && Position <= 0) {
_entryPrice = candle.ClosePrice;
_isLong = true;
BuyMarket(Volume + Math.Abs(Position));
}
} else if (crossDown) {
if (AllowBuyClose && Position > 0)
SellMarket(Position);
if (AllowSellOpen && Position >= 0) {
_entryPrice = candle.ClosePrice;
_isLong = false;
SellMarket(Volume + Math.Abs(Position));
}
}
if (_entryPrice != 0m) {
if (_isLong && Position > 0) {
var stop = _entryPrice - StopLoss;
var take = _entryPrice + TakeProfit;
if (candle.LowPrice <= stop ||
candle.HighPrice >= take)
SellMarket(Position);
} else if (!_isLong && Position < 0) {
var stop = _entryPrice + StopLoss;
var take = _entryPrice - TakeProfit;
if (candle.HighPrice >= stop ||
candle.LowPrice <= take)
BuyMarket(Math.Abs(Position));
}
}
})
.Start();
StartProtection(null, null);
}
}
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 color_trend_cf_strategy(Strategy):
def __init__(self):
super(color_trend_cf_strategy, self).__init__()
self._period = self.Param("Period", 30) \
.SetDisplay("CF Period", "Base period for fast EMA", "Indicator")
self._stop_loss = self.Param("StopLoss", 1000.0) \
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take Profit", "Take profit in price units", "Risk")
self._allow_buy_open = self.Param("AllowBuyOpen", True) \
.SetDisplay("Allow Buy", "Permission to open long", "Permissions")
self._allow_sell_open = self.Param("AllowSellOpen", True) \
.SetDisplay("Allow Sell", "Permission to open short", "Permissions")
self._allow_buy_close = self.Param("AllowBuyClose", True) \
.SetDisplay("Close Long", "Allow closing long positions", "Permissions")
self._allow_sell_close = self.Param("AllowSellClose", True) \
.SetDisplay("Close Short", "Allow closing short positions", "Permissions")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe for indicator", "General")
self._entry_price = 0.0
self._is_long = False
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
@property
def Period(self):
return self._period.Value
@Period.setter
def Period(self, value):
self._period.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def AllowBuyOpen(self):
return self._allow_buy_open.Value
@AllowBuyOpen.setter
def AllowBuyOpen(self, value):
self._allow_buy_open.Value = value
@property
def AllowSellOpen(self):
return self._allow_sell_open.Value
@AllowSellOpen.setter
def AllowSellOpen(self, value):
self._allow_sell_open.Value = value
@property
def AllowBuyClose(self):
return self._allow_buy_close.Value
@AllowBuyClose.setter
def AllowBuyClose(self, value):
self._allow_buy_close.Value = value
@property
def AllowSellClose(self):
return self._allow_sell_close.Value
@AllowSellClose.setter
def AllowSellClose(self, value):
self._allow_sell_close.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(color_trend_cf_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.Period
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.Period * 2
self.SubscribeCandles(self.CandleType) \
.Bind(fast_ema, slow_ema, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast = float(fast_value)
slow = float(slow_value)
if not self._initialized:
self._prev_fast = fast
self._prev_slow = slow
self._initialized = True
return
cross_up = self._prev_fast <= self._prev_slow and fast > slow
cross_down = self._prev_fast >= self._prev_slow and fast < slow
self._prev_fast = fast
self._prev_slow = slow
if cross_up:
if self.AllowSellClose and self.Position < 0:
self.BuyMarket(abs(self.Position))
if self.AllowBuyOpen and self.Position <= 0:
self._entry_price = float(candle.ClosePrice)
self._is_long = True
self.BuyMarket()
elif cross_down:
if self.AllowBuyClose and self.Position > 0:
self.SellMarket(self.Position)
if self.AllowSellOpen and self.Position >= 0:
self._entry_price = float(candle.ClosePrice)
self._is_long = False
self.SellMarket()
if self._entry_price != 0.0:
if self._is_long and self.Position > 0:
stop = self._entry_price - float(self.StopLoss)
take = self._entry_price + float(self.TakeProfit)
if float(candle.LowPrice) <= stop or float(candle.HighPrice) >= take:
self.SellMarket(self.Position)
elif not self._is_long and self.Position < 0:
stop = self._entry_price + float(self.StopLoss)
take = self._entry_price - float(self.TakeProfit)
if float(candle.HighPrice) >= stop or float(candle.LowPrice) <= take:
self.BuyMarket(abs(self.Position))
def OnReseted(self):
super(color_trend_cf_strategy, self).OnReseted()
self._entry_price = 0.0
self._is_long = False
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
def CreateClone(self):
return color_trend_cf_strategy()