Стратегия S7 Up Bot
Система пробоя, ищущая почти равные экстремумы, после которых цена делает резкий рывок.
Если два последовательных минимума почти равны и цена поднимается на Span Price, открывается покупка.
Продажа выполняется, когда два максимума совпадают и цена падает на Span Price.
Позиции защищаются тейк-профитом, стоп-лоссом, трейлинг-стопом и ранними выходами.
Детали
- Условия входа:
- Покупка: текущий и предыдущий минимум отличаются менее чем на
HL Divergence и цена выше минимума на Span Price.
- Продажа: текущий и предыдущий максимум отличаются менее чем на
HL Divergence и цена ниже максимума на Span Price.
- Длинные/Короткие: обе стороны.
- Условия выхода:
- Тейк-профит или стоп-лосс.
- Трейлинг-стоп или перенос стопа в безубыток.
- Ранний выход при пробое предыдущего экстремума (
Exit At Extremum) или при приближении к обратному уровню (Exit At Reversal).
- Стопы: абсолютные TP и SL с возможным трейлингом.
- Фильтры: отсутствуют.
Параметры
Take Profit – цель по прибыли в ценовых пунктах.
Stop Loss – ограничение убытка, 0 для автоматического.
HL Divergence – допустимое различие между экстремумами.
Span Price – расстояние от экстремума до цены для входа.
Max Trades – максимальное число одновременных сделок.
Use Trailing Stop – включить трейлинг-стоп.
Trail Stop – расстояние трейлинг-стопа.
Zero Trailing – перенос стопа при движении в прибыль.
Step Trailing – минимальный шаг переноса.
Exit At Extremum – выход при пробое предыдущего максимума/минимума.
Exit At Reversal – выход при приближении к противоположному уровню.
Span To Revers – дистанция для выхода по развороту.
Candle Type – используемый таймфрейм.
Order Volume – объём сделки.
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>
/// S7 Up Bot breakout strategy.
/// Opens long after double bottom and short after double top.
/// </summary>
public class S7UpBotStrategy : Strategy
{
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _hlDivergence;
private readonly StrategyParam<decimal> _spanPrice;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevLow;
private decimal _prevHigh;
private decimal _entryPrice;
private decimal _stopPrice;
private decimal _takeProfitPrice;
private bool _isLong;
private bool _inPosition;
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal HlDivergence { get => _hlDivergence.Value; set => _hlDivergence.Value = value; }
public decimal SpanPrice { get => _spanPrice.Value; set => _spanPrice.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public S7UpBotStrategy()
{
_takeProfit = Param(nameof(TakeProfit), 500m)
.SetDisplay("Take Profit", "Absolute take profit", "Risk");
_stopLoss = Param(nameof(StopLoss), 300m)
.SetDisplay("Stop Loss", "Absolute stop loss", "Risk");
_hlDivergence = Param(nameof(HlDivergence), 100m)
.SetGreaterThanZero()
.SetDisplay("HL Divergence", "Max difference between highs or lows", "General");
_spanPrice = Param(nameof(SpanPrice), 50m)
.SetGreaterThanZero()
.SetDisplay("Span Price", "Distance from extreme to price", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for analysis", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLow = 0m;
_prevHigh = 0m;
_entryPrice = 0m;
_stopPrice = 0m;
_takeProfitPrice = 0m;
_isLong = false;
_inPosition = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevLow = 0m;
_prevHigh = 0m;
_inPosition = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
if (_inPosition)
ManagePosition(candle, price);
if (!_inPosition && _prevLow != 0m && _prevHigh != 0m)
CheckEntry(candle, price);
_prevLow = candle.LowPrice;
_prevHigh = candle.HighPrice;
}
private void CheckEntry(ICandleMessage candle, decimal price)
{
// Double bottom: consecutive similar lows + bounce
if (Math.Abs(candle.LowPrice - _prevLow) < HlDivergence &&
price - candle.LowPrice > SpanPrice)
{
if (Position <= 0)
BuyMarket();
_inPosition = true;
_isLong = true;
_entryPrice = price;
_stopPrice = price - StopLoss;
_takeProfitPrice = price + TakeProfit;
}
// Double top: consecutive similar highs + drop
else if (Math.Abs(candle.HighPrice - _prevHigh) < HlDivergence &&
candle.HighPrice - price > SpanPrice)
{
if (Position >= 0)
SellMarket();
_inPosition = true;
_isLong = false;
_entryPrice = price;
_stopPrice = price + StopLoss;
_takeProfitPrice = price - TakeProfit;
}
}
private void ManagePosition(ICandleMessage candle, decimal price)
{
if (_isLong)
{
if (candle.HighPrice >= _takeProfitPrice || candle.LowPrice <= _stopPrice)
{
SellMarket();
_inPosition = false;
}
}
else
{
if (candle.LowPrice <= _takeProfitPrice || candle.HighPrice >= _stopPrice)
{
BuyMarket();
_inPosition = false;
}
}
}
}
import clr
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.Strategies import Strategy
class s7_up_bot_strategy(Strategy):
def __init__(self):
super(s7_up_bot_strategy, self).__init__()
self._take_profit = self.Param("TakeProfit", 500.0) \
.SetDisplay("Take Profit", "Absolute take profit", "Risk")
self._stop_loss = self.Param("StopLoss", 300.0) \
.SetDisplay("Stop Loss", "Absolute stop loss", "Risk")
self._hl_divergence = self.Param("HlDivergence", 100.0) \
.SetDisplay("HL Divergence", "Max difference between highs or lows", "General")
self._span_price = self.Param("SpanPrice", 50.0) \
.SetDisplay("Span Price", "Distance from extreme to price", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for analysis", "General")
self._prev_low = 0.0
self._prev_high = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
self._take_profit_price = 0.0
self._is_long = False
self._in_position = False
@property
def take_profit(self):
return self._take_profit.Value
@property
def stop_loss(self):
return self._stop_loss.Value
@property
def hl_divergence(self):
return self._hl_divergence.Value
@property
def span_price(self):
return self._span_price.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(s7_up_bot_strategy, self).OnReseted()
self._prev_low = 0.0
self._prev_high = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
self._take_profit_price = 0.0
self._is_long = False
self._in_position = False
def OnStarted2(self, time):
super(s7_up_bot_strategy, self).OnStarted2(time)
self._prev_low = 0.0
self._prev_high = 0.0
self._in_position = False
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if self._in_position:
self._manage_position(candle, price)
if not self._in_position and self._prev_low != 0.0 and self._prev_high != 0.0:
self._check_entry(candle, price, high, low)
self._prev_low = low
self._prev_high = high
def _check_entry(self, candle, price, high, low):
hl_div = float(self.hl_divergence)
span = float(self.span_price)
tp = float(self.take_profit)
sl = float(self.stop_loss)
# Double bottom
if abs(low - self._prev_low) < hl_div and price - low > span:
if self.Position <= 0:
self.BuyMarket()
self._in_position = True
self._is_long = True
self._entry_price = price
self._stop_price = price - sl
self._take_profit_price = price + tp
# Double top
elif abs(high - self._prev_high) < hl_div and high - price > span:
if self.Position >= 0:
self.SellMarket()
self._in_position = True
self._is_long = False
self._entry_price = price
self._stop_price = price + sl
self._take_profit_price = price - tp
def _manage_position(self, candle, price):
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if self._is_long:
if high >= self._take_profit_price or low <= self._stop_price:
self.SellMarket()
self._in_position = False
else:
if low <= self._take_profit_price or high >= self._stop_price:
self.BuyMarket()
self._in_position = False
def CreateClone(self):
return s7_up_bot_strategy()