Estrategia Rock Trader Neuro
Estrategia que opera utilizando Bandas de Bollinger y una neurona simple. Los últimos siete anchos de las Bandas de Bollinger se normalizan al rango [-1,1] y se combinan con pesos fijos. La suma ponderada pasa por una activación de tangente hiperbólica. Una salida negativa abre una posición larga, mientras que una salida positiva abre una posición corta. Las posiciones se cierran por stop loss o take profit.
Detalles
- Criterios de entrada:
- Largo: salida de la neurona < 0
- Corto: salida de la neurona > 0
- Largo/Corto: Ambos
- Criterios de salida:
- Stop loss o take profit alcanzado
- Stops: Distancia absoluta en precio
- Valores predeterminados:
StopLoss= 30TakeProfit= 100Lot= 1CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Neural
- Dirección: Ambos
- Indicadores: Bollinger Bands
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Corto plazo
- Estacionalidad: No
- Redes neuronales: Sí
- Divergencia: No
- Nivel de riesgo: Medio
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 using Bollinger Bands and a simple neuron to generate signals.
/// </summary>
public class RockTraderNeuroStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _lot;
private readonly StrategyParam<DataType> _candleType;
private decimal _band1;
private decimal _band2;
private decimal _band3;
private decimal _band4;
private decimal _band5;
private decimal _band6;
private decimal _band7;
private decimal _entryPrice;
private decimal _stopPrice;
private decimal _takePrice;
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
public decimal Lot
{
get => _lot.Value;
set => _lot.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public RockTraderNeuroStrategy()
{
_stopLoss = Param(nameof(StopLoss), 30m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");
_takeProfit = Param(nameof(TakeProfit), 100m)
.SetDisplay("Take Profit", "Take profit in price units", "Risk");
_lot = Param(nameof(Lot), 1m)
.SetDisplay("Lot", "Lots to trade", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_band1 = _band2 = _band3 = _band4 = _band5 = _band6 = _band7 = 0m;
_entryPrice = 0m;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = Lot;
_band1 = _band2 = _band3 = _band4 = _band5 = _band6 = _band7 = 0m;
_entryPrice = 0m;
_stopPrice = 0m;
_takePrice = 0m;
var bb = new BollingerBands
{
Length = 20,
Width = 2m
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandleEx)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandleEx(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var bb = (BollingerBandsValue)value;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
// Calculate current Bollinger Band width
var bandWidth = middle == 0m ? 0m : (upper - lower) / middle;
// Shift previous values to keep last seven widths
_band7 = _band6;
_band6 = _band5;
_band5 = _band4;
_band4 = _band3;
_band3 = _band2;
_band2 = _band1;
_band1 = bandWidth;
// Wait until all values are filled
if (_band7 == 0m)
return;
var min = Math.Min(Math.Min(Math.Min(_band1, _band2), Math.Min(_band3, _band4)), Math.Min(_band5, Math.Min(_band6, _band7)));
var max = Math.Max(Math.Max(Math.Max(_band1, _band2), Math.Max(_band3, _band4)), Math.Max(_band5, Math.Max(_band6, _band7)));
if (max == min)
return;
const decimal d1 = -1m;
const decimal d2 = 1m;
decimal Normalize(decimal x) => (x - min) * (d2 - d1) / (max - min) + d1;
var n1 = Normalize(_band1);
var n2 = Normalize(_band2);
var n3 = Normalize(_band3);
var n4 = Normalize(_band4);
var n5 = Normalize(_band5);
var n6 = Normalize(_band6);
var n7 = Normalize(_band7);
// Weighted sum of inputs
var net = n1 * 0.8m + n2 * -0.9m + n3 * 0.7m + n4 * 0.9m + n5 * -1m + n6 * 0.5m + n7 * 0m;
// Activation using hyperbolic tangent
var output = Tanh(net * 2m);
if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
SellMarket();
}
else if (Position < 0)
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
BuyMarket();
}
else
{
if (output < -0.5m)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_stopPrice = _entryPrice - StopLoss;
_takePrice = _entryPrice + TakeProfit;
}
else if (output > 0.5m)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_stopPrice = _entryPrice + StopLoss;
_takePrice = _entryPrice - TakeProfit;
}
}
}
private static decimal Tanh(decimal x)
{
var d = Math.Clamp((double)x, -20d, 20d);
var ePos = Math.Exp(d);
var eNeg = Math.Exp(-d);
return (decimal)((ePos - eNeg) / (ePos + eNeg));
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class rock_trader_neuro_strategy(Strategy):
def __init__(self):
super(rock_trader_neuro_strategy, self).__init__()
self._sl = self.Param("StopLoss", 30.0).SetDisplay("Stop Loss", "SL in price units", "Risk")
self._tp = self.Param("TakeProfit", 100.0).SetDisplay("Take Profit", "TP in price units", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle type", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(rock_trader_neuro_strategy, self).OnReseted()
self._bands = [0.0] * 7
self._entry_price = 0
self._stop_price = 0
self._take_price = 0
def OnStarted2(self, time):
super(rock_trader_neuro_strategy, self).OnStarted2(time)
self._bands = [0.0] * 7
self._entry_price = 0
self._stop_price = 0
self._take_price = 0
bb = BollingerBands()
bb.Length = 20
bb.Width = 2
sub = self.SubscribeCandles(self.CandleType)
sub.BindEx(bb, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle, bb_val):
if candle.State != CandleStates.Finished:
return
upper = bb_val.UpBand
lower = bb_val.LowBand
middle = bb_val.MovingAverage
if upper is None or lower is None or middle is None:
return
if middle == 0:
return
band_width = float((upper - lower) / middle)
# Shift previous values
for i in range(6, 0, -1):
self._bands[i] = self._bands[i - 1]
self._bands[0] = band_width
if self._bands[6] == 0:
return
mn = min(self._bands)
mx = max(self._bands)
if mx == mn:
return
def normalize(x):
return (x - mn) * 2.0 / (mx - mn) - 1.0
n = [normalize(b) for b in self._bands]
# Weighted sum
weights = [0.8, -0.9, 0.7, 0.9, -1.0, 0.5, 0.0]
net = sum(n[i] * weights[i] for i in range(7))
# Tanh activation
d = max(-20.0, min(20.0, net * 2.0))
e_pos = math.exp(d)
e_neg = math.exp(-d)
output = (e_pos - e_neg) / (e_pos + e_neg)
close = candle.ClosePrice
if self.Position > 0:
if candle.LowPrice <= self._stop_price or candle.HighPrice >= self._take_price:
self.SellMarket()
elif self.Position < 0:
if candle.HighPrice >= self._stop_price or candle.LowPrice <= self._take_price:
self.BuyMarket()
else:
if output < -0.5:
self.BuyMarket()
self._entry_price = close
self._stop_price = self._entry_price - self._sl.Value
self._take_price = self._entry_price + self._tp.Value
elif output > 0.5:
self.SellMarket()
self._entry_price = close
self._stop_price = self._entry_price + self._sl.Value
self._take_price = self._entry_price - self._tp.Value
def CreateClone(self):
return rock_trader_neuro_strategy()