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>
/// Elite eFibo Trader grid strategy converted from MQL5.
/// Builds a Fibonacci-based sequence of market entries at price levels.
/// Buys or sells at progressively worse prices with increasing volume (Fibonacci sequence).
/// Exits when total PnL target is reached or stop loss is hit.
/// </summary>
public class EliteEFiboTraderStrategy : Strategy
{
private readonly StrategyParam<int> _levelsCount;
private readonly StrategyParam<bool> _openBuy;
private readonly StrategyParam<bool> _openSell;
private readonly StrategyParam<decimal> _levelDistance;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private int _currentLevel;
private int _activeDirection;
private bool _cycleActive;
// Fibonacci volumes for grid levels
private static readonly decimal[] FibVolumes = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
/// <summary>
/// Enable buy-only mode.
/// </summary>
public bool OpenBuy
{
get => _openBuy.Value;
set => _openBuy.Value = value;
}
/// <summary>
/// Enable sell-only mode.
/// </summary>
public bool OpenSell
{
get => _openSell.Value;
set => _openSell.Value = value;
}
/// <summary>
/// Number of Fibonacci grid levels.
/// </summary>
public int LevelsCount
{
get => _levelsCount.Value;
set => _levelsCount.Value = value;
}
/// <summary>
/// Distance between successive pending levels in price steps.
/// </summary>
public decimal LevelDistance
{
get => _levelDistance.Value;
set => _levelDistance.Value = value;
}
/// <summary>
/// Stop-loss size in price steps.
/// </summary>
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take profit size in price steps.
/// </summary>
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public EliteEFiboTraderStrategy()
{
_levelsCount = Param(nameof(LevelsCount), 6)
.SetGreaterThanZero()
.SetDisplay("Levels Count", "Number of Fibonacci levels", "Grid");
_openBuy = Param(nameof(OpenBuy), true)
.SetDisplay("Open Buy", "Enable buying", "General");
_openSell = Param(nameof(OpenSell), true)
.SetDisplay("Open Sell", "Enable selling", "General");
_levelDistance = Param(nameof(LevelDistance), 50m)
.SetGreaterThanZero()
.SetDisplay("Level Distance", "Distance between orders in price steps", "Grid");
_stopLossPoints = Param(nameof(StopLossPoints), 200m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop-loss size in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 100m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Take profit size in price steps", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cycleActive = false;
_currentLevel = 0;
_activeDirection = 0;
_entryPrice = 0;
var sma = new SMA { Length = 20 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var step = Security.PriceStep ?? 1m;
if (!_cycleActive && Position == 0)
{
// Start a new cycle based on trend direction
if (OpenBuy && close > smaValue)
{
_activeDirection = 1;
_entryPrice = close;
_currentLevel = 0;
_cycleActive = true;
BuyMarket();
}
else if (OpenSell && close < smaValue)
{
_activeDirection = -1;
_entryPrice = close;
_currentLevel = 0;
_cycleActive = true;
SellMarket();
}
}
else if (_cycleActive)
{
var stopDistance = StopLossPoints * step;
var tpDistance = TakeProfitPoints * step;
var levelDist = LevelDistance * step;
// Check stop loss
if (_activeDirection == 1 && close <= _entryPrice - stopDistance)
{
SellMarket(Math.Abs(Position));
ResetCycle();
return;
}
else if (_activeDirection == -1 && close >= _entryPrice + stopDistance)
{
BuyMarket(Math.Abs(Position));
ResetCycle();
return;
}
// Check take profit
if (_activeDirection == 1 && close >= _entryPrice + tpDistance)
{
SellMarket(Math.Abs(Position));
ResetCycle();
return;
}
else if (_activeDirection == -1 && close <= _entryPrice - tpDistance)
{
BuyMarket(Math.Abs(Position));
ResetCycle();
return;
}
// Check for grid level additions (averaging into losing positions)
var nextLevel = _currentLevel + 1;
if (nextLevel < LevelsCount && nextLevel < FibVolumes.Length)
{
if (_activeDirection == 1 && close <= _entryPrice - levelDist * nextLevel)
{
BuyMarket(FibVolumes[nextLevel]);
_currentLevel = nextLevel;
}
else if (_activeDirection == -1 && close >= _entryPrice + levelDist * nextLevel)
{
SellMarket(FibVolumes[nextLevel]);
_currentLevel = nextLevel;
}
}
}
}
private void ResetCycle()
{
_cycleActive = false;
_currentLevel = 0;
_activeDirection = 0;
_entryPrice = 0;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
FIB_VOLUMES = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
class elite_e_fibo_trader_strategy(Strategy):
def __init__(self):
super(elite_e_fibo_trader_strategy, self).__init__()
self._levels_count = self.Param("LevelsCount", 6)
self._open_buy = self.Param("OpenBuy", True)
self._open_sell = self.Param("OpenSell", True)
self._level_distance = self.Param("LevelDistance", 50.0)
self._stop_loss_points = self.Param("StopLossPoints", 200.0)
self._take_profit_points = self.Param("TakeProfitPoints", 100.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._entry_price = 0.0
self._current_level = 0
self._active_direction = 0
self._cycle_active = False
@property
def LevelsCount(self):
return self._levels_count.Value
@LevelsCount.setter
def LevelsCount(self, value):
self._levels_count.Value = value
@property
def OpenBuy(self):
return self._open_buy.Value
@OpenBuy.setter
def OpenBuy(self, value):
self._open_buy.Value = value
@property
def OpenSell(self):
return self._open_sell.Value
@OpenSell.setter
def OpenSell(self, value):
self._open_sell.Value = value
@property
def LevelDistance(self):
return self._level_distance.Value
@LevelDistance.setter
def LevelDistance(self, value):
self._level_distance.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(elite_e_fibo_trader_strategy, self).OnStarted2(time)
self._cycle_active = False
self._current_level = 0
self._active_direction = 0
self._entry_price = 0.0
sma = SimpleMovingAverage()
sma.Length = 20
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
sma_val = float(sma_value)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if not self._cycle_active and self.Position == 0:
if self.OpenBuy and close > sma_val:
self._active_direction = 1
self._entry_price = close
self._current_level = 0
self._cycle_active = True
self.BuyMarket()
elif self.OpenSell and close < sma_val:
self._active_direction = -1
self._entry_price = close
self._current_level = 0
self._cycle_active = True
self.SellMarket()
elif self._cycle_active:
stop_distance = float(self.StopLossPoints) * step
tp_distance = float(self.TakeProfitPoints) * step
level_dist = float(self.LevelDistance) * step
if self._active_direction == 1 and close <= self._entry_price - stop_distance:
self.SellMarket()
self._reset_cycle()
return
elif self._active_direction == -1 and close >= self._entry_price + stop_distance:
self.BuyMarket()
self._reset_cycle()
return
if self._active_direction == 1 and close >= self._entry_price + tp_distance:
self.SellMarket()
self._reset_cycle()
return
elif self._active_direction == -1 and close <= self._entry_price - tp_distance:
self.BuyMarket()
self._reset_cycle()
return
next_level = self._current_level + 1
if next_level < int(self.LevelsCount) and next_level < len(FIB_VOLUMES):
if self._active_direction == 1 and close <= self._entry_price - level_dist * next_level:
self.BuyMarket()
self._current_level = next_level
elif self._active_direction == -1 and close >= self._entry_price + level_dist * next_level:
self.SellMarket()
self._current_level = next_level
def _reset_cycle(self):
self._cycle_active = False
self._current_level = 0
self._active_direction = 0
self._entry_price = 0.0
def OnReseted(self):
super(elite_e_fibo_trader_strategy, self).OnReseted()
self._entry_price = 0.0
self._current_level = 0
self._active_direction = 0
self._cycle_active = False
def CreateClone(self):
return elite_e_fibo_trader_strategy()