SmartAssTrade V2 Strategy
SmartAssTrade V2策略在多重时间框架(1m、5m、15m、30m、60m)上使用MACD直方图和20周期移动平均线,并结合Williams %R和RSI过滤器捕捉趋势动量。可选的追踪止损用于保护利润。
细节
- 入场条件:多数时间框架的MACD直方图和均线同时上升,并得到WPR/RSI确认
- 多空方向:双向
- 出场条件:价格触及止盈或止损;可选追踪止损
- 止损:绝对止损与止盈,可选追踪
- 默认值:
Volume= 1TakeProfit= 35StopLoss= 62UseTrailingStop= falseTrailingStop= 30TrailingStopStep= 1
- 过滤器:
- 类别:趋势
- 方向:双向
- 指标:MACD, SMA, Williams %R, RSI
- 止损:可选
- 复杂度:中等
- 时间框架:多时间框架 (1m,5m,15m,30m,60m)
- 季节性:无
- 神经网络:无
- 背离:无
- 风险等级:中等
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>
/// Strategy based on MACD histogram direction, WilliamsR, RSI and MA trend.
/// Buys when MACD is rising, MA is trending up, WPR and RSI confirm momentum.
/// </summary>
public class SmartAssTradeV2Strategy : Strategy
{
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<DataType> _candleType;
private MovingAverageConvergenceDivergence _macd;
private SimpleMovingAverage _ma;
private WilliamsR _wpr;
private RelativeStrengthIndex _rsi;
private decimal? _prevMacd;
private decimal? _prevMa;
private decimal? _prevWpr;
private decimal? _prevRsi;
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SmartAssTradeV2Strategy()
{
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk Management");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = null;
_prevMa = null;
_prevWpr = null;
_prevRsi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_macd = new MovingAverageConvergenceDivergence();
_ma = new SimpleMovingAverage { Length = 20 };
_wpr = new WilliamsR { Length = 26 };
_rsi = new RelativeStrengthIndex { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
StartProtection(
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent)
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var macdResult = _macd.Process(candle.ClosePrice, candle.OpenTime, true);
var maResult = _ma.Process(candle.ClosePrice, candle.OpenTime, true);
var wprResult = _wpr.Process(candle);
var rsiResult = _rsi.Process(candle.ClosePrice, candle.OpenTime, true);
if (!macdResult.IsFormed || !maResult.IsFormed || !wprResult.IsFormed || !rsiResult.IsFormed)
return;
var currMacd = macdResult.ToDecimal();
var currMa = maResult.ToDecimal();
var currWpr = wprResult.ToDecimal();
var currRsi = rsiResult.ToDecimal();
if (_prevMacd == null || _prevMa == null || _prevWpr == null || _prevRsi == null)
{
_prevMacd = currMacd;
_prevMa = currMa;
_prevWpr = currWpr;
_prevRsi = currRsi;
return;
}
var macdRising = currMacd > _prevMacd;
var macdFalling = currMacd < _prevMacd;
var maRising = currMa > _prevMa;
var maFalling = currMa < _prevMa;
// Buy signal: MACD rising, MA rising, WPR recovering, RSI rising below 70
var buySignal = macdRising && maRising
&& currWpr > _prevWpr && currRsi > _prevRsi
&& currRsi < 70m;
// Sell signal: MACD falling, MA falling, WPR declining, RSI falling above 30
var sellSignal = macdFalling && maFalling
&& currWpr < _prevWpr && currRsi < _prevRsi
&& currRsi > 30m;
if (Position <= 0 && buySignal)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (Position >= 0 && sellSignal)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevMacd = currMacd;
_prevMa = currMa;
_prevWpr = currWpr;
_prevRsi = currRsi;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import MovingAverageConvergenceDivergence, SimpleMovingAverage, WilliamsR, RelativeStrengthIndex, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class smart_ass_trade_v2_strategy(Strategy):
def __init__(self):
super(smart_ass_trade_v2_strategy, self).__init__()
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk Management")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._macd = None
self._ma = None
self._wpr = None
self._rsi = None
self._prev_macd = None
self._prev_ma = None
self._prev_wpr = None
self._prev_rsi = None
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(smart_ass_trade_v2_strategy, self).OnReseted()
self._prev_macd = None
self._prev_ma = None
self._prev_wpr = None
self._prev_rsi = None
def OnStarted2(self, time):
super(smart_ass_trade_v2_strategy, self).OnStarted2(time)
self._macd = MovingAverageConvergenceDivergence()
self._ma = SimpleMovingAverage()
self._ma.Length = 20
self._wpr = WilliamsR()
self._wpr.Length = 26
self._rsi = RelativeStrengthIndex()
self._rsi.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
self.StartProtection(
Unit(float(self.take_profit_pct), UnitTypes.Percent),
Unit(float(self.stop_loss_pct), UnitTypes.Percent))
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
macd_result = process_float(self._macd, candle.ClosePrice, candle.OpenTime, True)
ma_result = process_float(self._ma, candle.ClosePrice, candle.OpenTime, True)
wpr_inp = CandleIndicatorValue(self._wpr, candle)
wpr_result = self._wpr.Process(wpr_inp)
rsi_result = process_float(self._rsi, candle.ClosePrice, candle.OpenTime, True)
if not macd_result.IsFormed or not ma_result.IsFormed or not wpr_result.IsFormed or not rsi_result.IsFormed:
return
curr_macd = float(macd_result)
curr_ma = float(ma_result)
curr_wpr = float(wpr_result)
curr_rsi = float(rsi_result)
if self._prev_macd is None or self._prev_ma is None or self._prev_wpr is None or self._prev_rsi is None:
self._prev_macd = curr_macd
self._prev_ma = curr_ma
self._prev_wpr = curr_wpr
self._prev_rsi = curr_rsi
return
macd_rising = curr_macd > self._prev_macd
macd_falling = curr_macd < self._prev_macd
ma_rising = curr_ma > self._prev_ma
ma_falling = curr_ma < self._prev_ma
buy_signal = (macd_rising and ma_rising and
curr_wpr > self._prev_wpr and curr_rsi > self._prev_rsi and
curr_rsi < 70.0)
sell_signal = (macd_falling and ma_falling and
curr_wpr < self._prev_wpr and curr_rsi < self._prev_rsi and
curr_rsi > 30.0)
if self.Position <= 0 and buy_signal:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self.Position >= 0 and sell_signal:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_macd = curr_macd
self._prev_ma = curr_ma
self._prev_wpr = curr_wpr
self._prev_rsi = curr_rsi
def CreateClone(self):
return smart_ass_trade_v2_strategy()