首页
/
策略示例
在 GitHub 上查看
N Trades Per Set Martingale 策略
概述
本策略完整复刻了 MetaTrader 智能交易系统 “N trades per set martingale + Close and reset on equity increase”。策略仅做多,但通过马丁加仓和基于权益的重置机制实现动态仓位管理。每次上一笔交易平仓后都会立即开立新的多单,因此始终保持在场内。
交易逻辑
顺序进场 :只要当前没有持仓,就立刻以市价买入,并在成交后挂出止损与止盈。
胜负统计 :持仓关闭后,将出场价与入场价比较。若为盈利则增加胜场计数,否则计入败场;打平被视为亏损,与原版 EA 完全一致。
结束一轮 :同时跟踪本轮的交易数量。当计数达到 Trades Per Set 时,本轮结束,根据结果分为三种情况:
全部盈利 :使用当前权益除以 Equity Divisor 重新计算基础手数,然后清零各个计数器。
全部亏损 :将手数乘以 Scale Factor,随后清零计数器。
混合结果 :若胜负都有,则保持当前手数,仅清零计数器。
权益重置 :当账户权益累计增长达到 Equity Increase 时触发全局重置:清零计数器,按照最新权益重新计算手数,并把权益目标向前平移同样的增量。
该流程与原始 EA 中 fxDreema 模块的连线完全一致。
参数说明
参数
说明
Trades Per Set
构成一轮马丁循环的交易数量。
Stop Loss (pips)
以价格跳动为单位的止损距离,填 0 表示关闭止损。
Take Profit (pips)
以价格跳动为单位的止盈距离,填 0 表示关闭止盈。
Scale Factor
全部亏损后用于放大下次交易手数的倍数,低于 1 的值会被限制为 1。
Equity Divisor
在盈利轮次或权益重置后,用于由权益计算基础手数的除数。
Equity Increase
触发全局重置所需的权益增量,填 0 则禁用权益重置。
资金管理
手数会按照品种约束 (VolumeStep、MinVolume、MaxVolume) 调整,与 MQL 中的 AlignLots 行为一致。
当无法获得权益数据时,沿用上一笔的手数;如果是首笔交易,则退回到交易品种的最小步长。
止损与止盈通过 PriceStep 转换成价格跳动数。如果品种未提供价格步长,则直接将输入值四舍五入到最近的整数。
使用提示
策略只做多,与原版保持一致。若交易渠道允许做空,需要手动禁用空头交易。
由于每次成交后都会重新设置保护单,部分成交能够自动继承相同的止损和止盈。
权益重置在每次平仓后检查,请确保投资组合连接能提供实时权益,否则条件将无法触发。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// N Trades Per Set Martingale: RSI-based entry with position tracking.
/// Buys when RSI oversold, sells when RSI overbought.
/// </summary>
public class NTradesPerSetMartingaleStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public NTradesPerSetMartingaleStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
decimal? prevRsi = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, (candle, rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevRsi.HasValue)
{
var crossBelowOversold = prevRsi.Value >= 30m && rsiVal < 30m;
var crossAboveOverbought = prevRsi.Value <= 70m && rsiVal > 70m;
if (crossBelowOversold && Position <= 0)
BuyMarket();
else if (crossAboveOverbought && Position >= 0)
SellMarket();
}
prevRsi = rsiVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class n_trades_per_set_martingale_strategy(Strategy):
def __init__(self):
super(n_trades_per_set_martingale_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._rsi = None
@property
def rsi_period(self):
return self._rsi_period.Value
def OnReseted(self):
super(n_trades_per_set_martingale_strategy, self).OnReseted()
self._rsi = None
def OnStarted2(self, time):
super(n_trades_per_set_martingale_strategy, self).OnStarted2(time)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._rsi.IsFormed:
return
rsi = float(rsi_value)
if rsi < 30.0 and self.Position <= 0:
self.BuyMarket()
elif rsi > 70.0 and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return n_trades_per_set_martingale_strategy()