在 GitHub 上查看
MA包络线策略
策略由MetaTrader 5专家顾问“MA Envelopes”移植而来。它利用均线与包络线构建的通道寻找价格回踩机会。当完成的K线收盘价位于均线与包络上/下轨之间,并且处于设定的交易时间窗口内时,策略会在均线位置挂出限价单,同时设置基于包络线的止损和止盈。
交易逻辑
- 根据选择的均线类型、价格源和周期计算移动平均值,并利用偏差参数构建对称的包络线。
- 若完成K线收盘价高于均线且低于上轨,且当前卖价仍高于均线,则按阶梯方式在均线处挂出买入限价单。
- 每个买单的止损设置在下轨,止盈设置在上轨基础上再加对应的点数偏移。
- 最多管理三张独立的订单,对应
First、Second、Third 三组止盈偏移参数。
- 若完成K线收盘价低于均线且高于下轨,且当前买价仍低于均线,则镜像执行卖出限价逻辑。
StartHour 与 EndHour 控制交易时间。超过结束时间仍未成交的挂单会被取消。
MaximumRisk 控制单笔风险占权益的比例,DecreaseFactor 在连续亏损后按比例减少下次下单手数。下单数量会按照品种的成交量步长和最小/最大限制自动调整。
- 当挂单完全成交后,立即注册止损和止盈委托;若其中一张触发,另一张会被取消。如仅部分仓位被平掉,则为剩余仓位重新下达防护订单。
参数说明
| 参数 |
说明 |
MaximumRisk |
单笔交易所冒风险占可用权益的比例。 |
DecreaseFactor |
连续亏损时用于缩减下次下单手数的系数。 |
First/Second/ThirdStopTakeProfitPips |
三组阶梯订单在包络线基础上的附加点数。 |
StartHour, EndHour |
交易窗口的起止小时(终端时间,0–23)。 |
MaPeriod, MaShift, MaMethodType, AppliedPrice |
均线配置。 |
EnvelopeDeviation |
包络线宽度,单位为百分比。 |
CandleType |
策略处理的K线周期。 |
其他说明
- 当仓位仅部分被止损或止盈时,策略会重新为剩余仓位生成新的防护订单。
- 仅在交易窗口结束时取消未成交的挂单,已有仓位继续由止损止盈保护。
- 策略优先使用盘口数据获取最新买卖价;若无盘口则回退到K线收盘价。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class MaEnvelopesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevHigh, _prevLow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public MaEnvelopesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 15).SetGreaterThanZero().SetDisplay("Channel Period", "Channel lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null; _prevLow = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevHigh = high; _prevLow = low; return; }
if (_prevHigh == null || _prevLow == null) { _prevHigh = high; _prevLow = low; return; }
if (candle.ClosePrice > _prevHigh.Value && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (candle.ClosePrice < _prevLow.Value && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevHigh = high; _prevLow = low;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class ma_envelopes_strategy(Strategy):
def __init__(self):
super(ma_envelopes_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 15) \
.SetDisplay("Channel Period", "Channel lookback", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(ma_envelopes_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(ma_envelopes_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return ma_envelopes_strategy()