Стратегия Forex Fraus Portfolio
Эта стратегия торгует одним инструментом на основе индикатора Williams %R с большим периодом. Когда индикатор выходит из экстремальных зон, стратегия открывает позиции в направлении пробоя.
Принцип работы
- Рассчитывается Williams %R за
WprPeriod свечей.
- Если индикатор опускается ниже
BuyThreshold, активируется возможность покупки. Когда значение поднимается выше порога, выставляется рыночная покупка.
- Если индикатор поднимается выше
SellThreshold, активируется возможность продажи. Когда значение опускается ниже порога, выставляется рыночная продажа.
- Торговля ведётся только в промежуток времени между
StartHour и StopHour.
- Через параметры можно включить стоп‑лосс, тейк‑профит и трейлинг‑стоп.
Параметры
WprPeriod – период Williams %R.
BuyThreshold – значение для подготовки лонга.
SellThreshold – значение для подготовки шорта.
StartHour / StopHour – границы торговой сессии.
SlPoints – размер стоп‑лосса в пунктах. 0 отключает.
TpPoints – размер тейк‑профита в пунктах. 0 отключает.
UseTrailing – использовать трейлинг‑стоп.
TrailingStop – расстояние трейлинг‑стопа в пунктах.
TrailingStep – шаг обновления трейлинг‑стопа.
CandleType – тип свечей для подписки.
Заметки
Оригинальная версия MQL4 торговала несколькими валютными парами и управляла ордерами для каждой. Этот C# порт концентрируется на одном инструменте и демонстрирует основную идею с использованием высокоуровневого API StockSharp.
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>
/// Williams %R based strategy with trailing stop logic.
/// </summary>
public class ForexFrausPortfolioStrategy : Strategy
{
private readonly StrategyParam<int> _wprPeriod;
private readonly StrategyParam<decimal> _buyThreshold;
private readonly StrategyParam<decimal> _sellThreshold;
private readonly StrategyParam<int> _startHour;
private readonly StrategyParam<int> _stopHour;
private readonly StrategyParam<DataType> _candleType;
private bool _okBuy;
private bool _okSell;
public int WprPeriod { get => _wprPeriod.Value; set => _wprPeriod.Value = value; }
public decimal BuyThreshold { get => _buyThreshold.Value; set => _buyThreshold.Value = value; }
public decimal SellThreshold { get => _sellThreshold.Value; set => _sellThreshold.Value = value; }
public int StartHour { get => _startHour.Value; set => _startHour.Value = value; }
public int StopHour { get => _stopHour.Value; set => _stopHour.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ForexFrausPortfolioStrategy()
{
_wprPeriod = Param(nameof(WprPeriod), 60)
.SetDisplay("WPR Period", "Williams %R calculation period", "Parameters")
.SetOptimize(20, 200, 20);
_buyThreshold = Param(nameof(BuyThreshold), -90m)
.SetDisplay("Buy Threshold", "Trigger level for long entry", "Parameters");
_sellThreshold = Param(nameof(SellThreshold), -10m)
.SetDisplay("Sell Threshold", "Trigger level for short entry", "Parameters");
_startHour = Param(nameof(StartHour), 0)
.SetDisplay("Start Hour", "Trading start hour", "Time");
_stopHour = Param(nameof(StopHour), 24)
.SetDisplay("Stop Hour", "Trading stop hour", "Time");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_okBuy = false;
_okSell = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_okBuy = false;
_okSell = false;
var wpr = new WilliamsR { Length = WprPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(wpr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, wpr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal wprValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var hour = candle.OpenTime.Hour;
var inTime = StartHour <= StopHour
? hour >= StartHour && hour < StopHour
: hour >= StartHour || hour < StopHour;
if (!inTime)
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
return;
}
// WPR dips below buy threshold => arm buy signal
if (wprValue < BuyThreshold)
_okBuy = true;
// WPR crosses back above buy threshold while armed => buy
if (wprValue > BuyThreshold && _okBuy)
{
_okBuy = false;
if (Position <= 0)
BuyMarket();
return;
}
// WPR rises above sell threshold => arm sell signal
if (wprValue > SellThreshold)
_okSell = true;
// WPR crosses back below sell threshold while armed => sell
if (wprValue < SellThreshold && _okSell)
{
_okSell = false;
if (Position >= 0)
SellMarket();
}
}
}
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 WilliamsR
from StockSharp.Algo.Strategies import Strategy
class forex_fraus_portfolio_strategy(Strategy):
def __init__(self):
super(forex_fraus_portfolio_strategy, self).__init__()
self._wpr_period = self.Param("WprPeriod", 60) \
.SetDisplay("WPR Period", "Williams %R calculation period", "Parameters")
self._buy_threshold = self.Param("BuyThreshold", -90.0) \
.SetDisplay("Buy Threshold", "Trigger level for long entry", "Parameters")
self._sell_threshold = self.Param("SellThreshold", -10.0) \
.SetDisplay("Sell Threshold", "Trigger level for short entry", "Parameters")
self._start_hour = self.Param("StartHour", 0) \
.SetDisplay("Start Hour", "Trading start hour", "Time")
self._stop_hour = self.Param("StopHour", 24) \
.SetDisplay("Stop Hour", "Trading stop hour", "Time")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._ok_buy = False
self._ok_sell = False
@property
def wpr_period(self):
return self._wpr_period.Value
@property
def buy_threshold(self):
return self._buy_threshold.Value
@property
def sell_threshold(self):
return self._sell_threshold.Value
@property
def start_hour(self):
return self._start_hour.Value
@property
def stop_hour(self):
return self._stop_hour.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(forex_fraus_portfolio_strategy, self).OnReseted()
self._ok_buy = False
self._ok_sell = False
def OnStarted2(self, time):
super(forex_fraus_portfolio_strategy, self).OnStarted2(time)
self._ok_buy = False
self._ok_sell = False
wpr = WilliamsR()
wpr.Length = self.wpr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(wpr, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, wpr)
self.DrawOwnTrades(area)
def process_candle(self, candle, wpr_value):
if candle.State != CandleStates.Finished:
return
wpr_value = float(wpr_value)
hour = candle.OpenTime.Hour
start_h = int(self.start_hour)
stop_h = int(self.stop_hour)
if start_h <= stop_h:
in_time = hour >= start_h and hour < stop_h
else:
in_time = hour >= start_h or hour < stop_h
if not in_time:
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
return
buy_thr = float(self.buy_threshold)
sell_thr = float(self.sell_threshold)
if wpr_value < buy_thr:
self._ok_buy = True
if wpr_value > buy_thr and self._ok_buy:
self._ok_buy = False
if self.Position <= 0:
self.BuyMarket()
return
if wpr_value > sell_thr:
self._ok_sell = True
if wpr_value < sell_thr and self._ok_sell:
self._ok_sell = False
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return forex_fraus_portfolio_strategy()