首页
/
策略示例
在 GitHub 上查看
Smart Forex System 策略
概述
Smart Forex System 策略是 MetaTrader 智能交易系统在 StockSharp 平台上的移植版本。策略结合了上一根 K 线的动量过滤器与带有加仓倍数的网格加仓机制。当上一根 K 线出现显著的趋势收盘且当前价格相对于参考收盘价偏离足够多时,会启动第一笔交易。价格逆向移动时,会按照固定的点差间距继续加仓,并使用可配置的倍数放大手数。平仓逻辑通过网格平均价格设置的分级止盈,以及跟随最近一次加仓价格的止损来控制风险。
交易逻辑
信号判定
仅使用选定周期内最新完成的 K 线。
计算动量值 (当前收盘价 − 上一收盘价) / 上一收盘价 * 10,000。
若上一根 K 线为阴线且动量低于负阈值,则允许开启多头网格。
若上一根 K 线为阳线且动量高于正阈值,则允许开启空头网格。
通过 Trading Mode 参数可以限制仅做多、仅做空、双向或完全关闭交易。
网格加仓
当存在未平仓网格时,如果价格相对于最后一次进场价逆向运行至少 Grid Step 点,则触发下一笔加仓。
每次加仓的手数按 Lot Multiplier 放大,同时受到证券最小/最大手数以及 Max Volume 的限制。
网格中的订单数量达到 Max Trades 时停止继续加仓。
退出机制
从最近一次进场价起,设置距离为 Stop Loss 点的强制止损,突破该水平时立即清空整个网格。
依据网格规模设置不同的止盈目标:
单一持仓使用 First Take Profit 点的目标。
多笔持仓使用 Grid Take Profit 点的目标,以提高获利概率。
所有判断在 K 线收盘时进行,确保数据最终确认。
风险提示
加倍网格会在趋势行情中迅速放大头寸,请谨慎设置加仓倍数与最大订单数,尤其是在波动性较大的品种上。
默认 400 点的止损源自原始 EA,幅度较大,如需更紧的风险控制,可结合 ATR 等指标重新调整。
网格交易对保证金要求较高,务必确认账户杠杆、合约大小与 Start Volume 的组合在经纪商处可行。
参数一览
参数
说明
默认值
Trading Mode
允许的交易方向(仅多、仅空、双向、关闭)。
Long & Short
Momentum Threshold
触发信号所需的最小动量(伪点)。
1
Start Volume
新网格第一笔订单的手数。
0.01
Max Volume
单笔订单的最大手数。
2
Lot Multiplier
后续加仓的手数倍数。
1.5
Grid Step
连续加仓之间的最小点差。
26
Max Trades
单方向允许的最大订单数量。
12
First Take Profit
仅有一笔持仓时的止盈距离。
30
Grid Take Profit
多笔持仓时的止盈距离。
7
Stop Loss
最近一笔订单的止损距离。
400
Candle Type
用于计算信号的 K 线周期。
1 小时 K 线
使用建议
建议选择流动性充足、点差稳定的外汇品种运行策略。
Candle Type 默认设置为 1 小时,可根据交易风格调整为其他周期。
在真实环境运行前,请先在历史数据上优化网格间距、加仓倍数和动量阈值。
时刻关注保证金占用,必要时配合账户级别的资金保护机制。
避免在同一品种上同时运行多套网格策略,以减少风险叠加。
本移植版本使用收盘 K 线进行决策,减少噪音并提高回测与实盘之间的一致性。
下单手数会自动适配 StockSharp 证券对象的最小值、最大值和步长要求,兼容更多经纪商。
止盈与止损逻辑在策略内部统一处理,无需对每笔订单频繁修改参数。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Smart Forex System strategy: Triple EMA alignment.
/// Enters when fast > mid > slow (buy) or fast < mid < slow (sell).
/// </summary>
public class SmartForexSystemStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _midPeriod;
private readonly StrategyParam<int> _slowPeriod;
private bool _wasBullishAlignment;
private bool _hasPrevAlignment;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int MidPeriod { get => _midPeriod.Value; set => _midPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public SmartForexSystemStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_midPeriod = Param(nameof(MidPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Mid EMA", "Mid EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasBullishAlignment = false;
_hasPrevAlignment = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_wasBullishAlignment = false;
_hasPrevAlignment = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var mid = new ExponentialMovingAverage { Length = MidPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, mid, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal midValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
var bullishAlignment = fastValue > midValue && midValue > slowValue;
var bearishAlignment = fastValue < midValue && midValue < slowValue;
var crossedUp = bullishAlignment && (!_hasPrevAlignment || !_wasBullishAlignment);
var crossedDown = bearishAlignment && (!_hasPrevAlignment || _wasBullishAlignment);
if (crossedUp && Position <= 0)
BuyMarket();
else if (crossedDown && Position >= 0)
SellMarket();
if (bullishAlignment || bearishAlignment)
{
_wasBullishAlignment = bullishAlignment;
_hasPrevAlignment = 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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class smart_forex_system_strategy(Strategy):
def __init__(self):
super(smart_forex_system_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_period = self.Param("FastPeriod", 10)
self._mid_period = self.Param("MidPeriod", 25)
self._slow_period = self.Param("SlowPeriod", 50)
self._was_bullish_alignment = False
self._has_prev_alignment = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def MidPeriod(self):
return self._mid_period.Value
@MidPeriod.setter
def MidPeriod(self, value):
self._mid_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
def OnReseted(self):
super(smart_forex_system_strategy, self).OnReseted()
self._was_bullish_alignment = False
self._has_prev_alignment = False
def OnStarted2(self, time):
super(smart_forex_system_strategy, self).OnStarted2(time)
self._was_bullish_alignment = False
self._has_prev_alignment = False
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
mid = ExponentialMovingAverage()
mid.Length = self.MidPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, mid, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_value, mid_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
mid_val = float(mid_value)
slow_val = float(slow_value)
bullish_alignment = fast_val > mid_val and mid_val > slow_val
bearish_alignment = fast_val < mid_val and mid_val < slow_val
crossed_up = bullish_alignment and (not self._has_prev_alignment or not self._was_bullish_alignment)
crossed_down = bearish_alignment and (not self._has_prev_alignment or self._was_bullish_alignment)
if crossed_up and self.Position <= 0:
self.BuyMarket()
elif crossed_down and self.Position >= 0:
self.SellMarket()
if bullish_alignment or bearish_alignment:
self._was_bullish_alignment = bullish_alignment
self._has_prev_alignment = True
def CreateClone(self):
return smart_forex_system_strategy()