首页
/
策略示例
在 GitHub 上查看
MACD and SAR
该策略复刻了 MetaTrader 上的 “MACD and SAR” 专家顾问。在每根完成的 K 线结束后,它会同时检查 MACD 主线与信号线之间的关系以及 Parabolic SAR 点位。每个比较条件都提供了布尔开关,可以轻松反转方向,因此同一个框架既可用于顺势也可用于逆势思路。当累积仓位数未超过上限时,允许分批加仓。
当出现做多信号时,策略会先平掉所有空头头寸,然后在允许的情况下新增一个多头手数。做空信号的处理方式相同:先平多,再开空。没有额外的止损或止盈订单,仓位只会在生成反向信号时被关闭。
策略逻辑
等待配置好的时间框架上的 K 线收盘。
读取基于收盘价计算的 MACD(三个分量)以及当前的 Parabolic SAR 数值。
按以下顺序检查三个比较条件,每一项都可以通过布尔参数翻转:
MACD 主线与信号线的大小关系。
MACD 信号线与零轴的关系。
Parabolic SAR 与收盘价的关系。
如果三个做多条件全部满足且尚未达到持仓上限,则买入设定的手数(同时覆盖平空所需的数量)。
如果三个做空条件全部满足且仍有空间,则卖出设定的手数(包括平多所需的数量)。
参数
TradeVolume — 单笔交易的成交量(默认 0.1)。
MaxPositions — 同方向最多允许累计的仓位数量(默认 10)。
MacdFastPeriod — MACD 快速 EMA 周期(默认 12)。
MacdSlowPeriod — MACD 慢速 EMA 周期(默认 26)。
MacdSignalPeriod — MACD 信号线平滑周期(默认 9)。
SarStep — Parabolic SAR 加速度步长(默认 0.02)。
SarMaximum — Parabolic SAR 最大加速度(默认 0.2)。
BuyMacdGreaterSignal — 若为 true,做多需要 MACD 主线 > 信号线;否则要求主线 < 信号线(默认 true)。
BuySignalPositive — 若为 true,做多需要信号线 > 0;否则要求信号线 < 0(默认 false)。
BuySarAbovePrice — 若为 true,做多要求 SAR 高于价格;否则要求价格高于 SAR(默认 false)。
SellMacdGreaterSignal — 若为 true,做空需要 MACD 主线 > 信号线;否则要求主线 < 信号线(默认 false)。
SellSignalPositive — 若为 true,做空需要信号线 > 0;否则要求信号线 < 0(默认 true)。
SellSarAbovePrice — 若为 true,做空要求 SAR 高于价格;否则要求价格高于 SAR(默认 true)。
CandleType — 指标计算所使用的 K 线类型/时间框架(默认 15 分钟)。
其他说明
策略完全依赖指标信号,不包含额外的止损、止盈或资金管理规则。
通过比较 |Position| 与 MaxPositions * TradeVolume(带有微小容差)来控制加仓上限。
所有交易均以市价执行,请确保组合的成交量设置与目标市场兼容。
如需限制回撤或添加移动止损,可以利用 StockSharp 的保护机制,本实现未内置相关功能。
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>
/// MACD and Parabolic SAR trend-following strategy (simplified).
/// Uses EMA crossover as MACD proxy and ParabolicSar for trend confirmation.
/// </summary>
public class MacdAndSarStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public MacdAndSarStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles used for analysis", "General");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
decimal prevFast = 0, prevSlow = 0;
bool hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastValue;
prevSlow = slowValue;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastValue;
prevSlow = slowValue;
return;
}
// Crossover detection (MACD-like)
if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
{
BuyMarket();
}
else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
{
SellMarket();
}
prevFast = fastValue;
prevSlow = slowValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
}
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
from StockSharp.Algo.Strategies import Strategy
class macd_and_sar_strategy(Strategy):
def __init__(self):
super(macd_and_sar_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 26) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles used for analysis", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_and_sar_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(macd_and_sar_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(fast_ema, slow_ema, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return macd_and_sar_strategy()