抛物线 SAR 反转策略
抛物线 SAR 指标在价格上方或下方绘制点位以指示趋势方向。当点位转换至另一侧时,可能意味着前一波行情结束。本策略在这种翻转发生时进场,期待短期反转。
测试表明年均收益约为 148%,该策略在外汇市场表现最佳。
每根K线维持运行的 SAR 值。当指标从价格上方转至下方时开多仓;从下方转至上方时做空。该方法不设固定盈利目标,通常依赖手动或尾随止损退出。
由于 SAR 反应灵敏,在震荡市可能出现假信号,因此最好在行情波动明显时使用。
细节
- 入场条件:抛物线 SAR 相对于价格翻转。
- 多/空:双向。
- 退出条件:手动或外部止损。
- 止损:未明确。
- 默认值:
InitialAcceleration= 0.02MaxAcceleration= 0.2CandleType= 15 分钟
- 过滤条件:
- 类别: 趋势跟随
- 方向: 双向
- 指标: 抛物线 SAR
- 止损: 可选
- 复杂度: 基础
- 时间框架: 日内
- 季节性: 无
- 神经网络: 无
- 背离: 无
- 风险级别: 中等
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>
/// Parabolic SAR Reversal strategy.
/// When the SAR moves from above the close to below it the position turns long, and when it moves from below to above it turns short.
/// There is no other exit.
/// </summary>
public class ParabolicSarReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _initialAcceleration;
private readonly StrategyParam<decimal> _maxAcceleration;
private readonly StrategyParam<DataType> _candleType;
private bool? _prevSarAbove;
/// <summary>
/// Initial acceleration factor of the SAR.
/// </summary>
public decimal InitialAcceleration
{
get => _initialAcceleration.Value;
set => _initialAcceleration.Value = value;
}
/// <summary>
/// Maximum acceleration factor of the SAR.
/// </summary>
public decimal MaxAcceleration
{
get => _maxAcceleration.Value;
set => _maxAcceleration.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ParabolicSarReversalStrategy()
{
_initialAcceleration = Param(nameof(InitialAcceleration), 0.02m)
.SetGreaterThanZero()
.SetDisplay("Initial Acceleration", "Initial acceleration factor of the SAR", "Indicators");
_maxAcceleration = Param(nameof(MaxAcceleration), 0.2m)
.SetGreaterThanZero()
.SetDisplay("Max Acceleration", "Maximum acceleration factor of the SAR", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSarAbove = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSarAbove = null;
var sar = new ParabolicSar
{
Acceleration = InitialAcceleration,
AccelerationMax = MaxAcceleration,
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(sar, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue sarValue)
{
if (candle.State != CandleStates.Finished || !sarValue.IsFormed || sarValue.IsEmpty)
return;
var sar = sarValue.GetValue<decimal>();
if (sar <= 0)
return;
var isSarAbove = sar > candle.ClosePrice;
var wasSarAbove = _prevSarAbove;
_prevSarAbove = isSarAbove;
if (wasSarAbove is not bool previous || previous == isSarAbove || !IsFormedAndOnlineAndAllowTrading())
return;
if (!isSarAbove && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (isSarAbove && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
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, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ParabolicSar
from StockSharp.Algo.Strategies import Strategy
class parabolic_sar_reversal_strategy(Strategy):
"""
Parabolic SAR Reversal strategy.
When the SAR moves from above the close to below it the position turns long, and when it moves from below to above it turns short.
There is no other exit.
"""
def __init__(self):
super(parabolic_sar_reversal_strategy, self).__init__()
self._initial_acceleration = self.Param("InitialAcceleration", 0.02).SetGreaterThanZero().SetDisplay("Initial Acceleration", "Initial acceleration factor of the SAR", "Indicators")
self._max_acceleration = self.Param("MaxAcceleration", 0.2).SetGreaterThanZero().SetDisplay("Max Acceleration", "Maximum acceleration factor of the SAR", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_sar_above = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(parabolic_sar_reversal_strategy, self).OnReseted()
self._prev_sar_above = None
def OnStarted2(self, time):
super(parabolic_sar_reversal_strategy, self).OnStarted2(time)
self._prev_sar_above = None
sar = ParabolicSar()
sar.Acceleration = Decimal(self._initial_acceleration.Value)
sar.AccelerationMax = Decimal(self._max_acceleration.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(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 or not sar_value.IsFormed or sar_value.IsEmpty:
return
sar = sar_value.GetValue[Decimal](None)
if sar <= 0:
return
is_sar_above = sar > candle.ClosePrice
was_sar_above = self._prev_sar_above
self._prev_sar_above = is_sar_above
if was_sar_above is None or was_sar_above == is_sar_above or not self.IsFormedAndOnlineAndAllowTrading():
return
if not is_sar_above and self.Position <= 0:
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif is_sar_above and self.Position >= 0:
self.SellMarket(self.Volume + Math.Abs(self.Position))
def CreateClone(self):
return parabolic_sar_reversal_strategy()