Ten Points 3 v005 Strategy
Overview
This strategy is a StockSharp port of the MetaTrader 4 expert advisor "10points 3 v005". It follows the MACD slope to decide whether the current averaging basket should be long or short and keeps opening martingale orders every time price moves against the active position by a configurable distance. The enhanced "v005" release adds equity based protection rules, day and time filters and the option to disable either the long or the short cycle.
Trading logic
- Read the direction from the MACD main line. When the indicator rises the next basket will be long, when it falls the basket will be short. An option allows reversing the interpretation.
- Open the first market position immediately once a direction exists. Subsequent entries are added whenever price moves
EntryDistancePips against the floating position.
- Order sizes grow geometrically. The multiplier is controlled by
MartingaleFactor (or HighTradeFactor when more than 12 trades are allowed). Volumes are aligned to the instrument volume step and capped at 100 lots.
- Every entry updates aggregated stop-loss and take-profit levels. Initial values are offset by
InitialStopPips and TakeProfitPips, while trailing logic activates after the position earns EntryDistancePips + TrailingStopPips in favor.
- If account protection is enabled the strategy can align the target with the best entry (
ReboundLock) and close the most recent order once floating profit reaches SecureProfit.
- Equity protection rules close the whole basket when the floating loss exceeds
StopLossAmount, when equity rises above ProfitTarget + ProfitBuffer, or when equity drops below StartProtectionLevel.
- Trading is limited to the
OpenHour/CloseHour window and is disabled completely on Fridays by default.
Money management
When UseMoneyManagement is disabled the first order uses the fixed LotSize. When the flag is enabled the base volume is calculated from the current portfolio value and the RiskPercent parameter. Mini-account scaling can be simulated through IsStandardAccount.
Parameters
| Parameter |
Description |
TakeProfitPips |
Distance (in pips) of the take-profit applied to each entry. |
LotSize |
Base lot size when money management is disabled. |
InitialStopPips |
Initial stop-loss distance for every order. |
TrailingStopPips |
Trailing stop distance once the trigger threshold is reached. |
MaxTrades |
Maximum number of simultaneous martingale entries. |
EntryDistancePips |
Minimum adverse move required to add the next order. |
SecureProfit |
Floating profit (in currency units) required to trigger the account-protection exit. |
UseAccountProtection |
Enables the secure-profit and rebound lock logic. |
OrdersToProtect |
Number of final martingale steps protected by the secure-profit rule. |
ReverseSignals |
Reverses the MACD slope interpretation. |
UseMoneyManagement |
Enables balance-based sizing. |
RiskPercent |
Risk percentage used by the money-management formula. |
IsStandardAccount |
Uses standard-lot scaling instead of mini scaling. |
EurUsdPipValue, GbpUsdPipValue, UsdChfPipValue, UsdJpyPipValue, DefaultPipValue |
Pip values used to translate floating profit into currency. |
CandleType |
Candle timeframe used for signal generation. |
MacdFastLength, MacdSlowLength, MacdSignalLength |
MACD configuration. |
EnableLong, EnableShort |
Enable or disable the long/short basket. |
OpenHour, CloseHour, MinuteToStop |
Trading window configuration. |
StopLossProtection, StopLossAmount |
Equity-based stop-loss guard. |
ProfitTargetEnabled, ProfitTarget, ProfitBuffer |
Equity-based profit lock. |
StartProtectionEnabled, StartProtectionLevel |
Equity floor guard. |
ReboundLock |
Aligns exits with the best entry when protection is active. |
MartingaleFactor, HighTradeFactor |
Martingale multipliers. |
CloseOnFriday |
Disables trading during Fridays. |
Notes
- The strategy uses the high-level StockSharp API (
SubscribeCandles + BindEx) and does not expose raw indicator buffers.
- Every equity guard closes the active basket using market orders to replicate the original EA behaviour.
- Always validate the parameter values, pip size and pip value against your broker specifications before using the strategy in production.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// 10 Points 3 V005: Dual EMA crossover with RSI confirmation and ATR stops.
/// </summary>
public class TenPoints3V005Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public TenPoints3V005Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 30)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fastEma, slowEma, rsi, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 1.5m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 1.5m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
}
_prevFast = fastVal; _prevSlow = slowVal;
}
}
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, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class ten_points_3_v005_strategy(Strategy):
"""Dual EMA crossover with RSI confirmation and ATR stops."""
def __init__(self):
super(ten_points_3_v005_strategy, self).__init__()
self._fast_ema = self.Param("FastEmaLength", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_ema = self.Param("SlowEmaLength", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetDisplay("RSI Length", "RSI period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(ten_points_3_v005_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
def OnStarted2(self, time):
super(ten_points_3_v005_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
fast = ExponentialMovingAverage()
fast.Length = self._fast_ema.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_ema.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, rsi, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0 or atr_val <= 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
if self.Position > 0:
if (fast_val < slow_val and self._prev_fast >= self._prev_slow) or close <= self._entry_price - atr_val * 1.5:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
if (fast_val > slow_val and self._prev_fast <= self._prev_slow) or close >= self._entry_price + atr_val * 1.5:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0:
if fast_val > slow_val and self._prev_fast <= self._prev_slow and rsi_val > 50:
self._entry_price = close
self.BuyMarket()
elif fast_val < slow_val and self._prev_fast >= self._prev_slow and rsi_val < 50:
self._entry_price = close
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return ten_points_3_v005_strategy()