在 GitHub 上查看
平均蜡烛交叉策略
该策略重现了 MetaTrader 上的 “Average candle cross” 专家顾问。它只在上一根已完成的蜡烛向上或向下穿越均线、并且两组趋势均线已经指向同一方向时开仓。系统始终只持有一笔仓位,入场后立即根据设定的点值距离放置止损和止盈,使行为与原始的逐棒触发逻辑一致。
所有计算都基于已完成的 K 线,避免了未收盘行情带来的噪声。多头与空头拥有独立的均线参数,可以实现不同的平滑方式或周期。止损与止盈使用真实的挂单,距离等于 StopLossPips * PipSize,而止盈距离则为该值乘以对应的百分比参数。
细节
- 入场条件:
- 做多:上一根 K 线的两条趋势均线都向上 (
MA_fast1[1] > MA_slow1[1] 且 MA_fast2[1] > MA_slow2[1]),上一根 K 线收盘价高于交叉均线,同时前一根 K 线收盘价位于均线之下 (Close[2] <= MA_cross[2] 且 Close[1] > MA_cross[1])。
- 做空:上一根 K 线的两条趋势均线都向下 (
MA_fast1[1] < MA_slow1[1] 且 MA_fast2[1] < MA_slow2[1]),上一根 K 线收盘价低于交叉均线,同时前一根 K 线收盘价位于均线之上 (Close[2] >= MA_cross[2] 且 Close[1] < MA_cross[1])。
- 交易方向:多空双向,但不会同时持仓。
- 离场方式:
- 止损/止盈:是。止损距离为
StopLossPips * PipSize,止盈距离为止损距离乘以 “% of SL” 参数。
- 默认参数:
FirstTrendFastPeriod = 5,FirstTrendFastMethod = SMA。
FirstTrendSlowPeriod = 20,FirstTrendSlowMethod = SMA。
SecondTrendFastPeriod = 20,SecondTrendFastMethod = SMA。
SecondTrendSlowPeriod = 30,SecondTrendSlowMethod = SMA。
BullCrossPeriod = 5,BullCrossMethod = SMA。
BuyVolume = 0.01,BuyStopLossPips = 50,BuyTakeProfitPercent = 100。
FirstTrendBearFastPeriod = 5,FirstTrendBearFastMethod = SMA。
FirstTrendBearSlowPeriod = 20,FirstTrendBearSlowMethod = SMA。
SecondTrendBearFastPeriod = 20,SecondTrendBearFastMethod = SMA。
SecondTrendBearSlowPeriod = 30,SecondTrendBearSlowMethod = SMA。
BearCrossPeriod = 5,BearCrossMethod = SMA。
SellVolume = 0.01,SellStopLossPips = 50,SellTakeProfitPercent = 100。
PipSize = 0.0001。
- 过滤维度:
- 类型:趋势跟随。
- 方向:双向(多头与空头)。
- 指标:多条移动平均线。
- 止损:固定点数止损,按比例止盈。
- 复杂度:中等。
- 周期:使用配置的蜡烛序列(默认 15 分钟)。
- 季节性:否。
- 神经网络:否。
- 背离:否。
- 风险水平:中等。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Average Candle Cross strategy: price crossover above/below SMA.
/// Buys when close crosses above SMA, sells when close crosses below SMA.
/// </summary>
public class AverageCandleCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal _prevClose;
private decimal _prevSma;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public AverageCandleCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_period = Param(nameof(Period), 20)
.SetGreaterThanZero()
.SetDisplay("Period", "SMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevSma = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var sma = new SimpleMovingAverage { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevClose <= _prevSma && candle.ClosePrice > smaValue && Position <= 0)
BuyMarket();
else if (_prevClose >= _prevSma && candle.ClosePrice < smaValue && Position >= 0)
SellMarket();
}
_prevClose = candle.ClosePrice;
_prevSma = smaValue;
_hasPrev = 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 average_candle_cross_strategy(Strategy):
def __init__(self):
super(average_candle_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._period = self.Param("Period", 20) \
.SetDisplay("Period", "SMA period", "Indicators")
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def period(self):
return self._period.Value
@period.setter
def period(self, value):
self._period.Value = value
def OnReseted(self):
super(average_candle_cross_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(average_candle_cross_strategy, self).OnStarted2(time)
self._has_prev = False
sma = SimpleMovingAverage()
sma.Length = self.period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if self._has_prev:
if self._prev_close <= self._prev_sma and candle.ClosePrice > sma_value and self.Position <= 0:
self.BuyMarket()
elif self._prev_close >= self._prev_sma and candle.ClosePrice < sma_value and self.Position >= 0:
self.SellMarket()
self._prev_close = float(candle.ClosePrice)
self._prev_sma = float(sma_value)
self._has_prev = True
def CreateClone(self):
return average_candle_cross_strategy()