Estratégia Exp TrendValue
Uma estratégia baseada no indicador TrendValue. Ela constrói bandas dinâmicas de suporte e resistência usando médias móveis ponderadas dos preços máximos e mínimos deslocadas pelo ATR. Uma nova tendência de alta ou baixa é detectada quando o preço cruza a banda oposta.
Entrada e Saída
- Entrada comprado: Quando uma nova tendência de alta começa.
- Entrada vendido: Quando uma nova tendência de baixa começa.
- Saída comprado: Em um sinal de baixa ou linha de tendência.
- Saída vendido: Em um sinal de alta ou linha de tendência.
Parâmetros
BuyPosOpen/SellPosOpen– ativar entradas compradas/vendidas.BuyPosClose/SellPosClose– permitir o fechamento de posições compradas/vendidas.StopLossPips– stop loss em pontos de preço.TakeProfitPips– take profit em pontos de preço.MaPeriod– período da média móvel ponderada.ShiftPercent– deslocamento percentual aplicado às médias.AtrPeriod– período ATR.AtrSensitivity– multiplicador aplicado ao ATR.CandleType– período dos candles.
Notas
A estratégia assina dados de candles e atualiza os indicadores em cada candle completado. Ordens de mercado são colocadas quando as condições são atendidas e os níveis de stop e take profit são rastreados internamente.
using System;
using System.Collections.Generic;
using Ecng.Common;
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 the TrendValue indicator combining weighted moving averages and ATR.
/// </summary>
public class ExpTrendValueStrategy : Strategy
{
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _takeProfitPips;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _shiftPercent;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrSensitivity;
private readonly StrategyParam<DataType> _candleType;
private readonly WeightedMovingAverage _wmaHigh = new();
private readonly WeightedMovingAverage _wmaLow = new();
private readonly SimpleMovingAverage _rangeAverage = new();
private decimal _prevHighBand;
private decimal _prevLowBand;
private int _prevTrend;
private bool _initialized;
/// <summary>
/// Allow opening long positions.
/// </summary>
public bool BuyPosOpen { get => _buyPosOpen.Value; set => _buyPosOpen.Value = value; }
/// <summary>
/// Allow opening short positions.
/// </summary>
public bool SellPosOpen { get => _sellPosOpen.Value; set => _sellPosOpen.Value = value; }
/// <summary>
/// Allow closing long positions.
/// </summary>
public bool BuyPosClose { get => _buyPosClose.Value; set => _buyPosClose.Value = value; }
/// <summary>
/// Allow closing short positions.
/// </summary>
public bool SellPosClose { get => _sellPosClose.Value; set => _sellPosClose.Value = value; }
/// <summary>
/// Stop loss size in points.
/// </summary>
public int StopLossPips { get => _stopLossPips.Value; set => _stopLossPips.Value = value; }
/// <summary>
/// Take profit size in points.
/// </summary>
public int TakeProfitPips { get => _takeProfitPips.Value; set => _takeProfitPips.Value = value; }
/// <summary>
/// Weighted moving average period.
/// </summary>
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
/// <summary>
/// Percentage offset applied to moving averages.
/// </summary>
public decimal ShiftPercent { get => _shiftPercent.Value; set => _shiftPercent.Value = value; }
/// <summary>
/// ATR calculation period.
/// </summary>
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
/// <summary>
/// Multiplier for ATR shift.
/// </summary>
public decimal AtrSensitivity { get => _atrSensitivity.Value; set => _atrSensitivity.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="ExpTrendValueStrategy"/>.
/// </summary>
public ExpTrendValueStrategy()
{
_buyPosOpen = Param(nameof(BuyPosOpen), true).SetDisplay("Enable Long Entry", "Allow opening long positions", "Trading");
_sellPosOpen = Param(nameof(SellPosOpen), true).SetDisplay("Enable Short Entry", "Allow opening short positions", "Trading");
_buyPosClose = Param(nameof(BuyPosClose), true).SetDisplay("Allow Long Exit", "Allow closing long positions", "Trading");
_sellPosClose = Param(nameof(SellPosClose), true).SetDisplay("Allow Short Exit", "Allow closing short positions", "Trading");
_stopLossPips = Param(nameof(StopLossPips), 1000).SetGreaterThanZero().SetDisplay("Stop Loss", "Stop loss in points", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 2000).SetGreaterThanZero().SetDisplay("Take Profit", "Take profit in points", "Risk");
_maPeriod = Param(nameof(MaPeriod), 13).SetGreaterThanZero().SetDisplay("MA Period", "Weighted moving average period", "Indicator");
_shiftPercent = Param(nameof(ShiftPercent), 0.05m).SetDisplay("Shift Percent", "Percentage offset for bands", "Indicator");
_atrPeriod = Param(nameof(AtrPeriod), 15).SetGreaterThanZero().SetDisplay("ATR Period", "Range average period", "Indicator");
_atrSensitivity = Param(nameof(AtrSensitivity), 0.6m).SetGreaterThanZero().SetDisplay("ATR Sensitivity", "Multiplier for range shift", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Timeframe for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wmaHigh.Reset();
_wmaHigh.Length = 1;
_wmaLow.Reset();
_wmaLow.Length = 1;
_rangeAverage.Reset();
_rangeAverage.Length = 1;
_prevHighBand = _prevLowBand = 0m;
_prevTrend = 0;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_wmaHigh.Length = MaPeriod;
_wmaLow.Length = MaPeriod;
_rangeAverage.Length = AtrPeriod;
var closeTrigger = new SimpleMovingAverage { Length = 1 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(closeTrigger, ProcessCandle).Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal closeValue)
{
if (candle.State != CandleStates.Finished)
return;
var highMa = _wmaHigh.Process(new DecimalIndicatorValue(_wmaHigh, candle.HighPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var lowMa = _wmaLow.Process(new DecimalIndicatorValue(_wmaLow, candle.LowPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (!_wmaHigh.IsFormed || !_wmaLow.IsFormed)
return;
var rangeValue = _rangeAverage.Process(new DecimalIndicatorValue(_rangeAverage, candle.HighPrice - candle.LowPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (!_rangeAverage.IsFormed)
return;
var percentOffset = closeValue * ShiftPercent / 100m;
var rangeOffset = rangeValue * AtrSensitivity * 0.25m;
var highBand = highMa - rangeOffset + percentOffset;
var lowBand = lowMa + rangeOffset - percentOffset;
if (!_initialized)
{
_prevHighBand = highBand;
_prevLowBand = lowBand;
_initialized = true;
return;
}
var centerLine = (highBand + lowBand) / 2m;
var trend = candle.ClosePrice >= centerLine ? 1 : -1;
var upSignal = trend > 0 && _prevTrend <= 0;
var downSignal = trend < 0 && _prevTrend >= 0;
var haveUpTrend = trend > 0;
var haveDownTrend = trend < 0;
_prevHighBand = highBand;
_prevLowBand = lowBand;
_prevTrend = trend;
if (upSignal && Position == 0)
BuyMarket();
else if (downSignal && Position == 0)
SellMarket();
}
}
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, Unit, UnitTypes, CandleStates
from StockSharp.Algo.Indicators import WeightedMovingAverage, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class exp_trend_value_strategy(Strategy):
def __init__(self):
super(exp_trend_value_strategy, self).__init__()
self._buy_pos_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Enable Long Entry", "Allow opening long positions", "Trading")
self._sell_pos_open = self.Param("SellPosOpen", True) \
.SetDisplay("Enable Short Entry", "Allow opening short positions", "Trading")
self._buy_pos_close = self.Param("BuyPosClose", True) \
.SetDisplay("Allow Long Exit", "Allow closing long positions", "Trading")
self._sell_pos_close = self.Param("SellPosClose", True) \
.SetDisplay("Allow Short Exit", "Allow closing short positions", "Trading")
self._stop_loss_pips = self.Param("StopLossPips", 1000) \
.SetDisplay("Stop Loss", "Stop loss in points", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 2000) \
.SetDisplay("Take Profit", "Take profit in points", "Risk")
self._ma_period = self.Param("MaPeriod", 13) \
.SetDisplay("MA Period", "Weighted moving average period", "Indicator")
self._shift_percent = self.Param("ShiftPercent", 0.05) \
.SetDisplay("Shift Percent", "Percentage offset for bands", "Indicator")
self._atr_period = self.Param("AtrPeriod", 15) \
.SetDisplay("ATR Period", "Range average period", "Indicator")
self._atr_sensitivity = self.Param("AtrSensitivity", 0.6) \
.SetDisplay("ATR Sensitivity", "Multiplier for range shift", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._wma_high = WeightedMovingAverage()
self._wma_low = WeightedMovingAverage()
self._range_average = SimpleMovingAverage()
self._prev_high_band = 0.0
self._prev_low_band = 0.0
self._prev_trend = 0
self._initialized = False
self._entry_price = 0.0
self._stop_price = 0.0
self._take_profit_price = 0.0
@property
def BuyPosOpen(self):
return self._buy_pos_open.Value
@BuyPosOpen.setter
def BuyPosOpen(self, value):
self._buy_pos_open.Value = value
@property
def SellPosOpen(self):
return self._sell_pos_open.Value
@SellPosOpen.setter
def SellPosOpen(self, value):
self._sell_pos_open.Value = value
@property
def BuyPosClose(self):
return self._buy_pos_close.Value
@BuyPosClose.setter
def BuyPosClose(self, value):
self._buy_pos_close.Value = value
@property
def SellPosClose(self):
return self._sell_pos_close.Value
@SellPosClose.setter
def SellPosClose(self, value):
self._sell_pos_close.Value = value
@property
def StopLossPips(self):
return self._stop_loss_pips.Value
@StopLossPips.setter
def StopLossPips(self, value):
self._stop_loss_pips.Value = value
@property
def TakeProfitPips(self):
return self._take_profit_pips.Value
@TakeProfitPips.setter
def TakeProfitPips(self, value):
self._take_profit_pips.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
@property
def ShiftPercent(self):
return self._shift_percent.Value
@ShiftPercent.setter
def ShiftPercent(self, value):
self._shift_percent.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@AtrPeriod.setter
def AtrPeriod(self, value):
self._atr_period.Value = value
@property
def AtrSensitivity(self):
return self._atr_sensitivity.Value
@AtrSensitivity.setter
def AtrSensitivity(self, value):
self._atr_sensitivity.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(exp_trend_value_strategy, self).OnStarted2(time)
self._wma_high.Length = self.MaPeriod
self._wma_low.Length = self.MaPeriod
self._range_average.Length = self.AtrPeriod
close_trigger = SimpleMovingAverage()
close_trigger.Length = 1
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(close_trigger, self.ProcessCandle).Start()
self.StartProtection(
takeProfit=Unit(2, UnitTypes.Percent),
stopLoss=Unit(1, UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, close_value):
if candle.State != CandleStates.Finished:
return
high_ma = float(process_float(self._wma_high, candle.HighPrice, candle.OpenTime, True))
low_ma = float(process_float(self._wma_low, candle.LowPrice, candle.OpenTime, True))
if not self._wma_high.IsFormed or not self._wma_low.IsFormed:
return
range_val = candle.HighPrice - candle.LowPrice
range_avg = float(process_float(self._range_average, range_val, candle.OpenTime, True))
if not self._range_average.IsFormed:
return
cv = float(close_value)
percent_offset = cv * float(self.ShiftPercent) / 100.0
range_offset = range_avg * float(self.AtrSensitivity) * 0.25
high_band = high_ma - range_offset + percent_offset
low_band = low_ma + range_offset - percent_offset
if not self._initialized:
self._prev_high_band = high_band
self._prev_low_band = low_band
self._initialized = True
return
center_line = (high_band + low_band) / 2.0
close_price = float(candle.ClosePrice)
trend = 1 if close_price >= center_line else -1
up_signal = trend > 0 and self._prev_trend <= 0
down_signal = trend < 0 and self._prev_trend >= 0
self._prev_high_band = high_band
self._prev_low_band = low_band
self._prev_trend = trend
if up_signal and self.Position == 0:
self.BuyMarket()
elif down_signal and self.Position == 0:
self.SellMarket()
def OnReseted(self):
super(exp_trend_value_strategy, self).OnReseted()
self._wma_high.Reset()
self._wma_low.Reset()
self._range_average.Reset()
self._prev_high_band = 0.0
self._prev_low_band = 0.0
self._prev_trend = 0
self._initialized = False
self._entry_price = 0.0
self._stop_price = 0.0
self._take_profit_price = 0.0
def CreateClone(self):
return exp_trend_value_strategy()