Стратегия XRP AI 15-m Adaptive v3.1
Стратегия торгует XRP на 15-минутных свечах, используя фильтр тренда старшего таймфрейма. Выбирает между небольшим откатом, средним объёмным всплеском и крупным импульсом, применяя стопы и цели на основе ATR, трейлинг и выход по времени.
Параметры
- Risk Mult – множитель ATR для первоначального стопа.
- Small TP – множитель ATR для цели при небольшом откате.
- Med TP – множитель ATR для цели при среднем всплеске объёма.
- Large TP – множитель ATR для цели при крупном импульсе.
- Volume Mult – множитель SMA-20 объёма для определения всплесков.
- Trail Percent – процент ATR для трейлинг-стопа от максимальной цены.
- Trail Arm – прирост в ATR перед активацией трейлинга.
- Max Bars – максимальное число 15-минутных свечей в позиции.
- Candle Type – тип свечей для основных расчётов.
- Trend Candle Type – тип свечей для фильтра тренда.
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>
/// XRP AI 15-m Adaptive v3.1 strategy.
/// Long-only entries with RSI/EMA filter and StdDev-based management.
/// Uses higher timeframe EMA trend filter.
/// </summary>
public class XrpAi15mAdaptiveV31Strategy : Strategy
{
private readonly StrategyParam<decimal> _stopPct;
private readonly StrategyParam<decimal> _tpSmall;
private readonly StrategyParam<decimal> _tpLarge;
private readonly StrategyParam<decimal> _trailPct;
private readonly StrategyParam<int> _maxBars;
private readonly StrategyParam<DataType> _candleType;
private bool _trendUp;
private int _barIndex;
private int _entryBar;
private decimal _entryPrice;
private decimal _highWater;
private bool _trailLive;
private decimal _stopPrice;
private decimal _takePrice;
public decimal StopPct { get => _stopPct.Value; set => _stopPct.Value = value; }
public decimal TpSmall { get => _tpSmall.Value; set => _tpSmall.Value = value; }
public decimal TpLarge { get => _tpLarge.Value; set => _tpLarge.Value = value; }
public decimal TrailPct { get => _trailPct.Value; set => _trailPct.Value = value; }
public int MaxBars { get => _maxBars.Value; set => _maxBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public XrpAi15mAdaptiveV31Strategy()
{
_stopPct = Param(nameof(StopPct), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Stop %", "Stop loss percent", "Risk");
_tpSmall = Param(nameof(TpSmall), 2m)
.SetGreaterThanZero()
.SetDisplay("Small TP %", "Take profit for small setups", "Risk");
_tpLarge = Param(nameof(TpLarge), 4m)
.SetGreaterThanZero()
.SetDisplay("Large TP %", "Take profit for large setups", "Risk");
_trailPct = Param(nameof(TrailPct), 1m)
.SetGreaterThanZero()
.SetDisplay("Trail %", "Trailing stop percent", "Risk");
_maxBars = Param(nameof(MaxBars), 48)
.SetGreaterThanZero()
.SetDisplay("Max Bars", "Maximum bars to hold", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Main candle type", "Parameters");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_trendUp = false;
_barIndex = 0;
_entryBar = -1;
_entryPrice = 0;
_highWater = 0;
_trailLive = false;
_stopPrice = 0;
_takePrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema13 = new ExponentialMovingAverage { Length = 13 };
var ema34 = new ExponentialMovingAverage { Length = 34 };
var rsi = new RelativeStrengthIndex { Length = 14 };
_trendUp = false;
_barIndex = 0;
_entryBar = -1;
_entryPrice = 0;
_highWater = 0;
_trailLive = false;
_stopPrice = 0;
_takePrice = 0;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema13, ema34, rsi, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema13);
DrawIndicator(area, ema34);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal ema13, decimal ema34, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
// Use EMA cross for trend
_trendUp = ema13 > ema34;
// Exit management
if (Position > 0 && _entryPrice > 0)
{
if (candle.HighPrice > _highWater)
_highWater = candle.HighPrice;
// Stop loss
if (candle.ClosePrice <= _stopPrice)
{
SellMarket();
ResetTrade();
return;
}
// Take profit
if (candle.ClosePrice >= _takePrice)
{
SellMarket();
ResetTrade();
return;
}
// Trailing stop
if (!_trailLive && _highWater >= _entryPrice * (1 + TrailPct / 100m))
_trailLive = true;
if (_trailLive)
{
var trailStop = _highWater * (1 - TrailPct / 200m);
if (candle.ClosePrice <= trailStop)
{
SellMarket();
ResetTrade();
return;
}
}
// Time-based exit
if (_barIndex - _entryBar >= MaxBars)
{
SellMarket();
ResetTrade();
return;
}
}
// Entry conditions - long only
if (Position == 0)
{
// Large setup: extreme oversold + trend up
var largeOk = rsi < 25m && candle.ClosePrice > ema34 && _trendUp;
// Small setup: pullback to EMA in uptrend
var smallOk = candle.ClosePrice <= ema13 * 0.998m &&
rsi < 45m &&
candle.ClosePrice > candle.OpenPrice &&
_trendUp;
if (largeOk)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_entryBar = _barIndex;
_highWater = candle.ClosePrice;
_trailLive = false;
_stopPrice = _entryPrice * (1 - StopPct / 100m);
_takePrice = _entryPrice * (1 + TpLarge / 100m);
}
else if (smallOk)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_entryBar = _barIndex;
_highWater = candle.ClosePrice;
_trailLive = false;
_stopPrice = _entryPrice * (1 - StopPct / 100m);
_takePrice = _entryPrice * (1 + TpSmall / 100m);
}
}
}
private void ResetTrade()
{
_entryBar = -1;
_entryPrice = 0;
_highWater = 0;
_trailLive = false;
_stopPrice = 0;
_takePrice = 0;
}
}
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 xrp_ai15m_adaptive_v31_strategy(Strategy):
def __init__(self):
super(xrp_ai15m_adaptive_v31_strategy, self).__init__()
self._stop_pct = self.Param("StopPct", 1.5) \
.SetDisplay("Stop %", "Stop loss percent", "Risk")
self._tp_small = self.Param("TpSmall", 2) \
.SetDisplay("Small TP %", "Take profit for small setups", "Risk")
self._tp_large = self.Param("TpLarge", 4) \
.SetDisplay("Large TP %", "Take profit for large setups", "Risk")
self._trail_pct = self.Param("TrailPct", 1) \
.SetDisplay("Trail %", "Trailing stop percent", "Risk")
self._max_bars = self.Param("MaxBars", 48) \
.SetDisplay("Max Bars", "Maximum bars to hold", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Main candle type", "Parameters")
self._trend_up = False
self._bar_index = 0
self._entry_bar = 0
self._entry_price = 0.0
self._high_water = 0.0
self._trail_live = False
self._stop_price = 0.0
self._take_price = 0.0
@property
def stop_pct(self):
return self._stop_pct.Value
@property
def tp_small(self):
return self._tp_small.Value
@property
def tp_large(self):
return self._tp_large.Value
@property
def trail_pct(self):
return self._trail_pct.Value
@property
def max_bars(self):
return self._max_bars.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(xrp_ai15m_adaptive_v31_strategy, self).OnReseted()
self._trend_up = False
self._bar_index = 0
self._entry_bar = 0
self._entry_price = 0.0
self._high_water = 0.0
self._trail_live = False
self._stop_price = 0.0
self._take_price = 0.0
def OnStarted2(self, time):
super(xrp_ai15m_adaptive_v31_strategy, self).OnStarted2(time)
ema13 = ExponentialMovingAverage()
ema13.Length = 13
ema34 = ExponentialMovingAverage()
ema34.Length = 34
rsi = RelativeStrengthIndex()
rsi.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema13, ema34, rsi, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema13)
self.DrawIndicator(area, ema34)
self.DrawOwnTrades(area)
def on_process(self, candle, ema13, ema34, rsi):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
# Use EMA cross for trend
self._trend_up = ema13 > ema34
# Exit management
if self.Position > 0 and self._entry_price > 0:
if candle.HighPrice > self._high_water:
self._high_water = candle.HighPrice
# Stop loss
if candle.ClosePrice <= self._stop_price:
self.SellMarket()
# ResetTrade()
return
# Take profit
if candle.ClosePrice >= self._take_price:
self.SellMarket()
# ResetTrade()
return
# Trailing stop
if not self._trail_live and self._high_water >= self._entry_price * (1 + self.trail_pct / 100):
self._trail_live = True
if self._trail_live:
trail_stop = self._high_water * (1 - self.trail_pct / 200)
if candle.ClosePrice <= trail_stop:
self.SellMarket()
# ResetTrade()
return
# Time-based exit
if self._bar_index - self._entry_bar >= self.max_bars:
self.SellMarket()
# ResetTrade()
return
# Entry conditions - long only
if self.Position == 0:
# Large setup: extreme oversold + trend up
large_ok = rsi < 25 and candle.ClosePrice > ema34 and self._trend_up
# Small setup: pullback to EMA in uptrend
small_ok = (candle.ClosePrice <= ema13 * 0.998 and
rsi < 45 and
candle.ClosePrice > candle.OpenPrice and
self._trend_up)
if large_ok:
self.BuyMarket()
self._entry_price = candle.ClosePrice
self._entry_bar = self._bar_index
self._high_water = candle.ClosePrice
self._trail_live = False
self._stop_price = self._entry_price * (1 - self.stop_pct / 100)
self._take_price = self._entry_price * (1 + self.tp_large / 100)
elif small_ok:
self.BuyMarket()
self._entry_price = candle.ClosePrice
self._entry_bar = self._bar_index
self._high_water = candle.ClosePrice
self._trail_live = False
self._stop_price = self._entry_price * (1 - self.stop_pct / 100)
self._take_price = self._entry_price * (1 + self.tp_small / 100)
def reset_trade(self):
self._entry_bar = -1
self._entry_price = 0
self._high_water = 0
self._trail_live = False
self._stop_price = 0
self._take_price = 0
def CreateClone(self):
return xrp_ai15m_adaptive_v31_strategy()