Optimizing and Refactoring HmaClusterBot & -Indicator

This commit is contained in:
Michael Schimmel
2026-01-28 17:00:14 +01:00
parent 88442e5c58
commit a146b1389c
3 changed files with 120 additions and 66 deletions
Binary file not shown.
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using Myc; // Referenz auf die extrahierte Cluster-Logik
using Myc; // Referencing external cluster logic
namespace cAlgo.Robots
{
@@ -130,8 +130,6 @@ namespace cAlgo.Robots
{
Print(message);
// WICHTIG: Im Backtest NIEMALS Netzwerk-Calls machen, auch nicht bei Fehlern.
// Das führt bei vielen Fehlern zum Stillstand der Simulation.
if (IsBacktesting) return;
if (!string.IsNullOrWhiteSpace(TelegramBotToken) && !string.IsNullOrWhiteSpace(TelegramChatId))
@@ -272,7 +270,6 @@ namespace cAlgo.Robots
private bool _deviationConditionMetInCurrentCycle;
private bool _isTradingAllowedBasedOnPrevCycle;
// --- OPTIMIERUNG: Nutzt Calculator statt Liste ---
private readonly Myc.ClusterCalculator _clusterCalculator;
private readonly List<double> _amplitudes = new();
@@ -305,7 +302,6 @@ namespace cAlgo.Robots
_chatId = chatId;
_errorCallback = errorCallback;
// Calculator mit Reserve initialisieren
_clusterCalculator = new Myc.ClusterCalculator();
}
@@ -470,57 +466,25 @@ namespace cAlgo.Robots
ClusterLevel? newSl = null;
ClusterLevel? newTp = null;
// For logic: Find nearest strong cluster behind entry (SL) and nearest strong cluster ahead (TP)
double highestSlPrice = double.MinValue; // Buy SL: Highest below price
double lowestTpPrice = double.MaxValue; // Buy TP: Lowest above price
double lowestSlPrice = double.MaxValue; // Sell SL: Lowest above price
double highestTpPrice = double.MinValue; // Sell TP: Highest below price
if (pos.TradeType == TradeType.Buy)
{
double highestSlPrice = double.MinValue;
double highestTpPrice = double.MinValue;
foreach (var c in clusters)
{
if (c.Price < pNow && c.Significance < _config.SlSigThreshold && c.Price > highestSlPrice)
// SL: Strong clusters BELOW price -> Nearest one (Highest Price)
if (c.Price < pNow && c.Significance >= _config.SlSigThreshold && c.Price > highestSlPrice)
{
newSl = c;
highestSlPrice = c.Price;
}
if (c.Price > pNow && c.Significance >= _config.EntrySigThreshold && c.Price > highestTpPrice)
{
newTp = c;
highestTpPrice = c.Price;
}
}
double proposedSl = (newSl.HasValue) ? newSl.Value.Price : (pos.StopLoss ?? 0);
double proposedTp = (newTp.HasValue) ? newTp.Value.Price : (pos.TakeProfit ?? 0);
bool modifySl = pos.StopLoss.HasValue && (proposedSl > pos.StopLoss.Value + _symbol.TickSize);
if (!pos.StopLoss.HasValue && newSl.HasValue) modifySl = true;
bool modifyTp = newTp.HasValue && Math.Abs(proposedTp - (pos.TakeProfit ?? 0)) > _symbol.TickSize;
if (modifySl || modifyTp)
{
double finalSl = modifySl ? proposedSl : pos.StopLoss ?? 0;
double finalTp = modifyTp ? proposedTp : pos.TakeProfit ?? 0;
if (finalSl < _symbol.Bid && (finalTp == 0 || finalTp > _symbol.Bid))
{
_robot.ModifyPosition(pos, finalSl, finalTp, ProtectionType.Absolute);
}
}
}
else
{
double lowestSlPrice = double.MaxValue;
double lowestTpPrice = double.MaxValue;
foreach (var c in clusters)
{
if (c.Price > pNow && c.Significance < _config.SlSigThreshold && c.Price < lowestSlPrice)
{
newSl = c;
lowestSlPrice = c.Price;
}
if (c.Price < pNow && c.Significance >= _config.EntrySigThreshold && c.Price < lowestTpPrice)
// TP: Strong clusters ABOVE price -> Nearest one (Lowest Price)
if (c.Price > pNow && c.Significance >= _config.EntrySigThreshold && c.Price < lowestTpPrice)
{
newTp = c;
lowestTpPrice = c.Price;
@@ -530,6 +494,47 @@ namespace cAlgo.Robots
double proposedSl = (newSl.HasValue) ? newSl.Value.Price : (pos.StopLoss ?? 0);
double proposedTp = (newTp.HasValue) ? newTp.Value.Price : (pos.TakeProfit ?? 0);
// Move SL up only (trailing)
bool modifySl = pos.StopLoss.HasValue && (proposedSl > pos.StopLoss.Value + _symbol.TickSize);
if (!pos.StopLoss.HasValue && newSl.HasValue) modifySl = true;
// Update TP if it changes significantly
bool modifyTp = newTp.HasValue && Math.Abs(proposedTp - (pos.TakeProfit ?? 0)) > _symbol.TickSize;
if (modifySl || modifyTp)
{
double finalSl = modifySl ? proposedSl : pos.StopLoss ?? 0;
double finalTp = modifyTp ? proposedTp : pos.TakeProfit ?? 0;
// SL < Bid, TP > Bid (or 0)
if (finalSl < _symbol.Bid && (finalTp == 0 || finalTp > _symbol.Bid))
{
_robot.ModifyPosition(pos, finalSl, finalTp, ProtectionType.Absolute);
}
}
}
else // Sell
{
foreach (var c in clusters)
{
// SL: Strong clusters ABOVE price -> Nearest one (Lowest Price)
if (c.Price > pNow && c.Significance >= _config.SlSigThreshold && c.Price < lowestSlPrice)
{
newSl = c;
lowestSlPrice = c.Price;
}
// TP: Strong clusters BELOW price -> Nearest one (Highest Price)
if (c.Price < pNow && c.Significance >= _config.EntrySigThreshold && c.Price > highestTpPrice)
{
newTp = c;
highestTpPrice = c.Price;
}
}
double proposedSl = (newSl.HasValue) ? newSl.Value.Price : (pos.StopLoss ?? 0);
double proposedTp = (newTp.HasValue) ? newTp.Value.Price : (pos.TakeProfit ?? 0);
// Move SL down only (trailing)
bool modifySl = pos.StopLoss.HasValue && (proposedSl < pos.StopLoss.Value - _symbol.TickSize);
if (!pos.StopLoss.HasValue && newSl.HasValue) modifySl = true;
@@ -540,6 +545,7 @@ namespace cAlgo.Robots
double finalSl = modifySl ? proposedSl : pos.StopLoss ?? 0;
double finalTp = modifyTp ? proposedTp : pos.TakeProfit ?? 0;
// SL > Ask, TP < Ask (or 0)
if (finalSl > _symbol.Ask && (finalTp == 0 || finalTp < _symbol.Ask))
{
_robot.ModifyPosition(pos, finalSl, finalTp, ProtectionType.Absolute);
@@ -619,20 +625,32 @@ namespace cAlgo.Robots
ClusterLevel? sl = null;
ClusterLevel? tp = null;
double highestEntryPrice = double.MinValue;
double lowestSlPrice = double.MaxValue;
double lowestTpPrice = double.MaxValue;
double highestEntryPrice = double.MinValue; // Entry: Deepest fade (Highest Price)
double lowestSlPrice = double.MaxValue; // SL: Nearest strong resistance above Entry (Lowest Price > Entry)
double highestTpPrice = double.MinValue; // TP: Nearest strong support below Entry (Highest Price < Entry)
// 1. Find Entry (Above Price)
foreach (var c in clusters)
{
if (c.Price > pNow)
{
// Aggressive fade: Pick highest price available
if ((c.Significance >= _config.EntrySigThreshold) && (c.Price > highestEntryPrice))
{
entry = c;
highestEntryPrice = c.Price;
}
if ((c.Significance < _config.SlSigThreshold) && (c.Price < lowestSlPrice))
}
}
if (entry == null) return;
// 2. Find SL relative to Entry (Strong Cluster, Nearest Above)
foreach (var c in clusters)
{
if (c.Price > entry.Value.Price)
{
if (c.Significance >= _config.SlSigThreshold && c.Price < lowestSlPrice)
{
sl = c;
lowestSlPrice = c.Price;
@@ -640,16 +658,17 @@ namespace cAlgo.Robots
}
}
if (entry == null || sl == null) return;
if (sl == null) return;
// 3. Find TP relative to Entry (Strong Cluster, Nearest Below)
foreach (var c in clusters)
{
if ((c.Price < entry.Value.Price) && (c.Significance >= _config.EntrySigThreshold))
if (c.Price < entry.Value.Price)
{
if (c.Price < lowestTpPrice)
if (c.Significance >= _config.EntrySigThreshold && c.Price > highestTpPrice)
{
tp = c;
lowestTpPrice = c.Price;
highestTpPrice = c.Price;
}
}
}
@@ -670,20 +689,32 @@ namespace cAlgo.Robots
ClusterLevel? sl = null;
ClusterLevel? tp = null;
double lowestEntryPrice = double.MaxValue;
double highestSlPrice = double.MinValue;
double highestTpPrice = double.MinValue;
double lowestEntryPrice = double.MaxValue; // Entry: Deepest fade (Lowest Price)
double highestSlPrice = double.MinValue; // SL: Nearest strong support below Entry (Highest Price < Entry)
double lowestTpPrice = double.MaxValue; // TP: Nearest strong resistance above Entry (Lowest Price > Entry)
// 1. Find Entry (Below Price)
foreach (var c in clusters)
{
if (c.Price < pNow)
{
// Aggressive fade: Pick lowest price available
if ((c.Significance >= _config.EntrySigThreshold) && (c.Price < lowestEntryPrice))
{
entry = c;
lowestEntryPrice = c.Price;
}
if ((c.Significance < _config.SlSigThreshold) && (c.Price > highestSlPrice))
}
}
if (entry == null) return;
// 2. Find SL relative to Entry (Strong Cluster, Nearest Below)
foreach (var c in clusters)
{
if (c.Price < entry.Value.Price)
{
if (c.Significance >= _config.SlSigThreshold && c.Price > highestSlPrice)
{
sl = c;
highestSlPrice = c.Price;
@@ -691,16 +722,17 @@ namespace cAlgo.Robots
}
}
if (entry == null || sl == null) return;
if (sl == null) return;
// 3. Find TP relative to Entry (Strong Cluster, Nearest Above)
foreach (var c in clusters)
{
if ((c.Price > entry.Value.Price) && (c.Significance >= _config.EntrySigThreshold))
if (c.Price > entry.Value.Price)
{
if (c.Price > highestTpPrice)
if (c.Significance >= _config.EntrySigThreshold && c.Price < lowestTpPrice)
{
tp = c;
highestTpPrice = c.Price;
lowestTpPrice = c.Price;
}
}
}
@@ -760,7 +792,6 @@ namespace cAlgo.Robots
var result = _robot.ModifyPendingOrder(existingOrder, entry, sl, tp, ProtectionType.Absolute, null, volume);
if (!result.IsSuccessful)
{
// Falls Modifikation fehlschlägt (z.B. Spread), löschen wir die Order, um keine veralteten Levels zu handeln
_robot.CancelPendingOrder(existingOrder);
}
}
@@ -820,7 +851,6 @@ namespace cAlgo.Robots
if (_currentDynamicRange < _symbol.PipSize) _currentDynamicRange = _symbol.PipSize;
}
// Neuen Punkt in den optimierten Calculator einspeisen
_clusterCalculator.AddPoint(new Myc.ExtremumPoint
{
Price = _trendExtremum,