Optimizing and Refactoring HmaClusterBot & -Indicator
This commit is contained in:
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||||||
using cAlgo.API;
|
using cAlgo.API;
|
||||||
using cAlgo.API.Indicators;
|
using cAlgo.API.Indicators;
|
||||||
using cAlgo.API.Internals;
|
using cAlgo.API.Internals;
|
||||||
using Myc; // Referenz auf die extrahierte Cluster-Logik
|
using Myc; // Referencing external cluster logic
|
||||||
|
|
||||||
namespace cAlgo.Robots
|
namespace cAlgo.Robots
|
||||||
{
|
{
|
||||||
@@ -130,8 +130,6 @@ namespace cAlgo.Robots
|
|||||||
{
|
{
|
||||||
Print(message);
|
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 (IsBacktesting) return;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(TelegramBotToken) && !string.IsNullOrWhiteSpace(TelegramChatId))
|
if (!string.IsNullOrWhiteSpace(TelegramBotToken) && !string.IsNullOrWhiteSpace(TelegramChatId))
|
||||||
@@ -272,7 +270,6 @@ namespace cAlgo.Robots
|
|||||||
private bool _deviationConditionMetInCurrentCycle;
|
private bool _deviationConditionMetInCurrentCycle;
|
||||||
private bool _isTradingAllowedBasedOnPrevCycle;
|
private bool _isTradingAllowedBasedOnPrevCycle;
|
||||||
|
|
||||||
// --- OPTIMIERUNG: Nutzt Calculator statt Liste ---
|
|
||||||
private readonly Myc.ClusterCalculator _clusterCalculator;
|
private readonly Myc.ClusterCalculator _clusterCalculator;
|
||||||
private readonly List<double> _amplitudes = new();
|
private readonly List<double> _amplitudes = new();
|
||||||
|
|
||||||
@@ -305,7 +302,6 @@ namespace cAlgo.Robots
|
|||||||
_chatId = chatId;
|
_chatId = chatId;
|
||||||
_errorCallback = errorCallback;
|
_errorCallback = errorCallback;
|
||||||
|
|
||||||
// Calculator mit Reserve initialisieren
|
|
||||||
_clusterCalculator = new Myc.ClusterCalculator();
|
_clusterCalculator = new Myc.ClusterCalculator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,57 +466,25 @@ namespace cAlgo.Robots
|
|||||||
ClusterLevel? newSl = null;
|
ClusterLevel? newSl = null;
|
||||||
ClusterLevel? newTp = 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)
|
if (pos.TradeType == TradeType.Buy)
|
||||||
{
|
{
|
||||||
double highestSlPrice = double.MinValue;
|
|
||||||
double highestTpPrice = double.MinValue;
|
|
||||||
|
|
||||||
foreach (var c in clusters)
|
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;
|
newSl = c;
|
||||||
highestSlPrice = c.Price;
|
highestSlPrice = c.Price;
|
||||||
}
|
}
|
||||||
if (c.Price > pNow && c.Significance >= _config.EntrySigThreshold && c.Price > highestTpPrice)
|
// TP: Strong clusters ABOVE price -> Nearest one (Lowest Price)
|
||||||
{
|
if (c.Price > pNow && c.Significance >= _config.EntrySigThreshold && c.Price < lowestTpPrice)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
newTp = c;
|
newTp = c;
|
||||||
lowestTpPrice = c.Price;
|
lowestTpPrice = c.Price;
|
||||||
@@ -530,6 +494,47 @@ namespace cAlgo.Robots
|
|||||||
double proposedSl = (newSl.HasValue) ? newSl.Value.Price : (pos.StopLoss ?? 0);
|
double proposedSl = (newSl.HasValue) ? newSl.Value.Price : (pos.StopLoss ?? 0);
|
||||||
double proposedTp = (newTp.HasValue) ? newTp.Value.Price : (pos.TakeProfit ?? 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);
|
bool modifySl = pos.StopLoss.HasValue && (proposedSl < pos.StopLoss.Value - _symbol.TickSize);
|
||||||
if (!pos.StopLoss.HasValue && newSl.HasValue) modifySl = true;
|
if (!pos.StopLoss.HasValue && newSl.HasValue) modifySl = true;
|
||||||
|
|
||||||
@@ -540,6 +545,7 @@ namespace cAlgo.Robots
|
|||||||
double finalSl = modifySl ? proposedSl : pos.StopLoss ?? 0;
|
double finalSl = modifySl ? proposedSl : pos.StopLoss ?? 0;
|
||||||
double finalTp = modifyTp ? proposedTp : pos.TakeProfit ?? 0;
|
double finalTp = modifyTp ? proposedTp : pos.TakeProfit ?? 0;
|
||||||
|
|
||||||
|
// SL > Ask, TP < Ask (or 0)
|
||||||
if (finalSl > _symbol.Ask && (finalTp == 0 || finalTp < _symbol.Ask))
|
if (finalSl > _symbol.Ask && (finalTp == 0 || finalTp < _symbol.Ask))
|
||||||
{
|
{
|
||||||
_robot.ModifyPosition(pos, finalSl, finalTp, ProtectionType.Absolute);
|
_robot.ModifyPosition(pos, finalSl, finalTp, ProtectionType.Absolute);
|
||||||
@@ -619,20 +625,32 @@ namespace cAlgo.Robots
|
|||||||
ClusterLevel? sl = null;
|
ClusterLevel? sl = null;
|
||||||
ClusterLevel? tp = null;
|
ClusterLevel? tp = null;
|
||||||
|
|
||||||
double highestEntryPrice = double.MinValue;
|
double highestEntryPrice = double.MinValue; // Entry: Deepest fade (Highest Price)
|
||||||
double lowestSlPrice = double.MaxValue;
|
double lowestSlPrice = double.MaxValue; // SL: Nearest strong resistance above Entry (Lowest Price > Entry)
|
||||||
double lowestTpPrice = double.MaxValue;
|
double highestTpPrice = double.MinValue; // TP: Nearest strong support below Entry (Highest Price < Entry)
|
||||||
|
|
||||||
|
// 1. Find Entry (Above Price)
|
||||||
foreach (var c in clusters)
|
foreach (var c in clusters)
|
||||||
{
|
{
|
||||||
if (c.Price > pNow)
|
if (c.Price > pNow)
|
||||||
{
|
{
|
||||||
|
// Aggressive fade: Pick highest price available
|
||||||
if ((c.Significance >= _config.EntrySigThreshold) && (c.Price > highestEntryPrice))
|
if ((c.Significance >= _config.EntrySigThreshold) && (c.Price > highestEntryPrice))
|
||||||
{
|
{
|
||||||
entry = c;
|
entry = c;
|
||||||
highestEntryPrice = c.Price;
|
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;
|
sl = c;
|
||||||
lowestSlPrice = c.Price;
|
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)
|
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;
|
tp = c;
|
||||||
lowestTpPrice = c.Price;
|
highestTpPrice = c.Price;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,20 +689,32 @@ namespace cAlgo.Robots
|
|||||||
ClusterLevel? sl = null;
|
ClusterLevel? sl = null;
|
||||||
ClusterLevel? tp = null;
|
ClusterLevel? tp = null;
|
||||||
|
|
||||||
double lowestEntryPrice = double.MaxValue;
|
double lowestEntryPrice = double.MaxValue; // Entry: Deepest fade (Lowest Price)
|
||||||
double highestSlPrice = double.MinValue;
|
double highestSlPrice = double.MinValue; // SL: Nearest strong support below Entry (Highest Price < Entry)
|
||||||
double highestTpPrice = double.MinValue;
|
double lowestTpPrice = double.MaxValue; // TP: Nearest strong resistance above Entry (Lowest Price > Entry)
|
||||||
|
|
||||||
|
// 1. Find Entry (Below Price)
|
||||||
foreach (var c in clusters)
|
foreach (var c in clusters)
|
||||||
{
|
{
|
||||||
if (c.Price < pNow)
|
if (c.Price < pNow)
|
||||||
{
|
{
|
||||||
|
// Aggressive fade: Pick lowest price available
|
||||||
if ((c.Significance >= _config.EntrySigThreshold) && (c.Price < lowestEntryPrice))
|
if ((c.Significance >= _config.EntrySigThreshold) && (c.Price < lowestEntryPrice))
|
||||||
{
|
{
|
||||||
entry = c;
|
entry = c;
|
||||||
lowestEntryPrice = c.Price;
|
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;
|
sl = c;
|
||||||
highestSlPrice = c.Price;
|
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)
|
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;
|
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);
|
var result = _robot.ModifyPendingOrder(existingOrder, entry, sl, tp, ProtectionType.Absolute, null, volume);
|
||||||
if (!result.IsSuccessful)
|
if (!result.IsSuccessful)
|
||||||
{
|
{
|
||||||
// Falls Modifikation fehlschlägt (z.B. Spread), löschen wir die Order, um keine veralteten Levels zu handeln
|
|
||||||
_robot.CancelPendingOrder(existingOrder);
|
_robot.CancelPendingOrder(existingOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -820,7 +851,6 @@ namespace cAlgo.Robots
|
|||||||
if (_currentDynamicRange < _symbol.PipSize) _currentDynamicRange = _symbol.PipSize;
|
if (_currentDynamicRange < _symbol.PipSize) _currentDynamicRange = _symbol.PipSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neuen Punkt in den optimierten Calculator einspeisen
|
|
||||||
_clusterCalculator.AddPoint(new Myc.ExtremumPoint
|
_clusterCalculator.AddPoint(new Myc.ExtremumPoint
|
||||||
{
|
{
|
||||||
Price = _trendExtremum,
|
Price = _trendExtremum,
|
||||||
|
|||||||
Reference in New Issue
Block a user