移动交叉策略
概述
该策略是 move_cross.mq4 脚本的简化转换版本。策略使用由两条简单移动平均线计算的 RAVI(Range Action Verification Index)指标来判断趋势方向。
策略比较小时和日线的 RAVI 数值:
- 当小时 RAVI 为负且日线 RAVI 为正并上升时买入。
- 当小时 RAVI 为正且日线 RAVI 为负并下降时卖出。
策略以市价开仓,可选设定止盈和止损。
参数
| 名称 | 说明 | 默认值 |
|---|---|---|
| TakeProfit | 止盈点数 | 50 |
| StopLoss | 止损点数 | 100 |
备注
- 策略在小时和日线级别上使用两组长度分别为 2 和 24 的 SMA 计算 RAVI。
- 该示例仅用于教学目的,在真实交易前需要进一步调试。
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>
/// RAVI based trend strategy.
/// Uses fast and slow SMA to compute RAVI oscillator. Enters on RAVI trending conditions.
/// </summary>
public class MoveCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<decimal> _threshold;
private readonly StrategyParam<DataType> _candleType;
private decimal _raviPrev1;
private decimal _raviPrev2;
private decimal _raviPrev3;
private bool _hasHistory;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public decimal Threshold { get => _threshold.Value; set => _threshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MoveCrossStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 24)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
_threshold = Param(nameof(Threshold), 0.5m)
.SetDisplay("Threshold", "RAVI threshold", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_raviPrev1 = 0;
_raviPrev2 = 0;
_raviPrev3 = 0;
_hasHistory = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastSma = new SimpleMovingAverage { Length = FastPeriod };
var slowSma = new SimpleMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastSma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (slow == 0)
return;
var ravi = (fast - slow) / slow * 100m;
if (_hasHistory)
{
// Buy: RAVI rising for 3 bars and above threshold
var raviRising = ravi > _raviPrev1 && _raviPrev1 > _raviPrev2 && _raviPrev2 > _raviPrev3;
// Sell: RAVI falling for 3 bars and below negative threshold
var raviFalling = ravi < _raviPrev1 && _raviPrev1 < _raviPrev2 && _raviPrev2 < _raviPrev3;
if (raviRising && ravi > Threshold && Position <= 0)
BuyMarket();
else if (raviFalling && ravi < -Threshold && Position >= 0)
SellMarket();
}
_raviPrev3 = _raviPrev2;
_raviPrev2 = _raviPrev1;
_raviPrev1 = ravi;
_hasHistory = true;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class move_cross_strategy(Strategy):
def __init__(self):
super(move_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast Period", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 24) \
.SetDisplay("Slow Period", "Slow SMA period", "Indicators")
self._threshold = self.Param("Threshold", 0.5) \
.SetDisplay("Threshold", "RAVI threshold", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._ravi_prev1 = 0.0
self._ravi_prev2 = 0.0
self._ravi_prev3 = 0.0
self._has_history = False
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def threshold(self):
return self._threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(move_cross_strategy, self).OnReseted()
self._ravi_prev1 = 0.0
self._ravi_prev2 = 0.0
self._ravi_prev3 = 0.0
self._has_history = False
def OnStarted2(self, time):
super(move_cross_strategy, self).OnStarted2(time)
fast_sma = SimpleMovingAverage()
fast_sma.Length = self.fast_period
slow_sma = SimpleMovingAverage()
slow_sma.Length = self.slow_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_sma, slow_sma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_sma)
self.DrawIndicator(area, slow_sma)
self.DrawOwnTrades(area)
def on_process(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
if slow == 0:
return
ravi = (fast - slow) / slow * 100
if self._has_history:
# Buy: RAVI rising for 3 bars and above threshold
ravi_rising = ravi > self._ravi_prev1 and self._ravi_prev1 > self._ravi_prev2 and self._ravi_prev2 > self._ravi_prev3
# Sell: RAVI falling for 3 bars and below negative threshold
ravi_falling = ravi < self._ravi_prev1 and self._ravi_prev1 < self._ravi_prev2 and self._ravi_prev2 < self._ravi_prev3
if ravi_rising and ravi > self.threshold and self.Position <= 0:
self.BuyMarket()
elif ravi_falling and ravi < -self.threshold and self.Position >= 0:
self.SellMarket()
self._ravi_prev3 = self._ravi_prev2
self._ravi_prev2 = self._ravi_prev1
self._ravi_prev1 = ravi
self._has_history = True
def CreateClone(self):
return move_cross_strategy()