Hello All,
I’m glad to hear that the strategy has been working well, especially for buy entries in a bull market. The added protection logic to pause trading during excessive losses is an important safeguard for account protection, which is great for preventing further drawdowns during unfavorable market conditions.
This strategy certainly seems like a solid starting point for any trader who is enthusiastic about Hull Moving Averages. The combination of HMA crossovers, price positioning relative to Hull MAs, and the RSI filter is a great way to identify high-quality buy entries.
Key Features of the Code:
Hull Moving Averages (HMA):
Using multiple Hull Moving Averages (9, 21, and 100) is a solid method for identifying trend direction and momentum. The crossover strategy between HMA9 and HMA21 will allow the robot to enter trades when momentum is shifting in the market.
RSI Filtering:
RSI is used to confirm that the market is not overbought, reducing the likelihood of entering at the top of an uptrend. With RSI conditions set below the oversold level, it filters out potential overbought conditions and helps avoid buy entries when the market is too strong or too weak.
Trade Protection Mechanisms:
Pause Trading on Excessive Losses: If the account experiences too many losses, the strategy pauses trading for a specified duration. This is a good risk management feature to avoid excessive drawdowns.
Stop-Loss and Take-Profit Levels: The fixed pips stop loss and take profit levels offer a clear exit strategy for each trade, ensuring consistent risk management.
Trailing Stop Logic: The trailing stop logic allows the bot to lock in profits as the market moves in favor of the position. This adds a dynamic aspect to risk management.
Position Limits and Loss Tracking:
By limiting the number of active positions and monitoring the performance of current trades (buy positions only), the strategy avoids overexposing the account to risk. The system intelligently ensures that only a certain number of positions can be opened at once, adding a layer of protection.
Possible Improvements or Extensions:
While the code is well-structured, a few areas that could be worth testing or adjusting (depending on your future goals or market conditions) are:
Sell Conditions (for a more balanced approach):
If you ever want to optimize the strategy further to trade in both directions (long and short), revisiting the sell conditions with additional filters or a distinct set of entry rules could help balance the strategy’s profitability.
Additional Filters/Indicators:
You could experiment with other indicators like the MACD or Bollinger Bands to complement the Hull MAs and RSI for more robust entry and exit signals.
Dynamic Lot Size:
Rather than using a fixed lot size, you could introduce a risk-based position sizing approach where the lot size is dynamically calculated based on the current account balance and risk tolerance (e.g., risking 1% of the account balance per trade).
Backtesting & Optimization:
Continuously backtest this strategy on different timeframes and market conditions to fine-tune parameters such as stop loss, take profit, trailing stops, and RSI levels.
`
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class HullMAAlgo : Robot
{
private HullMovingAverage hma9;
private HullMovingAverage hma21;
private HullMovingAverage hma100;
private RelativeStrengthIndex rsi;
// Define order parameters
[Parameter("Lot Size", DefaultValue = 3)]
public double LotSize { get; set; }
[Parameter("Stop Loss (pips)", DefaultValue = 50)]
public double StopLossPips { get; set; }
[Parameter("Take Profit (pips)", DefaultValue = 100)]
public double TakeProfitPips { get; set; }
[Parameter("Trailing Stop (pips)", DefaultValue = 20)]
public double TrailingStopPips { get; set; }
[Parameter("RSI Period", DefaultValue = 14)]
public int RsiPeriod { get; set; }
[Parameter("RSI Overbought Level", DefaultValue = 70)]
public double RsiOverbought { get; set; }
[Parameter("RSI Oversold Level", DefaultValue = 30)]
public double RsiOversold { get; set; }
private DateTime lastTradeTime;
private double totalLosses;
private bool isTradingPaused;
private DateTime pauseEndTime;
protected override void OnStart()
{
// Initialize indicators
hma9 = Indicators.HullMovingAverage(MarketData.GetSeries(TimeFrame).Close, 9);
hma21 = Indicators.HullMovingAverage(MarketData.GetSeries(TimeFrame).Close, 21);
hma100 = Indicators.HullMovingAverage(MarketData.GetSeries(TimeFrame).Close, 100);
rsi = Indicators.RelativeStrengthIndex(MarketData.GetSeries(TimeFrame).Close, RsiPeriod);
lastTradeTime = DateTime.UtcNow;
totalLosses = 0;
isTradingPaused = false;
}
protected override void OnBar()
{
if (isTradingPaused)
{
if (DateTime.UtcNow >= pauseEndTime)
{
isTradingPaused = false;
totalLosses = 0; // Reset losses after pause
Print("Trading resumed.");
}
else
{
return; // Exit if still in pause
}
}
// Check for crossover conditions
bool crossover = hma9.Result.Last(1) > hma21.Result.Last(1) && hma9.Result.Last(2) <= hma21.Result.Last(2);
bool priceAboveHMAs = MarketSeries.Close.Last(1) > hma9.Result.Last(1);
bool priceBelowHMA100 = MarketSeries.Close.Last(1) < hma100.Result.Last(1);
bool rsiConditions = rsi.Result.Last(1) < RsiOversold;
var totalPositions = Positions.FindAll("Buy", Symbol).Length;
// Implement loss tracking
double totalProfit = 0;
foreach (var position in Positions.FindAll("Buy", Symbol))
{
totalProfit += position.GrossProfit;
if (position.GrossProfit < 0)
{
totalLosses += -position.GrossProfit; // Accumulate losses
}
}
// Check if trading should be paused
if (DateTime.UtcNow - lastTradeTime > TimeSpan.FromHours(8) && totalLosses >= 100)
{
isTradingPaused = true;
pauseEndTime = DateTime.UtcNow.AddHours(3);
Print("Trading paused due to excessive losses. This method is made to enhance the account equity protection.");
return;
}
// Check if conditions for entry are met
if (crossover && priceAboveHMAs && priceBelowHMA100 && totalPositions < 5)
{
// Prevent trading if two out of three trades are losing
if (totalPositions == 3)
{
int losingCount = 0;
foreach (var position in Positions.FindAll("Buy", Symbol))
{
if (position.GrossProfit < 0)
losingCount++;
}
if (losingCount >= 2)
{
Print("Trading paused due to 2 out of 3 trades being losing. This method is made to enhance the account equity protection.");
return;
}
}
// Calculate stop loss and take profit
double stopLossPrice = MarketSeries.Close.Last(1) - StopLossPips * Symbol.PipSize;
double takeProfitPrice = MarketSeries.Close.Last(1) + TakeProfitPips * Symbol.PipSize;
// Execute buy order
ExecuteMarketOrder(TradeType.Buy, Symbol, LotSize, "Buy", stopLossPrice, takeProfitPrice);
lastTradeTime = DateTime.UtcNow; // Update last trade time
}
// Implement trailing stop logic
foreach (var position in Positions.FindAll("Buy", Symbol.Name))
{
double newStopLossPrice = position.EntryPrice + TrailingStopPips * Symbol.PipSize;
if (position.GrossProfit >= position.EntryPrice + newStopLossPrice)
{
try
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
Print("Position Modified with Profits");
}
catch (Exception ex)
{
Print("Error modifying position: " + ex.Message);
}
}
}
}
}
}