SMC 策略
SMC策略利用最近的摆动高点和低点来定义溢价、均衡和折扣区域。结合SMA趋势过滤和简单订单块确认,在折扣区买入、溢价区卖出。
详情
- 入场条件: 价格在折扣区且高于SMA并得到订单块支撑;价格在溢价区且低于SMA并受订单块阻力
- 多空方向: 双向
- 出场条件: 相反信号
- 止损: 无
- 默认值:
SwingHighLength= 8SwingLowLength= 8SmaLength= 50OrderBlockLength= 20
- 过滤器:
- 分类: Zone
- 方向: 双向
- 指标: Highest, Lowest, SMA
- 止损: 无
- 复杂度: Basic
- 时间框架: Intraday
- 季节性: 无
- 神经网络: 无
- 背离: 无
- 风险等级: Medium
using System;
using System.Collections.Generic;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Premium/discount SMC zone strategy with SMA and simple order-block confirmation.
/// </summary>
public class SmcStrategy : Strategy
{
private readonly StrategyParam<int> _swingHighLength;
private readonly StrategyParam<int> _swingLowLength;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<int> _orderBlockLength;
private readonly StrategyParam<DataType> _candleType;
private readonly List<ICandleMessage> _candles = [];
public int SwingHighLength { get => _swingHighLength.Value; set => _swingHighLength.Value = value; }
public int SwingLowLength { get => _swingLowLength.Value; set => _swingLowLength.Value = value; }
public int SmaLength { get => _smaLength.Value; set => _smaLength.Value = value; }
public int OrderBlockLength { get => _orderBlockLength.Value; set => _orderBlockLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SmcStrategy()
{
_swingHighLength = Param(nameof(SwingHighLength), 8).SetGreaterThanZero();
_swingLowLength = Param(nameof(SwingLowLength), 8).SetGreaterThanZero();
_smaLength = Param(nameof(SmaLength), 50).SetGreaterThanZero();
_orderBlockLength = Param(nameof(OrderBlockLength), 20).SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_candles.Add(candle);
var required = Math.Max(Math.Max(SwingHighLength, SwingLowLength), Math.Max(SmaLength, OrderBlockLength)) + 1;
if (_candles.Count > required)
_candles.RemoveRange(0, _candles.Count - required);
if (_candles.Count < required)
return;
var previous = _candles.Take(_candles.Count - 1).ToArray();
var swingHigh = previous.Skip(previous.Length - SwingHighLength).Max(c => c.HighPrice);
var swingLow = previous.Skip(previous.Length - SwingLowLength).Min(c => c.LowPrice);
var sma = _candles.Skip(_candles.Count - SmaLength).Average(c => c.ClosePrice);
var orderBlock = previous.Skip(previous.Length - OrderBlockLength).ToArray();
var support = orderBlock.Min(c => c.LowPrice);
var resistance = orderBlock.Max(c => c.HighPrice);
var hasSupport = candle.LowPrice <= support && candle.ClosePrice >= support;
var hasResistance = candle.HighPrice >= resistance && candle.ClosePrice <= resistance;
var signal = GetSignal(
candle.ClosePrice, swingLow, swingHigh, sma, hasSupport, hasResistance);
if (signal > 0 && Position <= 0m)
BuyMarket(Volume + Math.Abs(Position));
else if (signal < 0 && Position >= 0m)
SellMarket(Volume + Math.Abs(Position));
}
internal static int GetSignal(
decimal price,
decimal swingLow,
decimal swingHigh,
decimal sma,
bool hasSupport,
bool hasResistance)
{
if (swingHigh <= swingLow)
return 0;
var equilibrium = (swingHigh + swingLow) / 2m;
if (price <= equilibrium && price > sma && hasSupport)
return 1;
if (price >= equilibrium && price < sma && hasResistance)
return -1;
return 0;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class smc_strategy(Strategy):
def __init__(self):
super(smc_strategy, self).__init__()
self._swing_high_length = self.Param("SwingHighLength", 8).SetGreaterThanZero()
self._swing_low_length = self.Param("SwingLowLength", 8).SetGreaterThanZero()
self._sma_length = self.Param("SmaLength", 50).SetGreaterThanZero()
self._order_block_length = self.Param("OrderBlockLength", 20).SetGreaterThanZero()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._candles = []
def GetWorkingSecurities(self):
return [(self.Security, self._candle_type.Value)]
def OnReseted(self):
super(smc_strategy, self).OnReseted()
self._candles = []
def OnStarted2(self, time):
super(smc_strategy, self).OnStarted2(time)
self.SubscribeCandles(self._candle_type.Value).Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
self._candles.append(candle)
required = max(
int(self._swing_high_length.Value),
int(self._swing_low_length.Value),
int(self._sma_length.Value),
int(self._order_block_length.Value)) + 1
if len(self._candles) > required:
del self._candles[:-required]
if len(self._candles) < required:
return
previous = self._candles[:-1]
sh = int(self._swing_high_length.Value)
sl = int(self._swing_low_length.Value)
sma_len = int(self._sma_length.Value)
ob_len = int(self._order_block_length.Value)
swing_high = max(float(c.HighPrice) for c in previous[-sh:])
swing_low = min(float(c.LowPrice) for c in previous[-sl:])
sma = sum(float(c.ClosePrice) for c in self._candles[-sma_len:]) / sma_len
order_block = previous[-ob_len:]
support = min(float(c.LowPrice) for c in order_block)
resistance = max(float(c.HighPrice) for c in order_block)
close = float(candle.ClosePrice)
has_support = float(candle.LowPrice) <= support and close >= support
has_resistance = float(candle.HighPrice) >= resistance and close <= resistance
signal = self.get_signal(close, swing_low, swing_high, sma, has_support, has_resistance)
if signal > 0 and self.Position <= 0:
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif signal < 0 and self.Position >= 0:
self.SellMarket(self.Volume + Math.Abs(self.Position))
@staticmethod
def get_signal(price, swing_low, swing_high, sma, has_support, has_resistance):
if swing_high <= swing_low:
return 0
equilibrium = (swing_high + swing_low) / 2.0
if price <= equilibrium and price > sma and has_support:
return 1
if price >= equilibrium and price < sma and has_resistance:
return -1
return 0
def CreateClone(self):
return smc_strategy()