Estrategia de Operación Contrarian con MA
Un sistema contrarian semanal que evalúa máximos, mínimos anteriores y una media móvil para abrir operaciones al final de cada semana. La posición se mantiene durante una semana independientemente de la dirección.
El método está diseñado para los principales pares de divisas, pero puede aplicarse a cualquier activo líquido con datos semanales.
Detalles
- Criterios de entrada:
- Compra: El cierre de la semana anterior está por encima del máximo más alto del período de análisis, o la media móvil está por encima de la apertura semanal.
- Venta: El cierre de la semana anterior está por debajo del mínimo más bajo del período de análisis, o la media móvil está por debajo de la apertura semanal.
- Largo/Corto: Ambos.
- Criterios de salida: La posición se cierra después de mantenerse durante una semana.
- Stops: Ninguno.
- Marco temporal: Velas semanales.
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>
/// Weekly contrarian strategy using moving average and extreme price levels.
/// </summary>
public class ContrarianTradeMaStrategy : Strategy
{
private readonly StrategyParam<int> _calcPeriod;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private int _barsInPosition;
private decimal _prevHighest;
private decimal _prevLowest;
private decimal _prevSma;
private bool _hasPrev;
public int CalcPeriod { get => _calcPeriod.Value; set => _calcPeriod.Value = value; }
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ContrarianTradeMaStrategy()
{
_calcPeriod = Param(nameof(CalcPeriod), 10)
.SetDisplay("Calc Period", "Lookback period for extremes", "General");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetDisplay("MA Period", "Moving average period", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_barsInPosition = 0;
_prevHighest = 0;
_prevLowest = 0;
_prevSma = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = CalcPeriod };
var lowest = new Lowest { Length = CalcPeriod };
var sma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, sma, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest, decimal sma)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevClose = candle.ClosePrice;
_prevHighest = highest;
_prevLowest = lowest;
_prevSma = sma;
_hasPrev = true;
return;
}
if (Position == 0)
{
if (_prevHighest < _prevClose && Position <= 0)
{
BuyMarket();
_barsInPosition = 0;
}
else if (_prevLowest > _prevClose && Position >= 0)
{
SellMarket();
_barsInPosition = 0;
}
else if (_prevSma > candle.OpenPrice && Position <= 0)
{
BuyMarket();
_barsInPosition = 0;
}
else if (_prevSma < candle.OpenPrice && Position >= 0)
{
SellMarket();
_barsInPosition = 0;
}
}
else
{
_barsInPosition++;
if (_barsInPosition >= CalcPeriod)
{
if (Position > 0)
SellMarket();
else
BuyMarket();
_barsInPosition = 0;
}
}
_prevClose = candle.ClosePrice;
_prevHighest = highest;
_prevLowest = lowest;
_prevSma = sma;
}
}
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 SimpleMovingAverage, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class contrarian_trade_ma_strategy(Strategy):
def __init__(self):
super(contrarian_trade_ma_strategy, self).__init__()
self._calc_period = self.Param("CalcPeriod", 10) \
.SetDisplay("Calc Period", "Lookback period for extremes", "General")
self._ma_period = self.Param("MaPeriod", 20) \
.SetDisplay("MA Period", "Moving average period", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candles", "General")
self._prev_close = 0.0
self._bars_in_position = 0
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._prev_sma = 0.0
self._has_prev = False
@property
def calc_period(self):
return self._calc_period.Value
@property
def ma_period(self):
return self._ma_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(contrarian_trade_ma_strategy, self).OnReseted()
self._prev_close = 0.0
self._bars_in_position = 0
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._prev_sma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(contrarian_trade_ma_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self.calc_period
lowest = Lowest()
lowest.Length = self.calc_period
sma = SimpleMovingAverage()
sma.Length = self.ma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, sma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def on_process(self, candle, highest, lowest, sma):
if candle.State != CandleStates.Finished:
return
if not self._has_prev:
self._prev_close = candle.ClosePrice
self._prev_highest = highest
self._prev_lowest = lowest
self._prev_sma = sma
self._has_prev = True
return
if self.Position == 0:
if self._prev_highest < self._prev_close and self.Position <= 0:
self.BuyMarket()
self._bars_in_position = 0
elif self._prev_lowest > self._prev_close and self.Position >= 0:
self.SellMarket()
self._bars_in_position = 0
elif self._prev_sma > candle.OpenPrice and self.Position <= 0:
self.BuyMarket()
self._bars_in_position = 0
elif self._prev_sma < candle.OpenPrice and self.Position >= 0:
self.SellMarket()
self._bars_in_position = 0
else:
self._bars_in_position += 1
if self._bars_in_position >= self.calc_period:
if self.Position > 0:
self.SellMarket()
else:
self.BuyMarket()
self._bars_in_position = 0
self._prev_close = candle.ClosePrice
self._prev_highest = highest
self._prev_lowest = lowest
self._prev_sma = sma
def CreateClone(self):
return contrarian_trade_ma_strategy()