diff --git a/Settings/HmaClusterBot, GER40 m5.cbotset b/Settings/HmaClusterBot, GER40 m5.cbotset new file mode 100644 index 0000000..049bdc5 --- /dev/null +++ b/Settings/HmaClusterBot, GER40 m5.cbotset @@ -0,0 +1,24 @@ +{ + "Chart": { + "Symbol": "GER40", + "Period": "m5" + }, + "Parameters": { + "SymbolsCsv": "", + "RiskPercent": 1.0, + "EntrySigThreshold": 15.0, + "SlSigThreshold": 5.0, + "SmaBiasPeriod": 250, + "HmaBiasPeriod": 225, + "UseBiasDeviationFilter": true, + "BiasDeviationAvgPeriod": 100, + "UseDynamicPositionManagement": true, + "CloseProfitOnBiasFlip": false, + "HmaClusterPeriod": 25, + "MaxPoints": 2000, + "DecayPeriod": 1000, + "SendTelegramOnly": false, + "TelegramBotToken": "8569913524:AAE9RGsvkBPa0yhTFCKBjVeST0fuzdOx5w0", + "TelegramChatId": "5171721381" + } +} \ No newline at end of file diff --git a/Sources/Robots/HmaClusterBot.algo b/Sources/Robots/HmaClusterBot.algo index 31e5eef..9f4af56 100644 Binary files a/Sources/Robots/HmaClusterBot.algo and b/Sources/Robots/HmaClusterBot.algo differ diff --git a/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.cs b/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.cs index 449fd6e..f6c0153 100644 --- a/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.cs +++ b/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.cs @@ -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 _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,