Forex Profit Strategy
Translation of the "Forex Profit" MetaTrader expert advisor. The strategy waits for alignment of three exponential moving averages and confirmation from Parabolic SAR before entering trades on the close of each finished candle. Risk is controlled through asymmetric stop-loss and take-profit distances, a trailing stop and an additional EMA-based profit lock.
Details
- Entry Criteria:
- Long:
EMA10above bothEMA25andEMA50, previous bar'sEMA10at or belowEMA50, and Parabolic SAR below the prior close. - Short:
EMA10below bothEMA25andEMA50, previous bar'sEMA10at or aboveEMA50, and Parabolic SAR above the prior close. - Signals are evaluated only once per completed candle.
- Long:
- Exit Criteria:
- Close long when
EMA10turns below its previous value and current profit exceeds theProfitThreshold. - Close short when
EMA10turns above its previous value and current profit exceeds theProfitThreshold. - Protective stop-loss and take-profit levels set at order entry (different distances for longs vs shorts).
- Trailing stop activates after price moves
TrailingStopPointsbeyond the entry and is updated byTrailingStepPointsincrements.
- Close long when
- Stops: Yes — fixed stop-loss, fixed take-profit, and trailing stop management.
- Default Values:
FastEmaLength= 10MediumEmaLength= 25SlowEmaLength= 50TakeProfitBuyPoints= 55TakeProfitSellPoints= 65StopLossBuyPoints= 60StopLossSellPoints= 85TrailingStopPoints= 74TrailingStepPoints= 5ProfitThreshold= 10SarAcceleration= 0.02SarMaxAcceleration= 0.2Volume= 1CandleType= 1 hour timeframe
- Additional Notes:
- Stop/target distances are expressed in instrument price steps and converted automatically using the security's tick size.
- Profit-based exits rely on the total position profit (including volume) converted from price ticks to account currency.
- Trailing logic keeps the stop behind price swings without overshooting the configured step.
- Filters:
- Category: Trend following
- Direction: Long & Short
- Indicators: EMA, Parabolic SAR
- Stops: Yes (fixed + trailing)
- Complexity: Intermediate
- Timeframe: Configurable (default 1 hour)
- Seasonality: No
- Neural networks: No
- Divergence: No
- Risk level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend-following strategy translated from the "Forex Profit" MQL expert.
/// Combines EMA alignment with Parabolic SAR confirmation and dynamic exits.
/// </summary>
public class ForexProfitStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _mediumEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<decimal> _takeProfitBuyPoints;
private readonly StrategyParam<decimal> _takeProfitSellPoints;
private readonly StrategyParam<decimal> _stopLossBuyPoints;
private readonly StrategyParam<decimal> _stopLossSellPoints;
private readonly StrategyParam<decimal> _trailingStopPoints;
private readonly StrategyParam<decimal> _trailingStepPoints;
private readonly StrategyParam<decimal> _profitThreshold;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _sarAcceleration;
private readonly StrategyParam<decimal> _sarMaxAcceleration;
private ExponentialMovingAverage _emaFast;
private ExponentialMovingAverage _emaMedium;
private ExponentialMovingAverage _emaSlow;
private ParabolicSar _sar;
private decimal? _ema10Prev;
private decimal? _ema10PrevPrev;
private decimal? _entryPrice;
private decimal? _stopPrice;
private decimal? _takeProfitPrice;
/// <summary>
/// Fast EMA length.
/// </summary>
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
/// <summary>
/// Medium EMA length.
/// </summary>
public int MediumEmaLength
{
get => _mediumEmaLength.Value;
set => _mediumEmaLength.Value = value;
}
/// <summary>
/// Slow EMA length.
/// </summary>
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
/// <summary>
/// Take profit distance for long positions in price steps.
/// </summary>
public decimal TakeProfitBuyPoints
{
get => _takeProfitBuyPoints.Value;
set => _takeProfitBuyPoints.Value = value;
}
/// <summary>
/// Take profit distance for short positions in price steps.
/// </summary>
public decimal TakeProfitSellPoints
{
get => _takeProfitSellPoints.Value;
set => _takeProfitSellPoints.Value = value;
}
/// <summary>
/// Stop loss distance for long positions in price steps.
/// </summary>
public decimal StopLossBuyPoints
{
get => _stopLossBuyPoints.Value;
set => _stopLossBuyPoints.Value = value;
}
/// <summary>
/// Stop loss distance for short positions in price steps.
/// </summary>
public decimal StopLossSellPoints
{
get => _stopLossSellPoints.Value;
set => _stopLossSellPoints.Value = value;
}
/// <summary>
/// Trailing stop distance in price steps.
/// </summary>
public decimal TrailingStopPoints
{
get => _trailingStopPoints.Value;
set => _trailingStopPoints.Value = value;
}
/// <summary>
/// Minimum step for trailing stop updates in price steps.
/// </summary>
public decimal TrailingStepPoints
{
get => _trailingStepPoints.Value;
set => _trailingStepPoints.Value = value;
}
/// <summary>
/// Minimal profit in account currency required to exit on EMA reversal.
/// </summary>
public decimal ProfitThreshold
{
get => _profitThreshold.Value;
set => _profitThreshold.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initial Parabolic SAR acceleration.
/// </summary>
public decimal SarAcceleration
{
get => _sarAcceleration.Value;
set => _sarAcceleration.Value = value;
}
/// <summary>
/// Maximum Parabolic SAR acceleration.
/// </summary>
public decimal SarMaxAcceleration
{
get => _sarMaxAcceleration.Value;
set => _sarMaxAcceleration.Value = value;
}
/// <summary>
/// Initializes <see cref="ForexProfitStrategy"/>.
/// </summary>
public ForexProfitStrategy()
{
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA Length", "Length of the fast EMA", "Averages")
;
_mediumEmaLength = Param(nameof(MediumEmaLength), 25)
.SetGreaterThanZero()
.SetDisplay("Medium EMA Length", "Length of the medium EMA", "Averages")
;
_slowEmaLength = Param(nameof(SlowEmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("Slow EMA Length", "Length of the slow EMA", "Averages")
;
_takeProfitBuyPoints = Param(nameof(TakeProfitBuyPoints), 55m)
.SetGreaterThanZero()
.SetDisplay("Take Profit Long", "Take profit distance for buys (points)", "Risk")
;
_takeProfitSellPoints = Param(nameof(TakeProfitSellPoints), 65m)
.SetGreaterThanZero()
.SetDisplay("Take Profit Short", "Take profit distance for sells (points)", "Risk")
;
_stopLossBuyPoints = Param(nameof(StopLossBuyPoints), 60m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss Long", "Stop loss distance for buys (points)", "Risk")
;
_stopLossSellPoints = Param(nameof(StopLossSellPoints), 85m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss Short", "Stop loss distance for sells (points)", "Risk")
;
_trailingStopPoints = Param(nameof(TrailingStopPoints), 74m)
.SetNotNegative()
.SetDisplay("Trailing Stop", "Trailing stop distance (points)", "Risk")
;
_trailingStepPoints = Param(nameof(TrailingStepPoints), 5m)
.SetNotNegative()
.SetDisplay("Trailing Step", "Minimal trailing step (points)", "Risk")
;
_profitThreshold = Param(nameof(ProfitThreshold), 10m)
.SetNotNegative()
.SetDisplay("Profit Threshold", "Profit required for EMA exit", "Risk")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
_sarAcceleration = Param(nameof(SarAcceleration), 0.02m)
.SetGreaterThanZero()
.SetDisplay("SAR Start", "Initial SAR acceleration", "Indicators")
;
_sarMaxAcceleration = Param(nameof(SarMaxAcceleration), 0.2m)
.SetGreaterThanZero()
.SetDisplay("SAR Max", "Maximum SAR acceleration", "Indicators")
;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema10Prev = null;
_ema10PrevPrev = null;
_entryPrice = null;
_stopPrice = null;
_takeProfitPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_emaFast = new EMA { Length = FastEmaLength };
_emaMedium = new EMA { Length = MediumEmaLength };
_emaSlow = new EMA { Length = SlowEmaLength };
_sar = new ParabolicSar
{
Acceleration = SarAcceleration,
AccelerationMax = SarMaxAcceleration
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _emaFast);
DrawIndicator(area, _emaMedium);
DrawIndicator(area, _emaSlow);
DrawIndicator(area, _sar);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var ema10Prev = _ema10Prev;
var ema10PrevPrev = _ema10PrevPrev;
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var isFinal = candle.State == CandleStates.Finished;
var ema10Value = _emaFast.Process(new DecimalIndicatorValue(_emaFast, median, candle.OpenTime) { IsFinal = isFinal }).ToDecimal();
var ema25Value = _emaMedium.Process(new DecimalIndicatorValue(_emaMedium, median, candle.OpenTime) { IsFinal = isFinal }).ToDecimal();
var ema50Value = _emaSlow.Process(new DecimalIndicatorValue(_emaSlow, median, candle.OpenTime) { IsFinal = isFinal }).ToDecimal();
var sarResult = _sar.Process(candle);
if (!_emaSlow.IsFormed || !_sar.IsFormed)
{
_ema10PrevPrev = ema10Prev;
_ema10Prev = ema10Value;
return;
}
var sarValue = sarResult.ToDecimal();
var step = Security?.PriceStep ?? 1m;
if (step <= 0m)
step = 1m;
var stepPrice = step;
var longSignal = ema10Value > ema25Value &&
ema10Value > ema50Value &&
ema10PrevPrev.HasValue &&
ema10PrevPrev.Value <= ema50Value &&
sarValue < candle.ClosePrice;
var shortSignal = ema10Value < ema25Value &&
ema10Value < ema50Value &&
ema10PrevPrev.HasValue &&
ema10PrevPrev.Value >= ema50Value &&
sarValue > candle.ClosePrice;
if (Position == 0m && IsFormedAndOnlineAndAllowTrading())
{
if (longSignal)
{
TryEnterLong(candle, step);
}
else if (shortSignal)
{
TryEnterShort(candle, step);
}
}
else if (Position > 0m)
{
ManageLongPosition(candle, ema10Value, ema10Prev, step, stepPrice);
}
else if (Position < 0m)
{
ManageShortPosition(candle, ema10Value, ema10Prev, step, stepPrice);
}
_ema10PrevPrev = ema10Prev;
_ema10Prev = ema10Value;
}
private void TryEnterLong(ICandleMessage candle, decimal step)
{
if (Volume <= 0m)
return;
BuyMarket(Volume);
var entry = candle.ClosePrice;
_entryPrice = entry;
_stopPrice = entry - step * StopLossBuyPoints;
_takeProfitPrice = entry + step * TakeProfitBuyPoints;
}
private void TryEnterShort(ICandleMessage candle, decimal step)
{
if (Volume <= 0m)
return;
SellMarket(Volume);
var entry = candle.ClosePrice;
_entryPrice = entry;
_stopPrice = entry + step * StopLossSellPoints;
_takeProfitPrice = entry - step * TakeProfitSellPoints;
}
private void ManageLongPosition(ICandleMessage candle, decimal ema10Value, decimal? ema10Prev, decimal step, decimal stepPrice)
{
if (_entryPrice == null)
return;
var profit = ComputeProfit(candle.ClosePrice, step, stepPrice);
if (ema10Prev.HasValue && ema10Value < ema10Prev.Value && profit > ProfitThreshold)
{
SellMarket(Math.Abs(Position));
ResetPositionTargets();
return;
}
if (_takeProfitPrice.HasValue && candle.HighPrice >= _takeProfitPrice.Value)
{
SellMarket(Math.Abs(Position));
ResetPositionTargets();
return;
}
if (_stopPrice.HasValue && candle.LowPrice <= _stopPrice.Value)
{
SellMarket(Math.Abs(Position));
ResetPositionTargets();
return;
}
UpdateLongTrailing(candle, step);
}
private void ManageShortPosition(ICandleMessage candle, decimal ema10Value, decimal? ema10Prev, decimal step, decimal stepPrice)
{
if (_entryPrice == null)
return;
var profit = ComputeProfit(candle.ClosePrice, step, stepPrice);
if (ema10Prev.HasValue && ema10Value > ema10Prev.Value && profit > ProfitThreshold)
{
BuyMarket(Math.Abs(Position));
ResetPositionTargets();
return;
}
if (_takeProfitPrice.HasValue && candle.LowPrice <= _takeProfitPrice.Value)
{
BuyMarket(Math.Abs(Position));
ResetPositionTargets();
return;
}
if (_stopPrice.HasValue && candle.HighPrice >= _stopPrice.Value)
{
BuyMarket(Math.Abs(Position));
ResetPositionTargets();
return;
}
UpdateShortTrailing(candle, step);
}
private void UpdateLongTrailing(ICandleMessage candle, decimal step)
{
if (TrailingStopPoints <= 0m || _entryPrice == null)
return;
var trailingDistance = step * TrailingStopPoints;
var trailingStep = step * TrailingStepPoints;
var movement = candle.ClosePrice - _entryPrice.Value;
if (movement > trailingDistance)
{
var newStop = candle.ClosePrice - trailingDistance;
if (!_stopPrice.HasValue || newStop - _stopPrice.Value >= trailingStep)
_stopPrice = newStop;
}
}
private void UpdateShortTrailing(ICandleMessage candle, decimal step)
{
if (TrailingStopPoints <= 0m || _entryPrice == null)
return;
var trailingDistance = step * TrailingStopPoints;
var trailingStep = step * TrailingStepPoints;
var movement = _entryPrice.Value - candle.ClosePrice;
if (movement > trailingDistance)
{
var newStop = candle.ClosePrice + trailingDistance;
if (!_stopPrice.HasValue || _stopPrice.Value - newStop >= trailingStep)
_stopPrice = newStop;
}
}
private decimal ComputeProfit(decimal currentPrice, decimal step, decimal stepPrice)
{
if (_entryPrice == null || Position == 0m)
return 0m;
var ticks = (currentPrice - _entryPrice.Value) / step;
return ticks * stepPrice * Position;
}
private void ResetPositionTargets()
{
_entryPrice = null;
_stopPrice = null;
_takeProfitPrice = null;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, ParabolicSar, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class forex_profit_strategy(Strategy):
def __init__(self):
super(forex_profit_strategy, self).__init__()
self._fast_ema_length = self.Param("FastEmaLength", 10)
self._medium_ema_length = self.Param("MediumEmaLength", 25)
self._slow_ema_length = self.Param("SlowEmaLength", 50)
self._take_profit_buy_points = self.Param("TakeProfitBuyPoints", 55.0)
self._take_profit_sell_points = self.Param("TakeProfitSellPoints", 65.0)
self._stop_loss_buy_points = self.Param("StopLossBuyPoints", 60.0)
self._stop_loss_sell_points = self.Param("StopLossSellPoints", 85.0)
self._trailing_stop_points = self.Param("TrailingStopPoints", 74.0)
self._trailing_step_points = self.Param("TrailingStepPoints", 5.0)
self._profit_threshold = self.Param("ProfitThreshold", 10.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._sar_acceleration = self.Param("SarAcceleration", 0.02)
self._sar_max_acceleration = self.Param("SarMaxAcceleration", 0.2)
self._ema_fast = None
self._ema_medium = None
self._ema_slow = None
self._sar = None
self._ema10_prev = None
self._ema10_prev_prev = None
self._entry_price = None
self._stop_price = None
self._take_profit_price = None
@property
def FastEmaLength(self):
return self._fast_ema_length.Value
@FastEmaLength.setter
def FastEmaLength(self, value):
self._fast_ema_length.Value = value
@property
def MediumEmaLength(self):
return self._medium_ema_length.Value
@MediumEmaLength.setter
def MediumEmaLength(self, value):
self._medium_ema_length.Value = value
@property
def SlowEmaLength(self):
return self._slow_ema_length.Value
@SlowEmaLength.setter
def SlowEmaLength(self, value):
self._slow_ema_length.Value = value
@property
def TakeProfitBuyPoints(self):
return self._take_profit_buy_points.Value
@TakeProfitBuyPoints.setter
def TakeProfitBuyPoints(self, value):
self._take_profit_buy_points.Value = value
@property
def TakeProfitSellPoints(self):
return self._take_profit_sell_points.Value
@TakeProfitSellPoints.setter
def TakeProfitSellPoints(self, value):
self._take_profit_sell_points.Value = value
@property
def StopLossBuyPoints(self):
return self._stop_loss_buy_points.Value
@StopLossBuyPoints.setter
def StopLossBuyPoints(self, value):
self._stop_loss_buy_points.Value = value
@property
def StopLossSellPoints(self):
return self._stop_loss_sell_points.Value
@StopLossSellPoints.setter
def StopLossSellPoints(self, value):
self._stop_loss_sell_points.Value = value
@property
def TrailingStopPoints(self):
return self._trailing_stop_points.Value
@TrailingStopPoints.setter
def TrailingStopPoints(self, value):
self._trailing_stop_points.Value = value
@property
def TrailingStepPoints(self):
return self._trailing_step_points.Value
@TrailingStepPoints.setter
def TrailingStepPoints(self, value):
self._trailing_step_points.Value = value
@property
def ProfitThreshold(self):
return self._profit_threshold.Value
@ProfitThreshold.setter
def ProfitThreshold(self, value):
self._profit_threshold.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def SarAcceleration(self):
return self._sar_acceleration.Value
@SarAcceleration.setter
def SarAcceleration(self, value):
self._sar_acceleration.Value = value
@property
def SarMaxAcceleration(self):
return self._sar_max_acceleration.Value
@SarMaxAcceleration.setter
def SarMaxAcceleration(self, value):
self._sar_max_acceleration.Value = value
def OnStarted2(self, time):
super(forex_profit_strategy, self).OnStarted2(time)
self._ema10_prev = None
self._ema10_prev_prev = None
self._entry_price = None
self._stop_price = None
self._take_profit_price = None
self._ema_fast = ExponentialMovingAverage()
self._ema_fast.Length = self.FastEmaLength
self._ema_medium = ExponentialMovingAverage()
self._ema_medium.Length = self.MediumEmaLength
self._ema_slow = ExponentialMovingAverage()
self._ema_slow.Length = self.SlowEmaLength
self._sar = ParabolicSar()
self._sar.Acceleration = self.SarAcceleration
self._sar.AccelerationMax = self.SarMaxAcceleration
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
median = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
ema10_result = process_float(self._ema_fast, Decimal(median), candle.CloseTime, True)
ema25_result = process_float(self._ema_medium, Decimal(median), candle.CloseTime, True)
ema50_result = process_float(self._ema_slow, Decimal(median), candle.CloseTime, True)
sar_result = self._sar.Process(CandleIndicatorValue(self._sar, candle))
ema10_value = float(ema10_result)
ema25_value = float(ema25_result)
ema50_value = float(ema50_result)
sar_value = float(sar_result)
ema10_prev = self._ema10_prev
ema10_prev_prev = self._ema10_prev_prev
if not self._ema_slow.IsFormed or not self._sar.IsFormed:
self._ema10_prev_prev = ema10_prev
self._ema10_prev = ema10_value
return
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if step <= 0.0:
step = 1.0
long_signal = (ema10_value > ema25_value and
ema10_value > ema50_value and
ema10_prev_prev is not None and
ema10_prev_prev <= ema50_value and
sar_value < close)
short_signal = (ema10_value < ema25_value and
ema10_value < ema50_value and
ema10_prev_prev is not None and
ema10_prev_prev >= ema50_value and
sar_value > close)
if self.Position == 0:
if long_signal:
self.BuyMarket()
self._entry_price = close
self._stop_price = close - step * float(self.StopLossBuyPoints)
self._take_profit_price = close + step * float(self.TakeProfitBuyPoints)
elif short_signal:
self.SellMarket()
self._entry_price = close
self._stop_price = close + step * float(self.StopLossSellPoints)
self._take_profit_price = close - step * float(self.TakeProfitSellPoints)
elif self.Position > 0:
self._manage_long(candle, ema10_value, ema10_prev, step)
elif self.Position < 0:
self._manage_short(candle, ema10_value, ema10_prev, step)
self._ema10_prev_prev = ema10_prev
self._ema10_prev = ema10_value
def _manage_long(self, candle, ema10_value, ema10_prev, step):
if self._entry_price is None:
return
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
profit = self._compute_profit(close, step)
if ema10_prev is not None and ema10_value < ema10_prev and profit > float(self.ProfitThreshold):
self.SellMarket()
self._reset_position_targets()
return
if self._take_profit_price is not None and high >= self._take_profit_price:
self.SellMarket()
self._reset_position_targets()
return
if self._stop_price is not None and low <= self._stop_price:
self.SellMarket()
self._reset_position_targets()
return
self._update_long_trailing(candle, step)
def _manage_short(self, candle, ema10_value, ema10_prev, step):
if self._entry_price is None:
return
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
profit = self._compute_profit(close, step)
if ema10_prev is not None and ema10_value > ema10_prev and profit > float(self.ProfitThreshold):
self.BuyMarket()
self._reset_position_targets()
return
if self._take_profit_price is not None and low <= self._take_profit_price:
self.BuyMarket()
self._reset_position_targets()
return
if self._stop_price is not None and high >= self._stop_price:
self.BuyMarket()
self._reset_position_targets()
return
self._update_short_trailing(candle, step)
def _update_long_trailing(self, candle, step):
trail_pts = float(self.TrailingStopPoints)
if trail_pts <= 0.0 or self._entry_price is None:
return
close = float(candle.ClosePrice)
trailing_distance = step * trail_pts
trailing_step = step * float(self.TrailingStepPoints)
movement = close - self._entry_price
if movement > trailing_distance:
new_stop = close - trailing_distance
if self._stop_price is None or new_stop - self._stop_price >= trailing_step:
self._stop_price = new_stop
def _update_short_trailing(self, candle, step):
trail_pts = float(self.TrailingStopPoints)
if trail_pts <= 0.0 or self._entry_price is None:
return
close = float(candle.ClosePrice)
trailing_distance = step * trail_pts
trailing_step = step * float(self.TrailingStepPoints)
movement = self._entry_price - close
if movement > trailing_distance:
new_stop = close + trailing_distance
if self._stop_price is None or self._stop_price - new_stop >= trailing_step:
self._stop_price = new_stop
def _compute_profit(self, current_price, step):
if self._entry_price is None or self.Position == 0:
return 0.0
ticks = (current_price - self._entry_price) / step
return ticks * step * self.Position
def _reset_position_targets(self):
self._entry_price = None
self._stop_price = None
self._take_profit_price = None
def OnReseted(self):
super(forex_profit_strategy, self).OnReseted()
self._ema_fast = None
self._ema_medium = None
self._ema_slow = None
self._sar = None
self._ema10_prev = None
self._ema10_prev_prev = None
self._entry_price = None
self._stop_price = None
self._take_profit_price = None
def CreateClone(self):
return forex_profit_strategy()