Forex Profit 策略
来自 MetaTrader 的 “Forex Profit” 专家顾问的移植版本。策略在每根完成的K线上检查三条指数移动平均线是否排列,并用 Parabolic SAR 做趋势确认,然后按收盘价入场。风险控制包括不对称的止损/止盈距离、跟踪止损以及基于 EMA 反转的利润锁定。
细节
- 入场条件:
- 多头:
EMA10同时高于EMA25和EMA50,上一根K线的EMA10不高于EMA50,且 Parabolic SAR 位于上一收盘价之下。 - 空头:
EMA10同时低于EMA25和EMA50,上一根K线的EMA10不低于EMA50,且 Parabolic SAR 位于上一收盘价之上。 - 每根完结K线只评估一次信号。
- 多头:
- 出场条件:
- 当
EMA10跌破其前值且当前利润超过ProfitThreshold时平掉多头。 - 当
EMA10升破其前值且当前利润超过ProfitThreshold时平掉空头。 - 开仓时同时设置止损和止盈(多空使用不同的距离)。
- 价格朝有利方向运行
TrailingStopPoints后启动跟踪止损,之后按TrailingStepPoints的步长上调。
- 当
- 止损:是 — 固定止损、固定止盈与跟踪止损结合。
- 默认参数:
FastEmaLength= 10MediumEmaLength= 25SlowEmaLength= 50TakeProfitBuyPoints= 55TakeProfitSellPoints= 65StopLossBuyPoints= 60StopLossSellPoints= 85TrailingStopPoints= 74TrailingStepPoints= 5ProfitThreshold= 10SarAcceleration= 0.02SarMaxAcceleration= 0.2Volume= 1CandleType= 1 小时时间框架
- 补充说明:
- 所有距离以价格最小变动单位表示,系统会根据品种的最小跳动值自动换算。
- 盈利平仓依据仓位的总利润(包含持仓量)并将价格跳动转换为账户货币。
- 跟踪止损保持在价格背后,只有当变动超过设定步长时才会移动。
- 过滤标签:
- 类型: Trend following
- 方向: 多空双向
- 指标: EMA, Parabolic SAR
- 止损: 是(固定 + 跟踪)
- 复杂度: 中等
- 时间框架: 可配置(默认 1 小时)
- 季节性: 否
- 神经网络: 否
- 背离: 否
- 风险等级: 中等
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()