Esta estrategia busca picos repentinos de impulso y opera en su contra. Calcula el cambio porcentual del precio de cierre en una barra utilizando un indicador Momentum. Cuando el cambio porcentual supera un umbral mínimo, el movimiento se considera un "tsunami". La estrategia vende después de un fuerte pico alcista y compra después de un fuerte pico bajista. Se aplican stop-loss y take-profit de protección en pasos de precio a través de StartProtection.
Detalles
Criterios de entrada:
Vender cuando el porcentaje de momentum > TsunamiStrength.
Comprar cuando el porcentaje de momentum < -TsunamiStrength.
Largo/Corto: Ambas direcciones.
Criterios de salida: Stop-loss o take-profit de protección.
Stops: Sí, a través de StartProtection.
Valores predeterminados:
MomentumPeriod = 1
TsunamiStrength = 0.24
TakeProfitPoints = 500
StopLossPoints = 700
CandleType = TimeSpan.FromMinutes(1)
Filtros:
Categoría: Reversión a la media
Dirección: Ambos
Indicadores: Momentum
Stops: Sí
Complejidad: Básico
Marco temporal: Intradía
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Alto
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;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Contrarian strategy based on strong momentum spikes.
/// Sells when momentum percentage rises above a small threshold.
/// Buys when momentum drops below the negative threshold.
/// Uses protective stop-loss and take-profit in price steps.
/// </summary>
public class HawaiianTsunamiSurferStrategy : Strategy
{
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<decimal> _tsunamiStrength;
private readonly StrategyParam<int> _takeProfitPoints;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Momentum calculation period.
/// </summary>
public int MomentumPeriod
{
get => _momentumPeriod.Value;
set => _momentumPeriod.Value = value;
}
/// <summary>
/// Momentum deviation from 0% to trigger trades (in percent).
/// </summary>
public decimal TsunamiStrength
{
get => _tsunamiStrength.Value;
set => _tsunamiStrength.Value = value;
}
/// <summary>
/// Take-profit in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Stop-loss in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="HawaiianTsunamiSurferStrategy"/>.
/// </summary>
public HawaiianTsunamiSurferStrategy()
{
_momentumPeriod = Param(nameof(MomentumPeriod), 1)
.SetDisplay("Momentum Period", "Period of the momentum indicator", "Indicators")
.SetGreaterThanZero();
_tsunamiStrength = Param(nameof(TsunamiStrength), 0.24m)
.SetDisplay("Threshold", "Momentum percentage deviation from 0%", "Parameters")
.SetGreaterThanZero();
_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
.SetDisplay("Take Profit Points", "Take profit distance in price steps", "Risk Management")
.SetGreaterThanZero();
_stopLossPoints = Param(nameof(StopLossPoints), 700)
.SetDisplay("Stop Loss Points", "Stop loss distance in price steps", "Risk Management")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create momentum indicator
var momentum = new Momentum { Length = MomentumPeriod };
// Subscribe to candles and bind the indicator
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(momentum, ProcessCandle)
.Start();
// Setup chart
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, momentum);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal momentumValue)
{
// Process only finished candles
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Convert momentum difference to percentage change around zero
var closePrice = candle.ClosePrice;
var previousPrice = closePrice - momentumValue;
if (previousPrice == 0m)
return;
var percentChange = (momentumValue / previousPrice) * 100m;
if (percentChange > TsunamiStrength && Position >= 0)
{
SellMarket();
}
else if (percentChange < -TsunamiStrength && Position <= 0)
{
BuyMarket();
}
}
}
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 Momentum
from StockSharp.Algo.Strategies import Strategy
class hawaiian_tsunami_surfer_strategy(Strategy):
def __init__(self):
super(hawaiian_tsunami_surfer_strategy, self).__init__()
self._momentum_period = self.Param("MomentumPeriod", 1) \
.SetDisplay("Momentum Period", "Period of the momentum indicator", "Indicators")
self._tsunami_strength = self.Param("TsunamiStrength", 0.24) \
.SetDisplay("Threshold", "Momentum percentage deviation from 0%", "Parameters")
self._take_profit_points = self.Param("TakeProfitPoints", 500) \
.SetDisplay("Take Profit Points", "Take profit distance in price steps", "Risk Management")
self._stop_loss_points = self.Param("StopLossPoints", 700) \
.SetDisplay("Stop Loss Points", "Stop loss distance in price steps", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def momentum_period(self):
return self._momentum_period.Value
@property
def tsunami_strength(self):
return self._tsunami_strength.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(hawaiian_tsunami_surfer_strategy, self).OnStarted2(time)
momentum = Momentum()
momentum.Length = self.momentum_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(momentum, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, momentum)
self.DrawOwnTrades(area)
def process_candle(self, candle, momentum_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
mom = float(momentum_value)
prev_price = close - mom
if prev_price == 0.0:
return
pct_change = (mom / prev_price) * 100.0
threshold = float(self.tsunami_strength)
if pct_change > threshold and self.Position >= 0:
self.SellMarket()
elif pct_change < -threshold and self.Position <= 0:
self.BuyMarket()
def CreateClone(self):
return hawaiian_tsunami_surfer_strategy()