在 GitHub 上查看
SilverTrend ColorJFatl Digit MMRec 策略
概述
本策略是 MetaTrader 顾问 Exp_SilverTrend_ColorJFatl_Digit_MMRec 的 StockSharp 版本。它保留了原始系统的双模块设计:
- SilverTrend 模块:根据 SilverTrend 指标的蜡烛颜色,识别价格突破自适应通道的时刻。
- ColorJFatl 模块:利用官方系数表计算 FATL(Fast Adaptive Trend Line),并使用 EMA 平滑器模拟 MetaTrader 中的 Jurik 平滑效果。
两个模块分别维护各自的虚拟仓位,可独立开多或开空,也可以在出现反向信号时平掉对侧仓位,并应用独立的止损/止盈距离。策略的最终净头寸等于两个模块虚拟仓位的代数和。
默认设置
- 时间框架:默认情况下两个模块都订阅 6 小时蜡烛,可通过参数修改。
- 交易数量:每个模块都有独立的下单量参数(默认
1)。
- 交易品种:由用户在 StockSharp 中选择的证券。
指标与信号逻辑
SilverTrend 模块
- 使用最近
SSP 根蜡烛构建高低价通道。
- 通过
(33 - Risk) / 100 系数收缩通道边界(与原始 MQL 实现一致)。
- 将蜡烛按趋势着色:
0/1 表示多头,3/4 表示空头,2 表示中性。
- 触发条件:
- 做多:位于参数
Signal Bar 指定位置的蜡烛变为多头颜色,而更早一根蜡烛不是多头。
- 做空:同一位置的蜡烛变为空头颜色,而更早一根蜡烛不是空头。
- 止损和止盈以点数设置,并根据交易标的的
PriceStep 转换为价格距离。
ColorJFatl 模块
- 根据选择的
Applied Price 类型,通过 FATL 系数表计算基础序列。
- 使用长度为
JMA Length 的 EMA 平滑该序列,JMA Phase 参数保留用于描述和兼容性(在当前实现中不直接影响计算)。
- 根据平滑后的数值斜率设置颜色:上升为
2,下降为 0,持平时保持前一颜色。
- 触发条件:
- 做多:颜色从
0/1 切换到 2。
- 做空:颜色从
1/2 切换到 0。
- 可选择在开仓前自动平掉模块内的反向仓位。
风险管理
- 两个模块分别记录各自的入场价以及止损/止盈距离。
- 当任一模块触发止损或止盈时,仅关闭该模块的虚拟仓位,另一模块保持不变。
- 当两个模块同时看多或看空时,它们的下单量会叠加。
参数说明
| 分组 |
参数 |
说明 |
| SilverTrend |
Silver Candle Type |
SilverTrend 模块使用的蜡烛类型。 |
| SilverTrend |
SSP |
构建高低价范围的长度。 |
| SilverTrend |
Risk |
通道收缩系数。 |
| SilverTrend |
Signal Bar |
读取信号时使用的蜡烛偏移。 |
| SilverTrend |
Allow Silver Long/Short |
是否允许多/空方向的开仓。 |
| SilverTrend |
Close Silver Long/Short |
是否允许自动平掉反向仓位。 |
| SilverTrend |
Silver Volume |
SilverTrend 模块下单量。 |
| SilverTrend |
Silver SL/TP |
止损和止盈的点数距离。 |
| ColorJFatl |
Color Candle Type |
ColorJFatl 模块使用的蜡烛类型。 |
| ColorJFatl |
JMA Length |
FATL 平滑的长度。 |
| ColorJFatl |
JMA Phase |
保留的 Jurik 相位参数。 |
| ColorJFatl |
Applied Price |
FATL 计算所使用的价格类型。 |
| ColorJFatl |
Digits |
FATL 数值的保留小数位数。 |
| ColorJFatl |
Color Signal Bar |
读取 FATL 信号的蜡烛偏移。 |
| ColorJFatl |
Allow/Close |
多/空开仓及是否自动平仓的开关。 |
| ColorJFatl |
Color Volume |
ColorJFatl 模块下单量。 |
| ColorJFatl |
Color SL/TP |
模块的止损、止盈点数。 |
使用建议
- 确认证券的
PriceStep 已正确设置,否则点数止损/止盈无法换算为价格。
- 可以单独开启或关闭任一模块,逐步验证它们的表现,再组合使用。
- 模块可以在相反方向持仓,策略最终头寸为两个模块仓位的和,因此可能出现多空对冲的情况。
- 针对目标市场优化
SSP、Risk、JMA Length 以及价格类型,可显著改善信号质量。
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>
/// SilverTrend ColorJFatl Digit MMRec strategy (simplified). Uses Highest/Lowest
/// channel breakout with EMA slope for trend confirmation and martingale recovery.
/// </summary>
public class SilverTrendColorJfatlDigitMmrecStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _emaLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public SilverTrendColorJfatlDigitMmrecStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_channelLength = Param(nameof(ChannelLength), 21)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators");
_emaLength = Param(nameof(EmaLength), 14)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period for confirmation", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = ChannelLength };
var lowest = new Lowest { Length = ChannelLength };
var lastTrend = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, (ICandleMessage candle, decimal highVal, decimal lowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var range = highVal - lowVal;
if (range <= 0)
return;
var close = candle.ClosePrice;
var mid = (highVal + lowVal) / 2m;
// Channel breakout detection
if (close > highVal - range * 0.1m)
lastTrend = 1;
else if (close < lowVal + range * 0.1m)
lastTrend = -1;
// Confirm with position relative to midpoint
if (lastTrend > 0 && close > mid && Position <= 0)
BuyMarket();
else if (lastTrend < 0 && close < mid && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
}
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 silver_trend_color_jfatl_digit_mmrec_strategy(Strategy):
def __init__(self):
super(silver_trend_color_jfatl_digit_mmrec_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._channel_length = self.Param("ChannelLength", 21) \
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators")
self._last_trend = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def ChannelLength(self):
return self._channel_length.Value
def OnReseted(self):
super(silver_trend_color_jfatl_digit_mmrec_strategy, self).OnReseted()
self._last_trend = 0
def OnStarted2(self, time):
super(silver_trend_color_jfatl_digit_mmrec_strategy, self).OnStarted2(time)
self._last_trend = 0
highest = Highest()
highest.Length = self.ChannelLength
lowest = Lowest()
lowest.Length = self.ChannelLength
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.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
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)
rng = hv - lv
if rng <= 0:
return
close = float(candle.ClosePrice)
mid = (hv + lv) / 2.0
if close > hv - rng * 0.1:
self._last_trend = 1
elif close < lv + rng * 0.1:
self._last_trend = -1
if self._last_trend > 0 and close > mid and self.Position <= 0:
self.BuyMarket()
elif self._last_trend < 0 and close < mid and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return silver_trend_color_jfatl_digit_mmrec_strategy()