SAR Автоматическая стратегия
Пример демонстрирует простую торговую методику на основе индикатора Parabolic SAR. Стратегия открывает длинную позицию, когда цена закрытия выше значения SAR и позиция отсутствует, и открывает короткую позицию, когда цена ниже SAR. Дополнительно реализованы фиксированные стоп-лосс, тейк-профит и опциональный трейлинг-стоп.
Параметры
SarStep– коэффициент ускорения SAR.SarMax– максимальный коэффициент ускорения SAR.StopLoss– расстояние стоп-лосса в ценовых единицах.TakeProfit– расстояние тейк-профита в ценовых единицах.TrailingStop– расстояние трейлинг-стопа в ценовых единицах.CandleType– тип свечей для расчётов.
Логика торговли
- Подписка на свечи и вычисление значений Parabolic SAR.
- Вход:
- Покупка при отсутствии позиции, если SAR ниже цены закрытия.
- Продажа при отсутствии позиции, если SAR выше цены закрытия.
- Выход:
- Закрытие позиции при достижении противоположного уровня SAR.
- Применение стоп-лосса, тейк-профита и трейлинг-стопа.
Стратегия предназначена для учебных целей и демонстрирует использование индикаторов и управления рисками в высокоуровневом API StockSharp.
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>
/// Simple Parabolic SAR based strategy with optional stop-loss,
/// take-profit and trailing stop management.
/// </summary>
public class SarAutomatedStrategy : Strategy
{
private readonly StrategyParam<decimal> _sarStep;
private readonly StrategyParam<decimal> _sarMax;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _highestPrice;
private decimal _lowestPrice;
/// <summary>
/// Parabolic SAR acceleration step.
/// </summary>
public decimal SarStep
{
get => _sarStep.Value;
set => _sarStep.Value = value;
}
/// <summary>
/// Parabolic SAR maximum acceleration.
/// </summary>
public decimal SarMax
{
get => _sarMax.Value;
set => _sarMax.Value = value;
}
/// <summary>
/// Stop loss in price units.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit in price units.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Trailing stop in price units.
/// </summary>
public decimal TrailingStop
{
get => _trailingStop.Value;
set => _trailingStop.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="SarAutomatedStrategy"/>.
/// </summary>
public SarAutomatedStrategy()
{
_sarStep = Param(nameof(SarStep), 0.002m)
.SetDisplay("SAR Step", "Acceleration factor for SAR", "Indicators");
_sarMax = Param(nameof(SarMax), 0.02m)
.SetDisplay("SAR Max", "Maximum acceleration for SAR", "Indicators");
_stopLoss = Param(nameof(StopLoss), 3500m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk Management");
_takeProfit = Param(nameof(TakeProfit), 6500m)
.SetDisplay("Take Profit", "Take profit in price units", "Risk Management");
_trailingStop = Param(nameof(TrailingStop), 800m)
.SetDisplay("Trailing Stop", "Trailing stop in price units", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).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();
_entryPrice = 0m;
_highestPrice = 0m;
_lowestPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sar = new ParabolicSar
{
Acceleration = SarStep,
AccelerationMax = SarMax
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sar, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal sarValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position == 0)
{
if (sarValue < candle.ClosePrice)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_highestPrice = candle.ClosePrice;
_lowestPrice = candle.ClosePrice;
}
else if (sarValue > candle.ClosePrice)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_highestPrice = candle.ClosePrice;
_lowestPrice = candle.ClosePrice;
}
}
else if (Position > 0)
{
_highestPrice = Math.Max(_highestPrice, candle.HighPrice);
if (candle.HighPrice - _entryPrice >= TakeProfit)
{
SellMarket();
return;
}
if (_entryPrice - candle.LowPrice >= StopLoss)
{
SellMarket();
return;
}
if (TrailingStop > 0m && _highestPrice - candle.ClosePrice >= TrailingStop)
{
SellMarket();
return;
}
if (sarValue > candle.ClosePrice)
{
SellMarket();
}
}
else if (Position < 0)
{
_lowestPrice = Math.Min(_lowestPrice, candle.LowPrice);
if (_entryPrice - candle.LowPrice >= TakeProfit)
{
BuyMarket();
return;
}
if (candle.HighPrice - _entryPrice >= StopLoss)
{
BuyMarket();
return;
}
if (TrailingStop > 0m && candle.ClosePrice - _lowestPrice >= TrailingStop)
{
BuyMarket();
return;
}
if (sarValue < candle.ClosePrice)
{
BuyMarket();
}
}
}
}
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 ParabolicSar
from StockSharp.Algo.Strategies import Strategy
class sar_automated_strategy(Strategy):
def __init__(self):
super(sar_automated_strategy, self).__init__()
self._sar_step = self.Param("SarStep", 0.002) \
.SetDisplay("SAR Step", "Acceleration factor for SAR", "Indicators")
self._sar_max = self.Param("SarMax", 0.02) \
.SetDisplay("SAR Max", "Maximum acceleration for SAR", "Indicators")
self._stop_loss = self.Param("StopLoss", 3500.0) \
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk Management")
self._take_profit = self.Param("TakeProfit", 6500.0) \
.SetDisplay("Take Profit", "Take profit in price units", "Risk Management")
self._trailing_stop = self.Param("TrailingStop", 800.0) \
.SetDisplay("Trailing Stop", "Trailing stop in price units", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
self._highest_price = 0.0
self._lowest_price = 0.0
@property
def sar_step(self):
return self._sar_step.Value
@property
def sar_max(self):
return self._sar_max.Value
@property
def stop_loss(self):
return self._stop_loss.Value
@property
def take_profit(self):
return self._take_profit.Value
@property
def trailing_stop(self):
return self._trailing_stop.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(sar_automated_strategy, self).OnReseted()
self._entry_price = 0.0
self._highest_price = 0.0
self._lowest_price = 0.0
def OnStarted2(self, time):
super(sar_automated_strategy, self).OnStarted2(time)
sar = ParabolicSar()
sar.Acceleration = self.sar_step
sar.AccelerationMax = self.sar_max
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sar, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
def process_candle(self, candle, sar_value):
if candle.State != CandleStates.Finished:
return
sar_value = float(sar_value)
close_price = float(candle.ClosePrice)
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
tp = float(self.take_profit)
sl = float(self.stop_loss)
ts = float(self.trailing_stop)
if self.Position == 0:
if sar_value < close_price:
self.BuyMarket()
self._entry_price = close_price
self._highest_price = close_price
self._lowest_price = close_price
elif sar_value > close_price:
self.SellMarket()
self._entry_price = close_price
self._highest_price = close_price
self._lowest_price = close_price
elif self.Position > 0:
self._highest_price = max(self._highest_price, high_price)
if high_price - self._entry_price >= tp:
self.SellMarket()
return
if self._entry_price - low_price >= sl:
self.SellMarket()
return
if ts > 0 and self._highest_price - close_price >= ts:
self.SellMarket()
return
if sar_value > close_price:
self.SellMarket()
elif self.Position < 0:
self._lowest_price = min(self._lowest_price, low_price)
if self._entry_price - low_price >= tp:
self.BuyMarket()
return
if high_price - self._entry_price >= sl:
self.BuyMarket()
return
if ts > 0 and close_price - self._lowest_price >= ts:
self.BuyMarket()
return
if sar_value < close_price:
self.BuyMarket()
def CreateClone(self):
return sar_automated_strategy()