Estratégia Rock Trader Neuro
Estratégia que opera utilizando Bandas de Bollinger e um neurônio simples. As últimas sete larguras das Bandas de Bollinger são normalizadas para o intervalo [-1,1] e combinadas com pesos fixos. A soma ponderada é passada por uma ativação de tangente hiperbólica. Uma saída negativa abre uma posição comprada, enquanto uma saída positiva abre uma posição vendida. As posições são fechadas por stop loss ou take profit.
Detalhes
- Critérios de entrada:
- Comprado: saída do neurônio < 0
- Vendido: saída do neurônio > 0
- Comprado/Vendido: Ambos
- Critérios de saída:
- Stop loss ou take profit atingido
- Stops: Distância absoluta de preço
- Valores padrão:
StopLoss= 30TakeProfit= 100Lot= 1CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoria: Neural
- Direção: Ambos
- Indicadores: Bollinger Bands
- Stops: Sim
- Complexidade: Intermediário
- Período: Curto prazo
- Sazonalidade: Não
- Redes neurais: Sim
- Divergência: Não
- Nível de risco: Médio
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()