Estrategia Anomalous Holonomy Field Theory
Esta estrategia combina EMA, RSI, MACD, ATR, tasa de cambio y distancia al VWAP en una señal compuesta. Las posiciones largas se abren cuando la señal supera un umbral definido por el usuario, mientras que las posiciones cortas se abren cuando cae por debajo del umbral negativo. Un stop basado en ATR protege las operaciones abiertas.
Detalles
- Criterios de entrada:
- Largo: señal ≥ umbral.
- Corto: señal ≤ −umbral.
- Largo/Corto: Ambos.
- Criterios de salida: Stop ATR.
- Stops: Sí, basado en ATR.
- Valores predeterminados:
SignalThreshold= 2CandleType= 5 minutos
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Múltiples
- Stops: Sí
- Complejidad: Avanzado
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Alto
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>
/// Anomalous Holonomy Field Theory strategy.
/// Combines EMA trend with RSI extremes and VWAP distance for composite signal.
/// </summary>
public class AnomalousHolonomyFieldTheoryStrategy : Strategy
{
private readonly StrategyParam<decimal> _signalThreshold;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// Absolute signal level required for trades.
/// </summary>
public decimal SignalThreshold
{
get => _signalThreshold.Value;
set => _signalThreshold.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Type of candles to use.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="AnomalousHolonomyFieldTheoryStrategy"/>.
/// </summary>
public AnomalousHolonomyFieldTheoryStrategy()
{
_signalThreshold = Param(nameof(SignalThreshold), 0.1m)
.SetDisplay("Signal Threshold", "Absolute signal level required for trades", "Parameters")
.SetRange(0.1m, 10m);
_cooldownBars = Param(nameof(CooldownBars), 50)
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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 OnReseted()
{
base.OnReseted();
_barIndex = 0;
_lastTradeBar = -200;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema20 = new ExponentialMovingAverage { Length = 20 };
var ema50 = new ExponentialMovingAverage { Length = 50 };
var rsi = new RelativeStrengthIndex { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema20, ema50, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema20);
DrawIndicator(area, ema50);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal ema20, decimal ema50, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
var close = candle.ClosePrice;
var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;
var signal = 0m;
// EMA trend component
if (close > ema20)
signal += close > ema50 ? 1.5m : 1m;
else if (close < ema20)
signal -= close < ema50 ? 1.5m : 1m;
// VWAP distance component
var vwap = candle.TotalVolume != 0 ? candle.TotalPrice / candle.TotalVolume : close;
var vwapDist = close != 0 ? (close - vwap) / close * 100m : 0m;
vwapDist = Math.Max(-2m, Math.Min(2m, vwapDist));
signal += vwapDist;
// RSI extremes component
if (rsiValue < 30m && signal > 0m)
signal += 1.5m;
else if (rsiValue < 40m && signal > 0m)
signal += 0.5m;
else if (rsiValue > 70m && signal < 0m)
signal -= 1.5m;
else if (rsiValue > 60m && signal < 0m)
signal -= 0.5m;
if (signal >= SignalThreshold && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (signal <= -SignalThreshold && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class anomalous_holonomy_field_theory_strategy(Strategy):
def __init__(self):
super(anomalous_holonomy_field_theory_strategy, self).__init__()
self._signal_threshold = self.Param("SignalThreshold", 0.1) \
.SetDisplay("Signal Threshold", "Absolute signal level required for trades", "Parameters")
self._cooldown_bars = self.Param("CooldownBars", 50) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bar_index = 0
self._last_trade_bar = -200
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
@cooldown_bars.setter
def cooldown_bars(self, value):
self._cooldown_bars.Value = value
def OnReseted(self):
super(anomalous_holonomy_field_theory_strategy, self).OnReseted()
self._bar_index = 0
self._last_trade_bar = -200
def OnStarted2(self, time):
super(anomalous_holonomy_field_theory_strategy, self).OnStarted2(time)
ema20 = ExponentialMovingAverage()
ema20.Length = 20
ema50 = ExponentialMovingAverage()
ema50.Length = 50
rsi = RelativeStrengthIndex()
rsi.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema20, ema50, rsi, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema20)
self.DrawIndicator(area, ema50)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema20_val, ema50_val, rsi_val):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
close = float(candle.ClosePrice)
e20 = float(ema20_val)
e50 = float(ema50_val)
rsi_v = float(rsi_val)
cooldown_ok = self._bar_index - self._last_trade_bar > self.cooldown_bars
signal = 0.0
if close > e20:
signal += 1.5 if close > e50 else 1.0
elif close < e20:
signal -= 1.5 if close < e50 else 1.0
vol = float(candle.TotalVolume) if candle.TotalVolume != 0 else 0.0
tp = float(candle.TotalPrice) if hasattr(candle, 'TotalPrice') else 0.0
vwap = tp / vol if vol != 0 else close
vwap_dist = (close - vwap) / close * 100.0 if close != 0 else 0.0
vwap_dist = max(-2.0, min(2.0, vwap_dist))
signal += vwap_dist
if rsi_v < 30.0 and signal > 0:
signal += 1.5
elif rsi_v < 40.0 and signal > 0:
signal += 0.5
elif rsi_v > 70.0 and signal < 0:
signal -= 1.5
elif rsi_v > 60.0 and signal < 0:
signal -= 0.5
threshold = float(self._signal_threshold.Value)
if signal >= threshold and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif signal <= -threshold and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
def CreateClone(self):
return anomalous_holonomy_field_theory_strategy()