diff --git a/Sources/Common/MSLib/HmaSma.cs b/Sources/Common/MSLib/HmaSma.cs new file mode 100644 index 0000000..2e8d88a --- /dev/null +++ b/Sources/Common/MSLib/HmaSma.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +namespace Myc.HmaSma +{ + /// + /// DTO representing a single row in the HMA/SMA configuration file. + /// + public class HmaSmaParameters + { + // Initialized to string.Empty to satisfy CS8618 + public string Symbol { get; set; } = string.Empty; + public string Timeframe { get; set; } = string.Empty; + public double EntrySig { get; set; } + public double SlSig { get; set; } + public int SmaBias { get; set; } + public int HmaBias { get; set; } + public int HmaCluster { get; set; } + public bool BiasFilter { get; set; } + public int BiasAvg { get; set; } + public bool DynMgmt { get; set; } + public bool TelegramOnly { get; set; } + + public override string ToString() + { + return $"{Symbol} {Timeframe}: SMA={SmaBias}, HMA={HmaBias}, Cluster={HmaCluster}"; + } + } + + /// + /// Handles parsing and caching of HMA/SMA configuration files. + /// + public class HmaSmaLoader + { + // Key: "SYMBOL_TIMEFRAME" (Normalized to UpperCase) + private readonly Dictionary _cache = new Dictionary(); + private readonly string _filePath; + + public HmaSmaLoader(string filePath) + { + _filePath = filePath; + } + + /// + /// Reads the file and populates the internal cache. + /// Throws FileNotFoundException if file is missing. + /// Returns number of successfully loaded entries. + /// + public int Load() + { + _cache.Clear(); + + if (!File.Exists(_filePath)) + throw new FileNotFoundException($"Config file not found: {_filePath}"); + + var lines = File.ReadAllLines(_filePath); + int loadedCount = 0; + + foreach (var line in lines) + { + var trimmed = line.Trim(); + if (string.IsNullOrWhiteSpace(trimmed) || trimmed.StartsWith("#")) + continue; + + // Split by whitespace (tabs or spaces) + var cols = trimmed.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + + // Ensure we have at least 11 columns based on specification + if (cols.Length < 11) + continue; + + try + { + var param = new HmaSmaParameters + { + Symbol = cols[0], + Timeframe = cols[1], + EntrySig = double.Parse(cols[2], CultureInfo.InvariantCulture), + SlSig = double.Parse(cols[3], CultureInfo.InvariantCulture), + SmaBias = int.Parse(cols[4], CultureInfo.InvariantCulture), + HmaBias = int.Parse(cols[5], CultureInfo.InvariantCulture), + HmaCluster = int.Parse(cols[6], CultureInfo.InvariantCulture), + BiasFilter = bool.Parse(cols[7]), + BiasAvg = int.Parse(cols[8], CultureInfo.InvariantCulture), + DynMgmt = bool.Parse(cols[9]), + TelegramOnly = bool.Parse(cols[10]) + }; + + string key = BuildKey(param.Symbol, param.Timeframe); + + // Overwrite duplicates if they exist lower in the file + _cache[key] = param; + loadedCount++; + } + catch (Exception) + { + // Fail silently for single bad lines, or log if logger provided. + // For library code, we skip invalid lines to ensure robustness. + continue; + } + } + + return loadedCount; + } + + /// + /// Retrieves configuration for a specific symbol and timeframe. + /// Returns null if not found. + /// + public HmaSmaParameters? GetParameters(string symbol, string timeframe) + { + string key = BuildKey(symbol, timeframe); + return _cache.TryGetValue(key, out var parameters) ? parameters : null; + } + + private static string BuildKey(string symbol, string timeframe) + { + return $"{symbol.ToUpperInvariant()}_{timeframe.ToUpperInvariant()}"; + } + } +} \ No newline at end of file diff --git a/Sources/Common/MSLib/MSLib.sln b/Sources/Common/MSLib/MSLib.sln new file mode 100644 index 0000000..79faa5c --- /dev/null +++ b/Sources/Common/MSLib/MSLib.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSLib", "MSLib.csproj", "{35379097-39C9-E3AB-CA26-4A355536E164}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {35379097-39C9-E3AB-CA26-4A355536E164}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35379097-39C9-E3AB-CA26-4A355536E164}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35379097-39C9-E3AB-CA26-4A355536E164}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35379097-39C9-E3AB-CA26-4A355536E164}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {63787C32-34FC-4DC2-99AD-98BEA2F486EC} + EndGlobalSection +EndGlobal diff --git a/Sources/Common/MSLib/SRCluster.cs b/Sources/Common/MSLib/SRCluster.cs new file mode 100644 index 0000000..fc8f9f5 --- /dev/null +++ b/Sources/Common/MSLib/SRCluster.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; + +namespace Myc +{ + public enum PointType { Peak, Trough } + + public struct ExtremumPoint + { + public double Price; + public int Index; + public PointType Type; + } + + public struct ClusterZone + { + public double Price; + public double Score; + } + + /// + /// Hochoptimierte Engine. Hält den State im Speicher, um GC-Allocations zu vermeiden. + /// Nutzt eine permanent preis-sortierte Liste für extrem schnelle Range-Abfragen. + /// + public class ClusterCalculator + { + // Permanente Buffer verhindern "new List<>" Zuweisungen pro Tick + private readonly List _priceSortedPoints; + private readonly List _candidatesBuffer; + private readonly List _resultsBuffer; + + private readonly CandidateComparer _candidateComparer = new CandidateComparer(); + + // Status für effizientes Aufräumen (Pruning) + private int _lastPruneIndex = 0; + private const int PruneInterval = 100; // Nur alle 100 Bars aufräumen spart CPU + + public ClusterCalculator(int capacity = 2000) + { + _priceSortedPoints = new List(capacity); + _candidatesBuffer = new List(capacity); + _resultsBuffer = new List(100); + } + + /// + /// Fügt einen Punkt via BinarySearch ein, um die Sortierung beizubehalten (O(log N)). + /// + public void AddPoint(ExtremumPoint point) + { + int low = 0; + int high = _priceSortedPoints.Count - 1; + + while (low <= high) + { + int mid = low + (high - low) / 2; + if (_priceSortedPoints[mid].Price < point.Price) + low = mid + 1; + else + high = mid - 1; + } + + _priceSortedPoints.Insert(low, point); + } + + /// + /// Entfernt alte Punkte. Nutzt einen effizienten "Swap-and-Cut" Algorithmus (O(N)), + /// statt langsamem RemoveAt in einer Schleife (O(N^2)). + /// + private void PruneOldPoints(int currentIndex, int decayPeriod) + { + int cutoffIndex = currentIndex - decayPeriod; + int writeIndex = 0; + + // In-Place Filterung (vermeidet Array-Copies) + for (int i = 0; i < _priceSortedPoints.Count; i++) + { + if (_priceSortedPoints[i].Index >= cutoffIndex) + { + _priceSortedPoints[writeIndex] = _priceSortedPoints[i]; + writeIndex++; + } + } + + // Den Rest der Liste abschneiden + if (writeIndex < _priceSortedPoints.Count) + { + _priceSortedPoints.RemoveRange(writeIndex, _priceSortedPoints.Count - writeIndex); + } + } + + public (List Zones, double TotalWeight) Calculate( + int currentIndex, + double currentPrice, + double range, + int decayPeriod, + int maxZones) + { + // 1. Internes Auto-Pruning (gedrosselt) + if (currentIndex - _lastPruneIndex >= PruneInterval) + { + PruneOldPoints(currentIndex, decayPeriod); + _lastPruneIndex = currentIndex; + } + + _candidatesBuffer.Clear(); + _resultsBuffer.Clear(); + + int count = _priceSortedPoints.Count; + if (count < 2) return (_resultsBuffer, 0.0); + + double totalWeightSum = 0.0; + + // 2. Sliding Window auf der sortierten Liste + // Da die Liste nach Preis sortiert ist, können wir Fenster [Center-Range, Center+Range] effizient finden. + int left = 0; + int right = 0; + + for (int i = 0; i < count; i++) + { + var centerPt = _priceSortedPoints[i]; + double centerWeight = GetWeight(centerPt, currentIndex, currentPrice, decayPeriod); + + // Tote Punkte ignorieren (Micro-Optimierung) + if (centerWeight <= 0.001) continue; + + totalWeightSum += centerWeight; + + double minPrice = centerPt.Price - range; + double maxPrice = centerPt.Price + range; + + // Fenster nach rechts erweitern + while (right < count && _priceSortedPoints[right].Price <= maxPrice) + { + right++; + } + + // Fenster von links verkleinern + while (left < right && _priceSortedPoints[left].Price < minPrice) + { + left++; + } + + // Gewichtung im Fenster summieren + double localScore = 0; + for (int k = left; k < right; k++) + { + localScore += GetWeight(_priceSortedPoints[k], currentIndex, currentPrice, decayPeriod); + } + + if (localScore > 0.01) + { + _candidatesBuffer.Add(new ClusterZone + { + Price = centerPt.Price, + Score = localScore + }); + } + } + + // 3. Kandidaten sortieren (Allocation Free via Comparer) + _candidatesBuffer.Sort(_candidateComparer); + + // 4. Überlappungen filtern + int candCount = _candidatesBuffer.Count; + for (int i = 0; i < candCount; i++) + { + if (_resultsBuffer.Count >= maxZones) break; + + var cand = _candidatesBuffer[i]; + bool overlaps = false; + + int resCount = _resultsBuffer.Count; + for (int j = 0; j < resCount; j++) + { + if (Math.Abs(_resultsBuffer[j].Price - cand.Price) < range) + { + overlaps = true; + break; + } + } + + if (!overlaps) + { + _resultsBuffer.Add(cand); + } + } + + return (_resultsBuffer, totalWeightSum); + } + + private double GetWeight(ExtremumPoint p, int currentIndex, double currentPrice, int decayPeriod) + { + double age = currentIndex - p.Index; + if (age > decayPeriod) return 0.0; + + double w = 1.0 - (age / decayPeriod); + if (w < 0) return 0.0; + + // Role Reversal Logic + if ((p.Type == PointType.Peak && p.Price < currentPrice) || + (p.Type == PointType.Trough && p.Price > currentPrice)) + { + w *= 2.0; + } + return w; + } + + private class CandidateComparer : IComparer + { + public int Compare(ClusterZone x, ClusterZone y) => y.Score.CompareTo(x.Score); + } + } +} \ No newline at end of file diff --git a/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.dll b/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.dll index acf6f9a..cd7721a 100644 Binary files a/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.dll and b/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.dll differ diff --git a/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.pdb b/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.pdb index d1c06a6..227563f 100644 Binary files a/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.pdb and b/Sources/Common/MSLib/bin/Debug/net6.0/MSLib.pdb differ diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.GeneratedMSBuildEditorConfig.editorconfig b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.GeneratedMSBuildEditorConfig.editorconfig index 4db8300..2387edc 100644 --- a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.GeneratedMSBuildEditorConfig.editorconfig +++ b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = MSLib -build_property.ProjectDir = C:\Users\Brummel\Documents\cAlgo\Sources\Common\MSLib\ +build_property.ProjectDir = c:\Users\Brummel\Documents\cAlgo\Sources\Common\MSLib\ diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.assets.cache b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.assets.cache index d7e1628..a98a7ac 100644 Binary files a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.assets.cache and b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.assets.cache differ diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.CoreCompileInputs.cache b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.CoreCompileInputs.cache index 5a1c6bb..9bcdebf 100644 --- a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.CoreCompileInputs.cache +++ b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -375eb7427a13a6a1a036f49ce73cc2a66452e118 +3ad9fabd4c4d10fabf7ae747a073d85bece381b1 diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.FileListAbsolute.txt b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.FileListAbsolute.txt index 71d3a6b..e94742d 100644 --- a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.FileListAbsolute.txt +++ b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.csproj.FileListAbsolute.txt @@ -10,3 +10,15 @@ C:\Users\Brummel\Documents\cAlgo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.dll C:\Users\Brummel\Documents\cAlgo\Sources\Common\MSLib\obj\Debug\net6.0\refint\MSLib.dll C:\Users\Brummel\Documents\cAlgo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.pdb C:\Users\Brummel\Documents\cAlgo\Sources\Common\MSLib\obj\Debug\net6.0\ref\MSLib.dll +t:\cTrader-Algo\Sources\Common\MSLib\bin\Debug\net6.0\MSLib.deps.json +t:\cTrader-Algo\Sources\Common\MSLib\bin\Debug\net6.0\MSLib.dll +t:\cTrader-Algo\Sources\Common\MSLib\bin\Debug\net6.0\MSLib.pdb +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.csproj.AssemblyReference.cache +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.GeneratedMSBuildEditorConfig.editorconfig +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.AssemblyInfoInputs.cache +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.AssemblyInfo.cs +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.csproj.CoreCompileInputs.cache +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.dll +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\refint\MSLib.dll +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\MSLib.pdb +t:\cTrader-Algo\Sources\Common\MSLib\obj\Debug\net6.0\ref\MSLib.dll diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.dll b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.dll index acf6f9a..cd7721a 100644 Binary files a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.dll and b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.dll differ diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.pdb b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.pdb index d1c06a6..227563f 100644 Binary files a/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.pdb and b/Sources/Common/MSLib/obj/Debug/net6.0/MSLib.pdb differ diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/ref/MSLib.dll b/Sources/Common/MSLib/obj/Debug/net6.0/ref/MSLib.dll index 00ff9d3..5a0174e 100644 Binary files a/Sources/Common/MSLib/obj/Debug/net6.0/ref/MSLib.dll and b/Sources/Common/MSLib/obj/Debug/net6.0/ref/MSLib.dll differ diff --git a/Sources/Common/MSLib/obj/Debug/net6.0/refint/MSLib.dll b/Sources/Common/MSLib/obj/Debug/net6.0/refint/MSLib.dll index 00ff9d3..5a0174e 100644 Binary files a/Sources/Common/MSLib/obj/Debug/net6.0/refint/MSLib.dll and b/Sources/Common/MSLib/obj/Debug/net6.0/refint/MSLib.dll differ diff --git a/Sources/Common/MSLib/obj/MSLib.csproj.nuget.dgspec.json b/Sources/Common/MSLib/obj/MSLib.csproj.nuget.dgspec.json index 103cb00..67ecc79 100644 --- a/Sources/Common/MSLib/obj/MSLib.csproj.nuget.dgspec.json +++ b/Sources/Common/MSLib/obj/MSLib.csproj.nuget.dgspec.json @@ -1,17 +1,17 @@ { "format": 1, "restore": { - "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj": {} + "c:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj": {} }, "projects": { - "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj": { + "c:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj": { "version": "1.0.0", "restore": { - "projectUniqueName": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj", + "projectUniqueName": "c:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj", "projectName": "MSLib", - "projectPath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj", + "projectPath": "c:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj", "packagesPath": "C:\\Users\\Brummel\\.nuget\\packages\\", - "outputPath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\obj\\", + "outputPath": "c:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\obj\\", "projectStyle": "PackageReference", "configFilePaths": [ "C:\\Users\\Brummel\\AppData\\Roaming\\NuGet\\NuGet.Config" diff --git a/Sources/Common/MSLib/obj/project.nuget.cache b/Sources/Common/MSLib/obj/project.nuget.cache index 701bd15..caa3c6c 100644 --- a/Sources/Common/MSLib/obj/project.nuget.cache +++ b/Sources/Common/MSLib/obj/project.nuget.cache @@ -1,8 +1,8 @@ { "version": 2, - "dgSpecHash": "Oo9DgV2PMMwBLALF97djBTxT9Wgbo3xT86Zo8aWAwrxLBxF4zrxrwtxR5/TCIXpFczNFbEDKftQZxvjl9Y6BHQ==", + "dgSpecHash": "QUjfNVpQVakrJnZ6ikXioBqXAAQSJGbdswDDGq/346m+iKBsBuuIGU7p4bNk4ScgIgCDP9J76j1QkbDrbUrkrg==", "success": true, - "projectFilePath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj", + "projectFilePath": "c:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Common\\MSLib\\MSLib.csproj", "expectedPackageFiles": [], "logs": [] } \ No newline at end of file diff --git a/Sources/Indicators/Candlestick Patterns DEMO.algo b/Sources/Indicators/Candlestick Patterns DEMO.algo deleted file mode 100644 index 84ced26..0000000 Binary files a/Sources/Indicators/Candlestick Patterns DEMO.algo and /dev/null differ diff --git a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO.sln b/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO.sln deleted file mode 100644 index b7a72d8..0000000 --- a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Candlestick Patterns DEMO", "Candlestick Patterns DEMO\Candlestick Patterns DEMO.csproj", "{B9F710D0-7DD5-4E04-B2E9-98C1878E7674}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B9F710D0-7DD5-4E04-B2E9-98C1878E7674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B9F710D0-7DD5-4E04-B2E9-98C1878E7674}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B9F710D0-7DD5-4E04-B2E9-98C1878E7674}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B9F710D0-7DD5-4E04-B2E9-98C1878E7674}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Candlestick Patterns DEMO.cs b/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Candlestick Patterns DEMO.cs deleted file mode 100644 index 0b8fa89..0000000 --- a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Candlestick Patterns DEMO.cs +++ /dev/null @@ -1,504 +0,0 @@ -using System; -using System.IO; -using cAlgo.API; -using cAlgo.API.Internals; -using cAlgo.API.Indicators; -using cAlgo.Indicators; - -namespace cAlgo -{ - [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FileSystem)] - public class CP : Indicator - { - #region Parameters - - [Parameter("Show names", DefaultValue = false)] - public bool Name_Status { get; set; } - - [Parameter("Show more info", DefaultValue = true)] - public bool Add_info { get; set; } - - [Parameter("Show Doji", DefaultValue = true)] - public bool Show_Doji { get; set; } - - [Parameter("Show Hammer", DefaultValue = true)] - public bool Show_Hammer { get; set; } - - [Parameter("MACD Long Cycle", DefaultValue = 26)] - public int LongCycle { get; set; } - - [Parameter("MACD Short Cycle", DefaultValue = 12)] - public int ShortCycle { get; set; } - - [Parameter("MACD Signal Periods", DefaultValue = 9)] - public int Periods { get; set; } - - [Parameter("Doji", DefaultValue = "✝")] - public string Doji_s { get; set; } - [Parameter("Hammer", DefaultValue = "☨")] - public string Hammer_s { get; set; } - - #endregion Parameters - - private MacdHistogram macd; - - private const VerticalAlignment vAlign = VerticalAlignment.Top; - private const HorizontalAlignment hAlign = HorizontalAlignment.Center; - - private const double n = 0.618; - - private const string UpArrow = "▲"; - private const string DownArrow = "▼"; - - private string Pattern_name; - - private double offset; - - private struct Candle - { - #region Data - - public double High; - public double Close; - public double Open; - public double Low; - - #endregion Data - - #region Functions - - public bool IsFallCandle() - { - if (Close < Open) - return true; - else - return false; - } - public bool IsRiseCandle() - { - if (Open < Close) - return true; - else - return false; - } - - public double Median() - { - return (High + Low) / 2; - } - - #endregion Functions - } - - private enum PatternType : int - { - Doji = 1, - Hammer = 2 - } - - protected override void Initialize() - { - macd = Indicators.MacdHistogram(MarketSeries.Close, LongCycle, ShortCycle, Periods); - offset = Symbol.PipSize * 5; - } - - private void DrawText(int index, int _Type) - { - var high = MarketSeries.High[index]; - var low = MarketSeries.Low[index]; - - int x = index; - - double h_y = high + offset; - double h_d_y = h_y + offset * 2.5; - double h_t_y = h_d_y + offset; - - double l_y = low - offset * 2.5; - double l_d_y = l_y - offset; - - - if (TimeFrame == TimeFrame.Minute) - { - h_y = high + offset / 2; - h_d_y = h_y + offset / 2; - h_t_y = h_d_y + offset; - - l_y = low - offset / 2; - l_d_y = l_y - offset / 2; - } - - - - if (TimeFrame == TimeFrame.Minute15) - { - h_y = high + offset / 1.5; - h_d_y = h_y + offset; - h_t_y = h_d_y + offset; - - l_y = low - offset * 1.5; - l_d_y = l_y - offset * 1.1; - } - - - if (TimeFrame == TimeFrame.Hour) - { - h_y = high + offset; - h_d_y = h_y + offset * 3; - h_t_y = h_d_y + offset; - - l_y = low - offset * 3; - l_d_y = l_y - offset * 3; - } - - if (TimeFrame == TimeFrame.Hour4) - { - h_y = high + offset; - h_d_y = h_y + offset * 5; - h_t_y = h_d_y + offset; - - l_y = low - offset * 5; - l_d_y = l_y - offset * 5; - } - - if (TimeFrame == TimeFrame.Daily) - { - h_y = high + offset * 3; - h_d_y = h_y + offset * 12; - h_t_y = h_d_y + offset; - - l_y = low - offset * 12; - l_d_y = l_y - offset * 12; - } - - if (TimeFrame == TimeFrame.Weekly) - { - h_y = high + offset * 6; - h_d_y = h_y + offset * 24; - h_t_y = h_d_y + offset; - - l_y = low - offset * 24; - l_d_y = l_y - offset * 24; - } - - if (TimeFrame == TimeFrame.Monthly) - { - h_y = high + offset * 24; - h_d_y = h_y + offset * 64; - h_t_y = h_d_y + offset; - - l_y = low - offset * 64; - l_d_y = l_y - offset * 64; - } - - string f_ObjName; - string s_ObjName; - - switch (_Type) - { - case (int)PatternType.Doji: - - f_ObjName = string.Format("Doji {0}", index); - s_ObjName = string.Format("Doji | {0}", index); - - ChartObjects.DrawText(f_ObjName, "Doji", x, h_d_y, vAlign, hAlign, Colors.White); - ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White); - - break; - - case (int)PatternType.Hammer: - - f_ObjName = string.Format("Hammer {0}", index); - s_ObjName = string.Format("Hammer | {0}", index); - - ChartObjects.DrawText(f_ObjName, "Hammer", x, h_d_y, vAlign, hAlign, Colors.White); - ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White); - - break; - - } - } - - private void DrawSymbols(int index, int _Type) - { - var high = MarketSeries.High[index]; - var low = MarketSeries.Low[index]; - - int x = index; - - double h_y = high + offset; - double h_d_y = h_y + offset * 2.5; - double h_t_y = h_d_y + offset; - - double l_y = low - offset * 2.5; - double l_d_y = l_y - offset; - - - if (TimeFrame == TimeFrame.Minute) - { - h_y = high + offset / 2; - h_d_y = h_y + offset / 2; - h_t_y = h_d_y + offset; - - l_y = low - offset / 2; - l_d_y = l_y - offset / 2; - } - - - - if (TimeFrame == TimeFrame.Minute15) - { - h_y = high + offset / 1.5; - h_d_y = h_y + offset; - h_t_y = h_d_y + offset; - - l_y = low - offset * 1.5; - l_d_y = l_y - offset * 1.1; - } - - - if (TimeFrame == TimeFrame.Hour) - { - h_y = high + offset; - h_d_y = h_y + offset * 3; - h_t_y = h_d_y + offset; - - l_y = low - offset * 3; - l_d_y = l_y - offset * 3; - } - - if (TimeFrame == TimeFrame.Hour4) - { - h_y = high + offset; - h_d_y = h_y + offset * 5; - h_t_y = h_d_y + offset; - - l_y = low - offset * 5; - l_d_y = l_y - offset * 5; - } - - if (TimeFrame == TimeFrame.Daily) - { - h_y = high + offset * 3; - h_d_y = h_y + offset * 12; - h_t_y = h_d_y + offset; - - l_y = low - offset * 12; - l_d_y = l_y - offset * 12; - } - - if (TimeFrame == TimeFrame.Weekly) - { - h_y = high + offset * 6; - h_d_y = h_y + offset * 24; - h_t_y = h_d_y + offset; - - l_y = low - offset * 24; - l_d_y = l_y - offset * 24; - } - - if (TimeFrame == TimeFrame.Monthly) - { - h_y = high + offset * 24; - h_d_y = h_y + offset * 64; - h_t_y = h_d_y + offset; - - l_y = low - offset * 64; - l_d_y = l_y - offset * 64; - } - - string f_ObjName; - string s_ObjName; - - switch (_Type) - { - case (int)PatternType.Doji: - - f_ObjName = string.Format("Doji {0}", index); - s_ObjName = string.Format("Doji | {0}", index); - - ChartObjects.DrawText(f_ObjName, Doji_s, x, h_d_y, vAlign, hAlign, Colors.White); - ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White); - - break; - - case (int)PatternType.Hammer: - - f_ObjName = string.Format("Hammer {0}", index); - s_ObjName = string.Format("Hammer | {0}", index); - - ChartObjects.DrawText(f_ObjName, Hammer_s, x, h_d_y, vAlign, hAlign, Colors.DarkOrange); - ChartObjects.DrawText(s_ObjName, "\n|", x, h_y, vAlign, hAlign, Colors.White); - - break; - - } - } - - - private bool Size(Candle candle) - { - if (candle.IsFallCandle()) - { - if ((candle.Open - candle.Close) > (candle.High - candle.Low) * n) - return true; - } - else if (candle.IsRiseCandle()) - { - if ((candle.Close - candle.Open) > (candle.High - candle.Low) * n) - return true; - } - - return false; - } - - private void Text_Info(int index, string Pattern_name) - { - if (Add_info == true) - { - - #region Pattern - - ChartObjects.DrawText("PATTERN", "LAST PATTERN : " + Pattern_name, StaticPosition.TopLeft, Colors.White); - - #endregion Pattern - - #region MACD - - if (MACD_Info(index) == "UP") - { - ChartObjects.DrawText("MACD", "\nMACD : ", StaticPosition.TopLeft, Colors.White); - ChartObjects.DrawText("ARROW MACD", "\n\t" + UpArrow, StaticPosition.TopLeft, Colors.DodgerBlue); - - } - else if (MACD_Info(index) == "DOWN") - { - ChartObjects.DrawText("MACD", "\nMACD : ", StaticPosition.TopLeft, Colors.White); - ChartObjects.DrawText("ARROW MACD", "\n\t" + DownArrow, StaticPosition.TopLeft, Colors.Crimson); - } - - #endregion MACD - - } - } - - private string MACD_Info(int index) - { - if (macd.Histogram[index] > 0) - { - return "UP"; - } - - if (macd.Histogram[index] < 0) - { - return "DOWN"; - } - return "ZERO"; - } - - - private bool Doji(Candle candle) - { - - if (candle.IsFallCandle() & (candle.Close != candle.Low)) - { - if ((candle.High - candle.Low) > 12 * (candle.Open - candle.Close)) - return true; - } - if (candle.IsRiseCandle() & (candle.Close != candle.High)) - { - if ((candle.High - candle.Low) > 12 * (candle.Close - candle.Open)) - return true; - } - return false; - } - - private bool Hammer(Candle candle) - { - if (candle.IsFallCandle() & (candle.Close == candle.Low)) - { - if ((candle.Median() > candle.Open) & (candle.Median() > candle.Close)) - { - if ((candle.Median() - candle.Low) > 1.618 * (candle.Open - candle.Close)) - return true; - } - } - - if (candle.IsRiseCandle() & (candle.Close == candle.High)) - { - if ((candle.Median() < candle.Open) & (candle.Median() < candle.Close)) - { - if ((candle.High - candle.Median()) > 1.618 * (candle.Close - candle.Open)) - return true; - } - } - - return false; - } - - public override void Calculate(int index) - { - #region structs - - Candle candle = new Candle(); - - #endregion structs - - #region variables - - int candle_index = 0; - - candle.High = MarketSeries.High.Last(candle_index); - candle.Open = MarketSeries.Open.Last(candle_index); - candle.Close = MarketSeries.Close.Last(candle_index); - candle.Low = MarketSeries.Low.Last(candle_index); - - #endregion variables - - #region Patterns - - // Doji - - if (Doji(candle)) - { - if (Show_Doji == true) - { - Pattern_name = "Doji"; - if (Name_Status == true) - { - DrawText(index, (int)PatternType.Doji); - } - else - { - DrawSymbols(index, (int)PatternType.Doji); - } - } - } - - //Hammer - - if (Hammer(candle)) - { - if (Show_Hammer == true) - { - Pattern_name = "Hammer"; - if (Name_Status == true) - { - DrawText(index, (int)PatternType.Hammer); - } - else - { - DrawSymbols(index, (int)PatternType.Hammer); - } - } - } - - #endregion Patterns - - #region Text - - Text_Info(index, Pattern_name); - - #endregion Text - } - } -} diff --git a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Candlestick Patterns DEMO.csproj b/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Candlestick Patterns DEMO.csproj deleted file mode 100644 index bfeb7d6..0000000 --- a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Candlestick Patterns DEMO.csproj +++ /dev/null @@ -1,58 +0,0 @@ - - - - - Debug - AnyCPU - {B9F710D0-7DD5-4E04-B2E9-98C1878E7674} - {DD87C1B2-3799-4CA2-93B6-5288EE928820};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - cAlgo - Candlestick Patterns DEMO - v4.0 - Client - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - False - ..\..\..\..\API\cAlgo.API.dll - - - - - - - - - \ No newline at end of file diff --git a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Properties/AssemblyInfo.cs b/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Properties/AssemblyInfo.cs deleted file mode 100644 index 814d8b2..0000000 --- a/Sources/Indicators/Candlestick Patterns DEMO/Candlestick Patterns DEMO/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Candlestick Patterns DEMO")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyProduct("Candlestick Patterns DEMO")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("35f19c43-c7cc-4f53-b8e0-61caaf9cd8e8")] - -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Sources/Indicators/Correlation with angle v1.1.algo b/Sources/Indicators/Correlation with angle v1.1.algo deleted file mode 100644 index 4f167e9..0000000 Binary files a/Sources/Indicators/Correlation with angle v1.1.algo and /dev/null differ diff --git a/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1.sln b/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1.sln deleted file mode 100644 index f4ad4f5..0000000 --- a/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30011.22 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correlation with angle v1.1", "Correlation with angle v1.1\Correlation with angle v1.1.csproj", "{0e2c43ed-8f8d-446b-848e-ed1fe9ef49a2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0e2c43ed-8f8d-446b-848e-ed1fe9ef49a2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0e2c43ed-8f8d-446b-848e-ed1fe9ef49a2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0e2c43ed-8f8d-446b-848e-ed1fe9ef49a2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0e2c43ed-8f8d-446b-848e-ed1fe9ef49a2}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1/Correlation with angle v1.1.cs b/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1/Correlation with angle v1.1.cs deleted file mode 100644 index 901975e..0000000 --- a/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1/Correlation with angle v1.1.cs +++ /dev/null @@ -1,249 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using cAlgo.API; -using cAlgo.API.Indicators; -using cAlgo.API.Internals; -using cAlgo.Indicators; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace cAlgo -{ - [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] - public class Correlationwithanglev11 : Indicator - { - [Parameter("Symbol Selection Method", DefaultValue = SymbolSelectionMethodType.SymbolList, Group = "Symbole Choice \n(Uncomment code for more than 6 Symbole)")] - public SymbolSelectionMethodType SymbolSelectionMethod { get; set; } - public enum SymbolSelectionMethodType - { - WatchList, - SymbolList - } - - [Parameter("Symbol List 1 / WatchList Name 1:", DefaultValue = "XAUUSD", Group = "Symbol Management (5 Symbol / List Maximum)")] - public string TradedSymbols1 { get; set; } - [Parameter("Symbol List 2 / WatchList Name 2:", DefaultValue = "SpotBrent", Group = "Symbol Management (5 Symbol / List Maximum)")] - public string TradedSymbols2 { get; set; } - - [Parameter("ExtraLevel", DefaultValue = 50, Group = "Angle Level")] - public int ExtraLevel { get; set; } - - [Parameter("PeriodA ngle", DefaultValue = 14, Group = "Angle Setting")] - public int PeriodAngle { get; set; } - [Parameter("Loockback Periods Angle", DefaultValue = 1, Group = "Angle Setting")] - public int LookbackAngle { get; set; } - [Parameter("Price Smooth Type", DefaultValue = MovingAverageType.Weighted, Group = "Angle Setting")] - public MovingAverageType MaTypeAngle { get; set; } - - [Parameter("History Diff Angle", DefaultValue = 1, Group = "Base Setting")] - public int HistoryTextLookback { get; set; } - - [Parameter("ShowSignals", DefaultValue = true, Group = "Histogram Setting")] - public bool ShowSignal { get; set; } - [Parameter("Sensibility Histogram", DefaultValue = 0.3, Group = "Histogram Setting")] - public double SensibilityHisto { get; set; } - - [Parameter("Signal Periods", DefaultValue = 55, Group = "Histogram Setting")] - public int SignalPeriods { get; set; } - [Parameter("Price Smooth Type", DefaultValue = MovingAverageType.Weighted, Group = "Histogram Setting")] - public MovingAverageType MaTypeSignal { get; set; } - - [Output("List 1 : Symb n° 1", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN1 { get; set; } - [Output("List 1 : Symb n° 2", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN2 { get; set; } - [Output("List 1 : Symb n° 3", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN3 { get; set; } - [Output("List 1 : Symb n° 4", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN4 { get; set; } - [Output("List 1 : Symb n° 5", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN5 { get; set; } - - [Output("List 2 : Symb n° 6", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN6 { get; set; } - [Output("List 2 : Symb n° 7", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN7 { get; set; } - [Output("List 2 : Symb n° 8", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN8 { get; set; } - [Output("List 2 : Symb n° 9", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN9 { get; set; } - [Output("List 2 : Symb n° 10", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN10 { get; set; } - - [Output("LevelHigh", LineColor = "Gold", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries LevelHigh { get; set; } - [Output("LevelMid", LineColor = "White", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries LevelMid { get; set; } - [Output("LevelLow", LineColor = "Gold", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries LevelLow { get; set; } - - private MovingAverage[] angleIndex1, angleIndex2; - private AverageTrueRange[] atrIndex1, atrIndex2; - - private Symbol[] TradeList1, TradeList2; - private Bars[] bars1, bars2; - private IndicatorDataSeries[] ResPaireWatchlist1, ResPaireWatchlist2; - private int[] indexBars1, indexBars2; - - protected override void Initialize() - { - if (SymbolSelectionMethod == SymbolSelectionMethodType.WatchList) - { - // Get the trade list from the watchlist 1 provided by the user - foreach (Watchlist w in Watchlists) - { - if (w.Name == TradedSymbols1) - { - TradeList1 = Symbols.GetSymbols(w.SymbolNames.ToArray()); - } - } - // Get the trade list from the watchlist 2 provided by the user - foreach (Watchlist w in Watchlists) - { - if (w.Name == TradedSymbols2) - { - TradeList2 = Symbols.GetSymbols(w.SymbolNames.ToArray()); - } - } - Print(); - Print("Watchlist 1 : [ {0} ] = {1} symbols || Watchlist 2 : [ {2} ] = {3} symbols", Bars.ToString().Substring(0, 3), TradeList1.Length, Bars.ToString().Substring(3, 3), TradeList2.Length); - Print(); - } - else if (SymbolSelectionMethod == SymbolSelectionMethodType.SymbolList) - { - // Get the trade list from the SymbolList provided by the user - string[] SymbolList = TradedSymbols1.Split(' '); - TradeList1 = Symbols.GetSymbols(SymbolList); - - // Get the trade list from the SymbolList provided by the user - string[] SymbolList2 = TradedSymbols2.Split(' '); - TradeList2 = Symbols.GetSymbols(SymbolList2); - } - - //Create Indicators for Watchlist 1 - angleIndex1 = new MovingAverage[TradeList1.Length]; - atrIndex1 = new AverageTrueRange[TradeList1.Length]; - bars1 = new Bars[TradeList1.Length]; - indexBars1 = new int[TradeList1.Length]; - ResPaireWatchlist1 = new IndicatorDataSeries[TradeList1.Length]; - - //Create Indicators for Watchlist 2 - angleIndex2 = new MovingAverage[TradeList2.Length]; - atrIndex2 = new AverageTrueRange[TradeList2.Length]; - bars2 = new Bars[TradeList2.Length]; - indexBars2 = new int[TradeList2.Length]; - ResPaireWatchlist2 = new IndicatorDataSeries[TradeList2.Length]; - - //Initialize Indicators for Watchlist 1 - int i = 0; - foreach (var symbol in TradeList1) - { - Print("Watchlist : [ {0} ] => {1} symbols = {2}", Bars.SymbolName, (i + 1), symbol.Name); - //Load bars of watchlist 1 - bars1[i] = MarketData.GetBars(TimeFrame, symbol.Name); - while (bars1[i].OpenTimes[0] > Bars.OpenTimes[0]) - bars1[i].LoadMoreHistory(); - - //Load Futurs DataSerie watchlist 1 (calculation in Calculate(int index)) - ResPaireWatchlist1[i] = CreateDataSeries(); - - //Load Indicators watchlist 1 - - atrIndex1[i] = Indicators.AverageTrueRange(bars1[i], 500, MovingAverageType.Simple); - angleIndex1[i] = Indicators.MovingAverage(bars1[i].ClosePrices, PeriodAngle, MaTypeAngle); - i++; - } - //Initialize Indicators for Watchlist 2 - Print(); - - int j = 0; - foreach (var symbol2 in TradeList2) - { - Print("Watchlist : [ {0} ] => {1} symbols = {2}", Bars.SymbolName, (j + 1), symbol2.Name); - //Load bars of watchlist 2 - bars2[j] = MarketData.GetBars(TimeFrame, symbol2.Name); - while (bars2[j].OpenTimes[0] > Bars.OpenTimes[0]) - bars2[j].LoadMoreHistory(); - - //Load Futurs DataSerie watchlist 2 (calculation in Calculate(int index)) - ResPaireWatchlist2[j] = CreateDataSeries(); - - //Load Indicators watchlist 2 - atrIndex2[j] = Indicators.AverageTrueRange(bars2[j], 500, MovingAverageType.Simple); - angleIndex2[j] = Indicators.MovingAverage(bars2[j].ClosePrices, PeriodAngle, MaTypeAngle); - j++; - } - Print(); - } - public override void Calculate(int index) - { - //Plot Static level on indicator - LevelHigh[index] = ExtraLevel; - LevelMid[index] = 0; - LevelLow[index] = 0 - ExtraLevel; - - if (index < PeriodAngle) - return; - - //Calculate angle by symbol list 1 - for (int i = 0; i < TradeList1.Length; i++) - { - indexBars1[i] = bars1[i].OpenTimes.GetIndexByTime(Bars.OpenTimes[index]); - ResPaireWatchlist1[i][index] = GetCalculationAngle(angleIndex1[i].Result[indexBars1[i]], angleIndex1[i].Result[indexBars1[i] - LookbackAngle], atrIndex1[i].Result[indexBars1[i]]); - } - - //Remove Static text of difference into index and index - HistoryTextLookback - if (IndicatorArea.FindAllObjects(ChartObjectType.Text).Length > 0) - IndicatorArea.RemoveAllObjects(); - //Calculate difference into index and index - HistoryTextLookback list 1 - for (int i = 0; i < TradeList1.Length; i++) - IndicatorArea.DrawText((TradeList1[i]).ToString() + index, TradeList1[i] + " : " + ResPaireWatchlist1[i][index].ToString("F2"), index + 2, double.IsNaN(ResPaireWatchlist1[i][index]) ? 0 : ResPaireWatchlist1[i][index], ResPaireWatchlist1[i][index] > ResPaireWatchlist1[i][index - HistoryTextLookback] ? Color.Lime : Color.Red); - - //Output the result like symbolList number != output number list 1 - int j = TradeList1.Length - 1; - SymbN1[index] = ResPaireWatchlist1[0 < j ? 0 : j][index]; - SymbN2[index] = ResPaireWatchlist1[1 < j ? 1 : j][index]; - SymbN3[index] = ResPaireWatchlist1[2 < j ? 2 : j][index]; - SymbN4[index] = ResPaireWatchlist1[3 < j ? 3 : j][index]; - SymbN5[index] = ResPaireWatchlist1[4 < j ? 4 : j][index]; - - //Calculate angle by symbol list 2 - for (int i = 0; i < TradeList2.Length; i++) - { - indexBars2[i] = bars2[i].OpenTimes.GetIndexByTime(Bars.OpenTimes[index]); - ResPaireWatchlist2[i][index] = GetCalculationAngle(angleIndex2[i].Result[indexBars2[i]], angleIndex2[i].Result[indexBars2[i] - LookbackAngle], atrIndex2[i].Result[indexBars2[i]]); - } - - //Calculate difference into index and index - HistoryTextLookback list 2 - for (int i = 0; i < TradeList2.Length; i++) - IndicatorArea.DrawText((TradeList2[i]).ToString() + index, TradeList2[i] + " : " + ResPaireWatchlist2[i][index].ToString("F2"), index + 2, double.IsNaN(ResPaireWatchlist2[i][index]) ? 0 : ResPaireWatchlist2[i][index], ResPaireWatchlist2[i][index] > ResPaireWatchlist2[i][index - HistoryTextLookback] ? Color.Lime : Color.Red); - - //Output the result like symbolList number != output number list 2 - int k = TradeList2.Length - 1; - SymbN6[index] = ResPaireWatchlist2[0 < k ? 0 : k][index]; - SymbN7[index] = ResPaireWatchlist2[1 < k ? 1 : k][index]; - SymbN8[index] = ResPaireWatchlist2[2 < k ? 2 : k][index]; - SymbN9[index] = ResPaireWatchlist2[3 < k ? 3 : k][index]; - SymbN10[index] = ResPaireWatchlist2[4 < k ? 4 : k][index]; - - } - - //Function for angle calculation with atr normalization - public double GetCalculationAngle(double priceSmooth, double priceSmoothLoockBack, double atr) - { - var _momentumpositive = priceSmooth - priceSmoothLoockBack; - var _momentumnegative = priceSmoothLoockBack - priceSmooth; - var _momentum = priceSmooth > priceSmoothLoockBack - ? _momentumpositive / atr - : _momentumnegative / atr; - var _hypothenuse = Math.Sqrt((_momentum * _momentum) + (LookbackAngle * LookbackAngle)); - var _cos = (LookbackAngle / _hypothenuse); - var _angle = priceSmooth > priceSmoothLoockBack - ? (0 + (Math.Acos(_cos) * 100)) - : (0 - (Math.Acos(_cos) * 100)); - return _angle; - } - } -} diff --git a/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1/Correlation with angle v1.1.csproj b/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1/Correlation with angle v1.1.csproj deleted file mode 100644 index 4040d8c..0000000 --- a/Sources/Indicators/Correlation with angle v1.1/Correlation with angle v1.1/Correlation with angle v1.1.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - net6.0 - - - - - - diff --git a/Sources/Indicators/Correlation with angle v1.1/msAngle of MultiSymbol.cs b/Sources/Indicators/Correlation with angle v1.1/msAngle of MultiSymbol.cs deleted file mode 100644 index c1cd75e..0000000 --- a/Sources/Indicators/Correlation with angle v1.1/msAngle of MultiSymbol.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using cAlgo.API; -using cAlgo.API.Indicators; -using cAlgo.API.Internals; -using cAlgo.Indicators; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace cAlgo -{ - //[Cloud("Fast Smooth", "Slow Smooth", FirstColor = "Green", SecondColor = "Red", Opacity = 0.1)] - [Levels(0)] - [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] - public class AngleOfMultiSymbol : Indicator - { - [Parameter("Symbol Selection Method", DefaultValue = SymbolSelectionMethodType.SymbolList, Group = "Symbole Choice \n(Uncomment code for more than 6 Symbole)")] - public SymbolSelectionMethodType SymbolSelectionMethod { get; set; } - [Parameter("Symbol List", DefaultValue = "EURUSD GBPUSD AUDUSD USDCHF", Group = "Symbole Choice \n(Uncomment code for more than 6 Symbole)")] - public string TradedSymbols { get; set; } - [Parameter("Watchlist Name", DefaultValue = "My Watchlist", Group = "Symbole Choice \n(Uncomment code for more than 6 Symbole)")] - public string WatchlistName { get; set; } - - public enum SymbolSelectionMethodType - { - CurrentChart, - SymbolList, - WatchList - } - - [Parameter("History Diff Angle", DefaultValue = 1, Group = "Base Setting")] - public int HistoryTextLookback { get; set; } - [Parameter("Tf", DefaultValue = "Hour1", Group = "Base Setting")] - public TimeFrame Tf { get; set; } - [Parameter("Price Smooth Period (255)", DefaultValue = 255, Group = "Angle Setting")] - public int SmoothPeriods { get; set; } - [Parameter("Price Smooth Type", DefaultValue = MovingAverageType.Weighted, Group = "Angle Setting")] - public MovingAverageType MaType { get; set; } - [Parameter("Loockback Periods Angle", DefaultValue = 1, Group = "Angle Setting")] - public int LookbackPeriodsAngle { get; set; } - [Parameter("Sensitivity (1.0)", DefaultValue = 1, Group = "Angle Setting")] - public double Sensitivity { get; set; } - - [Output("Symb n° 1", LineColor = "White", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN1 { get; set; } - [Output("Symb n° 2", LineColor = "Lime", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN2 { get; set; } - [Output("Symb n° 3", LineColor = "Green", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN3 { get; set; } - [Output("Symb n° 4", LineColor = "DeepSkyBlue", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN4 { get; set; } - [Output("Symb n° 5", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN5 { get; set; } - [Output("Symb n° 6", LineColor = "Magenta", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN6 { get; set; } - - /*Uncomment For more Symbole on the chart - [Output("Symb n° 7", LineColor = "Green", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN7 { get; set; } - [Output("Symb n° 8", LineColor = "DeepSkyBlue", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN8 { get; set; } - [Output("Symb n° 9", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN9 { get; set; } - [Output("Symb n° 10", LineColor = "Magenta", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 1)] - public IndicatorDataSeries SymbN10 { get; set; } - */ - - private MovingAverage[] ma; - private AverageTrueRange[] atr; - - private Symbol[] TradeList; - private Bars[] bars; - private IndicatorDataSeries[] Sources, ResSymbol; - private int[] indexBars; - - protected override void Initialize() - { - if (SymbolSelectionMethod == SymbolSelectionMethodType.WatchList) - { - // Get the trade list from the watchlist provided by the user - foreach (Watchlist w in Watchlists) - { - if (w.Name == WatchlistName) - { - TradeList = Symbols.GetSymbols(w.SymbolNames.ToArray()); - } - } - } - else if (SymbolSelectionMethod == SymbolSelectionMethodType.SymbolList) - { - // Get the trade list from the sysmbol list provided by the user - string[] SymbolList = TradedSymbols.ToUpper().Split(' '); - - TradeList = Symbols.GetSymbols(SymbolList); - } - else - { - TradeList = new Symbol[1]; - TradeList[0] = Symbol; - } - - atr = new AverageTrueRange[TradeList.Length]; - ma = new MovingAverage[TradeList.Length]; - bars = new Bars[TradeList.Length]; - indexBars = new int[TradeList.Length]; - Sources = new IndicatorDataSeries[TradeList.Length]; - ResSymbol = new IndicatorDataSeries[TradeList.Length]; - - Print("{0} traded symbols: ", TradeList.Length); - - int i = 0; - foreach (var symbol in TradeList) - { - Print(symbol.Name); - - bars[i] = MarketData.GetBars(Tf, symbol.Name); - if (bars[i].OpenTimes[0] > Bars.OpenTimes[0]) - bars[i].LoadMoreHistory(); - //Load indicators on start up EP5-ATR - Sources[i] = CreateDataSeries(); - ResSymbol[i] = CreateDataSeries(); - atr[i] = Indicators.AverageTrueRange(bars[i], 500, MovingAverageType.Simple); - - ma[i] = Indicators.MovingAverage(Sources[i], SmoothPeriods, MaType); - i++; - } - } - - public override void Calculate(int index) - { - if (index < SmoothPeriods) - return; - - for (int i = 0; i < TradeList.Length; i++) - { - //indexBars[i] = GetIndexByDate(bars[i], Bars.OpenTimes[index]); - - indexBars[i] = bars[i].OpenTimes.GetIndexByTime(Bars.OpenTimes[index]); - Sources[i][index] = bars[i].ClosePrices[indexBars[i]]; - ResSymbol[i][index] = GetCalculationSymbol(ma[i].Result[index], ma[i].Result[index - LookbackPeriodsAngle], atr[i].Result[indexBars[i]]); - } - - SymbN1[index] = ResSymbol[0][index]; - SymbN2[index] = ResSymbol[1][index]; - SymbN3[index] = ResSymbol[2][index]; - SymbN4[index] = ResSymbol[3][index]; - SymbN5[index] = ResSymbol[4][index]; - SymbN6[index] = ResSymbol[5][index]; - - /* Uncomment For More Symbols on chart - SymbN7[index] = ResSymbol[2][index]; - SymbN8[index] = ResSymbol[3][index]; - SymbN9[index] = ResSymbol[4][index]; - SymbN10[index] = ResSymbol[5][index]; - */ - - IndicatorArea.RemoveAllObjects(); - - for (int i = 0; i < TradeList.Length; i++) - { - IndicatorArea.DrawText((TradeList[i]).ToString() + index, TradeList[i] + " : " + ResSymbol[i][index].ToString("F2"), index, ResSymbol[i][index], ResSymbol[i][index] > ResSymbol[i][index - HistoryTextLookback] ? Color.Lime : Color.Red); - } - - } - public double GetCalculationSymbol(double priceSmooth, double priceSmoothLoockBack, double atr) - { - var _momentumpositive = priceSmooth - priceSmoothLoockBack; - var _momentumnegative = priceSmoothLoockBack - priceSmooth; - var _momentum = priceSmooth > priceSmoothLoockBack - ? _momentumpositive / atr - : _momentumnegative / atr; - var _hypothenuse = Math.Sqrt((_momentum * _momentum) + (LookbackPeriodsAngle * LookbackPeriodsAngle)); - var _cos = (LookbackPeriodsAngle / _hypothenuse); - var _angle = priceSmooth > priceSmoothLoockBack - ? (0 + (Math.Acos(_cos) * 100)) * Sensitivity - : (0 - (Math.Acos(_cos) * 100)) * Sensitivity; - return _angle; - } - } -} diff --git a/Sources/Indicators/Correlation with angle v1.1/msAngle of MultiSymbol.csproj b/Sources/Indicators/Correlation with angle v1.1/msAngle of MultiSymbol.csproj deleted file mode 100644 index 4040d8c..0000000 --- a/Sources/Indicators/Correlation with angle v1.1/msAngle of MultiSymbol.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - net6.0 - - - - - - diff --git a/Sources/Indicators/Economic Events On Chart.algo b/Sources/Indicators/Economic Events On Chart.algo deleted file mode 100644 index bd94e70..0000000 Binary files a/Sources/Indicators/Economic Events On Chart.algo and /dev/null differ diff --git a/Sources/Indicators/Economic Events On Chart/.gitattributes b/Sources/Indicators/Economic Events On Chart/.gitattributes deleted file mode 100644 index 1ff0c42..0000000 --- a/Sources/Indicators/Economic Events On Chart/.gitattributes +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/Sources/Indicators/Economic Events On Chart/.gitignore b/Sources/Indicators/Economic Events On Chart/.gitignore deleted file mode 100644 index 9491a2f..0000000 --- a/Sources/Indicators/Economic Events On Chart/.gitignore +++ /dev/null @@ -1,363 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Oo]ut/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file diff --git a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart.sln b/Sources/Indicators/Economic Events On Chart/Economic Events On Chart.sln deleted file mode 100644 index d5b245c..0000000 --- a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Economic Events On Chart", "Economic Events On Chart\Economic Events On Chart.csproj", "{7D9A4560-D021-4B46-8D58-83DCBEBBE654}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7D9A4560-D021-4B46-8D58-83DCBEBBE654}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D9A4560-D021-4B46-8D58-83DCBEBBE654}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D9A4560-D021-4B46-8D58-83DCBEBBE654}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D9A4560-D021-4B46-8D58-83DCBEBBE654}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Economic Events On Chart.cs b/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Economic Events On Chart.cs deleted file mode 100644 index b831773..0000000 --- a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Economic Events On Chart.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System; -using cAlgo.API; -using System.Collections.Generic; -using System.Xml; -using System.Net; -using System.Xml.Serialization; -using System.IO; -using System.Text; -using System.Linq; -using System.Globalization; - -namespace cAlgo -{ - [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.Internet)] - public class EconomicEventsOnChart : Indicator - { - private Color _colorHighImpact, _colorMediumImpact, _colorLowImpact, _colorOthers; - - private TextBlock _textBlock; - - [Parameter("Data URI", DefaultValue = "https://nfs.faireconomy.media/ff_calendar_thisweek.xml", Group = "General")] - public string DataUri { get; set; } - - [Parameter("Only Symbol Events", DefaultValue = true, Group = "General")] - public bool OnlySymbolEvents { get; set; } - - [Parameter("Show Past Events", DefaultValue = true, Group = "General")] - public bool ShowPastEvents { get; set; } - - [Parameter("Show", DefaultValue = true, Group = "High Impact")] - public bool ShowHighImpact { get; set; } - - [Parameter("Color", DefaultValue = "Red", Group = "High Impact")] - public string ColorHighImpact { get; set; } - - [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "High Impact")] - public LineStyle LineStyleHighImpact { get; set; } - - [Parameter("Thickness", DefaultValue = 1, Group = "High Impact")] - public int ThicknessHighImpact { get; set; } - - [Parameter("Show", DefaultValue = true, Group = "Medium Impact")] - public bool ShowMediumImpact { get; set; } - - [Parameter("Color", DefaultValue = "Gold", Group = "Medium Impact")] - public string ColorMediumImpact { get; set; } - - [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "Medium Impact")] - public LineStyle LineStyleMediumImpact { get; set; } - - [Parameter("Thickness", DefaultValue = 1, Group = "Medium Impact")] - public int ThicknessMediumImpact { get; set; } - - [Parameter("Show", DefaultValue = true, Group = "Low Impact")] - public bool ShowLowImpact { get; set; } - - [Parameter("Color", DefaultValue = "Yellow", Group = "Low Impact")] - public string ColorLowImpact { get; set; } - - [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "Low Impact")] - public LineStyle LineStyleLowImpact { get; set; } - - [Parameter("Thickness", DefaultValue = 1, Group = "Low Impact")] - public int ThicknessLowImpact { get; set; } - - [Parameter("Show", DefaultValue = false, Group = "Others")] - public bool ShowOthers { get; set; } - - [Parameter("Color", DefaultValue = "Gray", Group = "Others")] - public string ColorOthers { get; set; } - - [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "Others")] - public LineStyle LineStyleOthers { get; set; } - - [Parameter("Thickness", DefaultValue = 1, Group = "Others")] - public int ThicknessOthers { get; set; } - - [Parameter("Show", DefaultValue = true, Group = "Text Block")] - public bool ShowTextBlock { get; set; } - - [Parameter("Background Color", DefaultValue = "#969696", Group = "Text Block")] - public string TextBlockBackgroundColor { get; set; } - - [Parameter("Color", DefaultValue = "White", Group = "Text Block")] - public string TextBlockColor { get; set; } - - [Parameter("Horizontal Alignment", DefaultValue = HorizontalAlignment.Center, Group = "Text Block")] - public HorizontalAlignment TextBlockHorizontalAlignment { get; set; } - - [Parameter("Vertical Alignment", DefaultValue = VerticalAlignment.Bottom, Group = "Text Block")] - public VerticalAlignment TextBlockVerticalAlignment { get; set; } - - [Parameter("Text Alignment", DefaultValue = TextAlignment.Center, Group = "Text Block")] - public TextAlignment TextBlockTextAlignment { get; set; } - - [Parameter("Font Weight", DefaultValue = FontWeight.Bold, Group = "Text Block")] - public FontWeight TextBlockFontWeight { get; set; } - - protected override void Initialize() - { - RemoveEventLines(); - - if (ShowTextBlock) - { - _textBlock = new TextBlock - { - IsVisible = false, - HorizontalAlignment = TextBlockHorizontalAlignment, - VerticalAlignment = TextBlockVerticalAlignment, - BackgroundColor = GetColor(TextBlockBackgroundColor), - ForegroundColor = GetColor(TextBlockColor), - TextAlignment = TextBlockTextAlignment, - FontWeight = TextBlockFontWeight, - Padding = 5 - }; - - Chart.AddControl(_textBlock); - - Chart.ObjectHoverChanged += Chart_ObjectHoverChanged; - } - - _colorHighImpact = GetColor(ColorHighImpact); - _colorMediumImpact = GetColor(ColorMediumImpact); - _colorLowImpact = GetColor(ColorLowImpact); - _colorOthers = GetColor(ColorOthers); - - var events = GetNewsEvents(); - - DisplayEvents(events); - } - - private void Chart_ObjectHoverChanged(ChartObjectHoverChangedEventArgs obj) - { - if (!obj.IsObjectHovered || obj.ChartObject == null || string.IsNullOrWhiteSpace(obj.ChartObject.Name) || !obj.ChartObject.Name.EndsWith("Event", StringComparison.OrdinalIgnoreCase)) - { - _textBlock.IsVisible = false; - - return; - } - - _textBlock.Text = string.Format("{0} | {1}", obj.ChartObject.Name.Replace(" | Event", string.Empty), obj.ChartObject.Comment); - - _textBlock.IsVisible = true; - } - - public override void Calculate(int index) - { - } - - private IEnumerable GetNewsEvents() - { - using (var webClient = new WebClient()) - { - var data = webClient.DownloadString(DataUri); - - return GetNewsEventsFromXml(data); - } - } - - private IEnumerable GetNewsEventsFromXml(string xml) - { - var xmlSerializer = new XmlSerializer(typeof(WeeklyEvents)); - - var stream = new StringReader(xml); - - var weeklyEvents = xmlSerializer.Deserialize(stream) as WeeklyEvents; - - foreach (var newsEvent in weeklyEvents.Events) - { - var timeString = string.Format("{0} {1}", newsEvent.UtcDate, newsEvent.UtcTime); - - DateTimeOffset time; - - if (DateTimeOffset.TryParseExact(timeString, "MM-dd-yyyy h:mmtt", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out time)) - { - newsEvent.Time = time; - } - } - - return weeklyEvents.Events; - } - - private void DisplayEvents(IEnumerable events) - { - foreach (var newsEvent in events) - { - if (!newsEvent.Time.HasValue - || (newsEvent.Impact == NewsEventImpact.High && !ShowHighImpact) - || (newsEvent.Impact == NewsEventImpact.Medium && !ShowMediumImpact) - || (newsEvent.Impact == NewsEventImpact.Low && !ShowLowImpact) - || ((newsEvent.Impact == NewsEventImpact.None || newsEvent.Impact == NewsEventImpact.Holiday) && !ShowOthers) - || (OnlySymbolEvents && !IsEventRelatedToSymbol(newsEvent.Currency)) - || (!ShowPastEvents && newsEvent.Time < Server.TimeInUtc)) continue; - - var lineSettings = GetLineSettings(newsEvent.Impact); - - var eventLine = Chart.DrawVerticalLine(string.Format("{0} | {1} | {2} | Event", newsEvent.Title, newsEvent.Currency, newsEvent.Impact), newsEvent.Time.Value.UtcDateTime, lineSettings.Color, lineSettings.Thickness, lineSettings.Style); - - var stringBuilder = new StringBuilder(); - - if (!string.IsNullOrWhiteSpace(newsEvent.Forecast)) - { - stringBuilder.Append(string.Format("Forecast: {0} | ", newsEvent.Forecast)); - } - - if (!string.IsNullOrWhiteSpace(newsEvent.Previous)) - { - stringBuilder.Append(string.Format("Previous: {0} | ", newsEvent.Previous)); - } - - if (newsEvent.Time.HasValue) - { - var time = newsEvent.Time.Value.ToOffset(Application.UserTimeOffset); - - stringBuilder.Append(string.Format("Time: {0:s}", time)); - } - - eventLine.Comment = stringBuilder.ToString(); - eventLine.IsInteractive = true; - eventLine.IsLocked = true; - } - } - - private bool IsEventRelatedToSymbol(string eventCurrency) - { - return SymbolName.StartsWith(eventCurrency, StringComparison.OrdinalIgnoreCase) || SymbolName.EndsWith(eventCurrency, StringComparison.OrdinalIgnoreCase); - } - - private Color GetColor(string colorString, int alpha = 255) - { - var color = colorString[0] == '#' ? Color.FromHex(colorString) : Color.FromName(colorString); - - return Color.FromArgb(alpha, color); - } - - private LineSettings GetLineSettings(NewsEventImpact impact) - { - switch (impact) - { - case NewsEventImpact.High: - return new LineSettings - { - Color = _colorHighImpact, - Style = LineStyleHighImpact, - Thickness = ThicknessHighImpact - }; - - case NewsEventImpact.Medium: - return new LineSettings - { - Color = _colorMediumImpact, - Style = LineStyleMediumImpact, - Thickness = ThicknessMediumImpact - }; - - case NewsEventImpact.Low: - return new LineSettings - { - Color = _colorLowImpact, - Style = LineStyleLowImpact, - Thickness = ThicknessLowImpact - }; - - default: - return new LineSettings - { - Color = _colorOthers, - Style = LineStyleOthers, - Thickness = ThicknessOthers - }; - } - } - - private void RemoveEventLines() - { - var chartObjects = Chart.Objects.ToArray(); - - foreach (var chartObject in chartObjects) - { - if (chartObject.ObjectType != ChartObjectType.VerticalLine || !chartObject.IsInteractive || string.IsNullOrEmpty(chartObject.Name) || !chartObject.Name.EndsWith("Event", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - Chart.RemoveObject(chartObject.Name); - } - } - } - - [XmlRoot("weeklyevents")] - public class WeeklyEvents - { - [XmlElement("event")] - public List Events { get; set; } - } - - public class NewsEvent - { - [XmlElement("title")] - public string Title { get; set; } - - [XmlElement("country")] - public string Currency { get; set; } - - [XmlElement("date")] - public string UtcDate { get; set; } - - [XmlElement("time")] - public string UtcTime { get; set; } - - [XmlIgnore] - public DateTimeOffset? Time { get; set; } - - [XmlElement("impact")] - public NewsEventImpact Impact { get; set; } - - [XmlElement("previous")] - public string Previous { get; set; } - - [XmlElement("forecast")] - public string Forecast { get; set; } - } - - public enum NewsEventImpact - { - None, - - High, - - Medium, - - Low, - - Holiday - } - - public struct LineSettings - { - public Color Color { get; set; } - - public LineStyle Style { get; set; } - - public int Thickness { get; set; } - } -} \ No newline at end of file diff --git a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Economic Events On Chart.csproj b/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Economic Events On Chart.csproj deleted file mode 100644 index b2d03cf..0000000 --- a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Economic Events On Chart.csproj +++ /dev/null @@ -1,60 +0,0 @@ - - - - - 7.2 - Debug - AnyCPU - {7D9A4560-D021-4B46-8D58-83DCBEBBE654} - {DD87C1B2-3799-4CA2-93B6-5288EE928820};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - cAlgo - Economic Events On Chart - v4.0 - Client - 512 - True - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - False - ..\..\..\..\API\cAlgo.API.dll - - - - - - - - - \ No newline at end of file diff --git a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Properties/AssemblyInfo.cs b/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Properties/AssemblyInfo.cs deleted file mode 100644 index 5334d9f..0000000 --- a/Sources/Indicators/Economic Events On Chart/Economic Events On Chart/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Economic Events On Chart")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyProduct("Economic Events On Chart")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("35f19c43-c7cc-4f53-b8e0-61caaf9cd8e8")] - -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -#if DEBUG - [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations)] -#endif \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterDisplay.algo b/Sources/Indicators/HmaClusterDisplay.algo index 17e0f49..a6155d4 100644 Binary files a/Sources/Indicators/HmaClusterDisplay.algo and b/Sources/Indicators/HmaClusterDisplay.algo differ diff --git a/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.cs b/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.cs index 390e899..46d8a11 100644 --- a/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.cs +++ b/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.cs @@ -1,9 +1,8 @@ using System; -using System.IO; -using System.Linq; using cAlgo.API; using cAlgo.API.Indicators; using cAlgo.API.Internals; +using Myc.HmaSma; namespace cAlgo { @@ -39,7 +38,7 @@ namespace cAlgo private HullMovingAverage _hmaBiasIndicator; private HullMovingAverage _hmaClusterIndicator; - // Default values from prompt header + // Default values private int _smaBiasLength = 200; private int _hmaBiasLength = 250; private int _hmaClusterLength = 25; @@ -48,7 +47,7 @@ namespace cAlgo protected override void Initialize() { - LoadConfiguration(); + ApplyExternalConfiguration(); // Initialize indicators with loaded or default values _smaBiasIndicator = Indicators.SimpleMovingAverage(Bars.ClosePrices, _smaBiasLength); @@ -62,73 +61,39 @@ namespace cAlgo { if (_smaBiasIndicator != null) SmaBiasOutput[index] = _smaBiasIndicator.Result[index]; - + if (_hmaBiasIndicator != null) HmaBiasOutput[index] = _hmaBiasIndicator.Result[index]; - + if (_hmaClusterIndicator != null) HmaClusterOutput[index] = _hmaClusterIndicator.Result[index]; } - private void LoadConfiguration() + private void ApplyExternalConfiguration() { - if (!File.Exists(ConfigFilePath)) - { - Print($"Config file not found at {ConfigFilePath}. Using defaults."); - return; - } - try { - var lines = File.ReadAllLines(ConfigFilePath); - var currentSymbol = SymbolName; - // cTrader ShortName returns "m5", "h1", etc. which matches your file format - var currentTimeframe = TimeFrame.ShortName; + var loader = new HmaSmaLoader(ConfigFilePath); + loader.Load(); - foreach (var line in lines) + // cTrader TimeFrame.ShortName returns values like "m5", "h1" which match the library expectation + var parameters = loader.GetParameters(SymbolName, TimeFrame.ShortName); + + if (parameters != null) { - var trimmedLine = line.Trim(); - - // Skip comments and empty lines - if (string.IsNullOrWhiteSpace(trimmedLine) || trimmedLine.StartsWith("#")) - continue; - - // Split by whitespace - var columns = trimmedLine.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - - // Ensure we have enough columns (need at least up to index 6) - if (columns.Length < 7) - continue; - - var cfgSymbol = columns[0]; - var cfgTimeframe = columns[1]; - - // Check for match (case-insensitive) - if (string.Equals(cfgSymbol, currentSymbol, StringComparison.OrdinalIgnoreCase) && - string.Equals(cfgTimeframe, currentTimeframe, StringComparison.OrdinalIgnoreCase)) - { - // Parse values - // Col 4: SmaBias - // Col 5: HmaBias - // Col 6: HmaCluster - if (int.TryParse(columns[4], out int sBias) && - int.TryParse(columns[5], out int hBias) && - int.TryParse(columns[6], out int hCluster)) - { - _smaBiasLength = sBias; - _hmaBiasLength = hBias; - _hmaClusterLength = hCluster; - Print($"Configuration found for {currentSymbol} {currentTimeframe}"); - return; // Stop searching after match - } - } + _smaBiasLength = parameters.SmaBias; + _hmaBiasLength = parameters.HmaBias; + _hmaClusterLength = parameters.HmaCluster; + Print($"Configuration loaded for {SymbolName} {TimeFrame.ShortName}"); + } + else + { + Print($"No specific config found for {SymbolName} {TimeFrame.ShortName}. Using defaults."); } - - Print($"No specific config found for {currentSymbol} {currentTimeframe}. Using defaults."); } catch (Exception ex) { - Print($"Error reading config file: {ex.Message}. Using defaults."); + Print($"Error loading configuration: {ex.Message}. Using defaults."); } } } diff --git a/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.csproj b/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.csproj index da1fef1..866383b 100644 --- a/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.csproj +++ b/Sources/Indicators/HmaClusterDisplay/HmaClusterDisplay/HmaClusterDisplay.csproj @@ -1,9 +1,14 @@ + net6.0 - - + + + ..\..\..\Common\MSLib\obj\Debug\net6.0\MSLib.dll + + + \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR.algo b/Sources/Indicators/HmaClusterSR.algo index 329c2c4..d1d1a03 100644 Binary files a/Sources/Indicators/HmaClusterSR.algo and b/Sources/Indicators/HmaClusterSR.algo differ diff --git a/Sources/Indicators/HmaClusterSR/.vscode/tasks.json b/Sources/Indicators/HmaClusterSR/.vscode/tasks.json new file mode 100644 index 0000000..215166e --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/.vscode/tasks.json @@ -0,0 +1 @@ +{"version":"2.0.0","tasks":[{"label":"build","command":"dotnet","type":"process","args":["build","${workspaceFolder}","/property:GenerateFullPaths=true","/consoleLoggerParameters:NoSummary"],"problemMatcher":"$msCompile"}]} \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.cs b/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.cs index 5495496..c421f70 100644 --- a/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.cs +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.cs @@ -1,777 +1,72 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; using cAlgo.API; using cAlgo.API.Indicators; using cAlgo.API.Internals; +using Myc; -namespace cAlgo.Robots +namespace cAlgo.Indicators { - [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] - public class HmaClusterBot : Robot + [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] + public class HmaClusterSR : Indicator { #region Parameters + [Parameter("HMA Period", DefaultValue = 25, MinValue = 2)] + public int HmaPeriod { get; set; } - [Parameter("Symbols (CSV)", DefaultValue = "", Group = "Multi Symbol")] - public string SymbolsCsv { get; set; } + [Parameter("Amplitude Period (Swings)", DefaultValue = 50, MinValue = 1)] + public int AmplitudePeriod { get; set; } - [Parameter("Risk % of Balance", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 10.0, Group = "Risk")] - public double RiskPercent { get; set; } + [Parameter("Auto Range Multiplier", DefaultValue = 0.5, MinValue = 0.05, MaxValue = 1.0)] + public double RangeMultiplier { get; set; } - [Parameter("Entry Significance %", DefaultValue = 20.0, MinValue = 1.0, Group = "Thresholds")] - public double EntrySigThreshold { get; set; } - - [Parameter("Stop Loss Significance %", DefaultValue = 10.0, MinValue = 1.0, Group = "Thresholds")] - public double SlSigThreshold { get; set; } - - [Parameter("SMA Bias Period", DefaultValue = 200, Group = "Bias")] - public int SmaBiasPeriod { get; set; } - - [Parameter("HMA Bias Period", DefaultValue = 250, Group = "Bias")] - public int HmaBiasPeriod { get; set; } - - [Parameter("Use Bias Deviation Filter", DefaultValue = true, Group = "Bias Filter")] - public bool UseBiasDeviationFilter { get; set; } - - [Parameter("Bias Deviation Avg Period", DefaultValue = 500, Group = "Bias Filter")] - public int BiasDeviationAvgPeriod { get; set; } - - [Parameter("Use Dynamic Position Management", DefaultValue = true, Group = "Management")] - public bool UseDynamicPositionManagement { get; set; } - - [Parameter("Close Profit on Bias Flip", DefaultValue = false, Group = "Management")] - public bool CloseProfitOnBiasFlip { get; set; } - - [Parameter("HMA Cluster Period", DefaultValue = 25, Group = "Clusters")] - public int HmaClusterPeriod { get; set; } - - [Parameter("Cluster Max Points", DefaultValue = 2000, Group = "Clusters")] + [Parameter("Buffer Size (Points)", DefaultValue = 2000, MinValue = 10)] public int MaxPoints { get; set; } - [Parameter("Cluster Decay (Bars)", DefaultValue = 1000, Group = "Clusters")] + [Parameter("Decay Period (Bars)", DefaultValue = 1000, MinValue = 100)] public int DecayPeriod { get; set; } - // --- Telegram Parameters --- - [Parameter("Send Telegram Only", DefaultValue = false, Group = "Telegram")] - public bool SendTelegramOnly { get; set; } - - [Parameter("Telegram Bot Token", DefaultValue = "8569913524:AAE9RGsvkBPa0yhTFCKBjVeST0fuzdOx5w0", Group = "Telegram")] - public string TelegramBotToken { get; set; } - - [Parameter("Telegram Chat ID", DefaultValue = "5171721381", Group = "Telegram")] - public string TelegramChatId { get; set; } - + [Parameter("Max Zones", DefaultValue = 100, MinValue = 1)] + public int MaxZones { get; set; } #endregion - private readonly List _strategies = new List(); - private static readonly HttpClient _httpClient = new HttpClient(); - - protected override void OnStart() - { - try - { - if (string.IsNullOrWhiteSpace(SymbolsCsv)) - { - Print("CSV is empty. Running in Single-Symbol Mode on Chart Symbol."); - - var config = new StrategyConfig - { - SymbolName = SymbolName, - EntrySigThreshold = EntrySigThreshold, - SlSigThreshold = SlSigThreshold, - SmaBiasPeriod = SmaBiasPeriod, - HmaBiasPeriod = HmaBiasPeriod, - HmaClusterPeriod = HmaClusterPeriod, - UseBiasDeviationFilter = UseBiasDeviationFilter, - BiasDeviationAvgPeriod = BiasDeviationAvgPeriod, - UseDynamicPositionManagement = UseDynamicPositionManagement, - CloseProfitOnBiasFlip = CloseProfitOnBiasFlip, - SendTelegramOnly = SendTelegramOnly, - RiskPercent = RiskPercent, - MaxPoints = MaxPoints, - DecayPeriod = DecayPeriod - }; - - var strategy = new ClusterStrategy(this, Symbol, Bars, config, _httpClient, TelegramBotToken, TelegramChatId, BroadcastError); - _strategies.Add(strategy); - strategy.Start(); - } - else - { - Print("CSV detected. Running in Multi-Symbol Mode."); - ParseCsvAndCreateStrategies(); - } - } - catch (Exception ex) - { - BroadcastError($"CRITICAL STARTUP ERROR: {ex.Message}"); - Stop(); - } - } - - protected override void OnStop() - { - foreach (var strategy in _strategies) - { - strategy.Stop(); - } - } - - protected override void OnError(Error error) - { - BroadcastError($"TRADING ERROR [{error.Code}]: {error.ToString}"); - } - - public void BroadcastError(string message) - { - Print(message); - - if (!string.IsNullOrWhiteSpace(TelegramBotToken) && !string.IsNullOrWhiteSpace(TelegramChatId)) - { - string formattedMsg = $"⚠️ ERROR @ {DateTime.UtcNow:HH:mm:ss} UTC\n\n{message}"; - _ = SendTelegramRawAsync(TelegramBotToken, TelegramChatId, formattedMsg); - } - } - - private async Task SendTelegramRawAsync(string token, string chatId, string message) - { - try - { - string url = $"https://api.telegram.org/bot{token}/sendMessage?chat_id={chatId}&text={Uri.EscapeDataString(message)}&parse_mode=HTML"; - await _httpClient.GetAsync(url); - } - catch (Exception ex) - { - Print("FAILED TO SEND TELEGRAM ERROR: " + ex.Message); - } - } - - private void ParseCsvAndCreateStrategies() - { - var normalizedCsv = SymbolsCsv.Replace("\n", ",").Replace("\r", ","); - - var tokens = normalizedCsv.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) - .Select(t => t.Trim()) - .Where(t => !string.IsNullOrEmpty(t)) - .ToArray(); - - int paramsPerSymbol = 10; - - if (tokens.Length % paramsPerSymbol != 0) - { - string err = $"CSV Token count ({tokens.Length}) is not a multiple of {paramsPerSymbol}. Check format."; - BroadcastError(err); - } - - for (int i = 0; i < tokens.Length; i += paramsPerSymbol) - { - if (i + paramsPerSymbol > tokens.Length) break; - - string symName = tokens[i]; - - try - { - Symbol symbol = Symbols.GetSymbol(symName); - if (symbol == null) - { - BroadcastError($"Symbol '{symName}' not found in cTrader."); - continue; - } - - Bars bars = MarketData.GetBars(TimeFrame, symName); - - var config = new StrategyConfig - { - SymbolName = symName, - EntrySigThreshold = double.Parse(tokens[i + 1], CultureInfo.InvariantCulture), - SlSigThreshold = double.Parse(tokens[i + 2], CultureInfo.InvariantCulture), - SmaBiasPeriod = int.Parse(tokens[i + 3], CultureInfo.InvariantCulture), - HmaBiasPeriod = int.Parse(tokens[i + 4], CultureInfo.InvariantCulture), - HmaClusterPeriod = int.Parse(tokens[i + 5], CultureInfo.InvariantCulture), - UseBiasDeviationFilter = bool.Parse(tokens[i + 6]), - BiasDeviationAvgPeriod = int.Parse(tokens[i + 7], CultureInfo.InvariantCulture), - UseDynamicPositionManagement = bool.Parse(tokens[i + 8]), - SendTelegramOnly = bool.Parse(tokens[i + 9]), - - // Default values for parameters not in CSV yet - CloseProfitOnBiasFlip = CloseProfitOnBiasFlip, - RiskPercent = RiskPercent, - MaxPoints = MaxPoints, - DecayPeriod = DecayPeriod - }; - - var strategy = new ClusterStrategy(this, symbol, bars, config, _httpClient, TelegramBotToken, TelegramChatId, BroadcastError); - _strategies.Add(strategy); - strategy.Start(); - - Print("Initialized Strategy for {0}", symName); - } - catch (Exception ex) - { - BroadcastError($"Config Error for '{symName}': {ex.Message}"); - } - } - } - } - - public class StrategyConfig - { - public string SymbolName { get; set; } - public double EntrySigThreshold { get; set; } - public double SlSigThreshold { get; set; } - public int SmaBiasPeriod { get; set; } - public int HmaBiasPeriod { get; set; } - public int HmaClusterPeriod { get; set; } - public bool UseBiasDeviationFilter { get; set; } - public int BiasDeviationAvgPeriod { get; set; } - public bool UseDynamicPositionManagement { get; set; } - public bool CloseProfitOnBiasFlip { get; set; } - public bool SendTelegramOnly { get; set; } - public double RiskPercent { get; set; } - public int MaxPoints { get; set; } - public int DecayPeriod { get; set; } - } - - public class ClusterStrategy - { - #region Types & Fields - - private enum PointType { Peak, Trough } - private enum Bias { Long, Short, Neutral } - - private struct ExtremumPoint - { - public double Price; - public int Index; - public PointType Type; - } - - public struct ClusterLevel - { - public double Price; - public double Significance; - } - - private readonly Robot _robot; - private readonly Symbol _symbol; - private readonly Bars _bars; - private readonly StrategyConfig _config; - private readonly HttpClient _httpClient; - private readonly string _botToken; - private readonly string _chatId; - private readonly Action _errorCallback; - - private SimpleMovingAverage _smaBias; - private HullMovingAverage _hmaBias; - private HullMovingAverage _hmaCluster; - - private readonly Queue _deviationQueue = new Queue(); - private double _runningDeviationSum; + #region Fields + private HullMovingAverage _hma; - private bool _deviationConditionMetInCurrentCycle; - private bool _isTradingAllowedBasedOnPrevCycle; + // Neue optimierte Engine + private ClusterCalculator _calculator; - private readonly List _extremaPoints = new(); + // Lokaler State für Trend private readonly List _amplitudes = new(); - private double _trendExtremum; private int _trendExtremumIndex; private double _lastExtremumPrice; private bool? _isUpTrend; private double _currentDynamicRange; - - private const string Label = "HmaClusterBot"; - #endregion - public ClusterStrategy( - Robot robot, - Symbol symbol, - Bars bars, - StrategyConfig config, - HttpClient httpClient, - string token, - string chatId, - Action errorCallback) + protected override void Initialize() { - _robot = robot; - _symbol = symbol; - _bars = bars; - _config = config; - _httpClient = httpClient; - _botToken = token; - _chatId = chatId; - _errorCallback = errorCallback; - } - - public void Start() - { - int requiredBars = Math.Max(_config.SmaBiasPeriod, _config.HmaBiasPeriod); - requiredBars = Math.Max(requiredBars, _config.BiasDeviationAvgPeriod) + 10; - - while (_bars.Count < requiredBars) - { - int loaded = _bars.LoadMoreHistory(); - if (loaded == 0) - { - _errorCallback?.Invoke($"Not enough history for {_config.SymbolName}. Loaded: {_bars.Count}, Req: {requiredBars}"); - return; - } - } - - _smaBias = _robot.Indicators.SimpleMovingAverage(_bars.ClosePrices, _config.SmaBiasPeriod); - _hmaBias = _robot.Indicators.HullMovingAverage(_bars.ClosePrices, _config.HmaBiasPeriod); - _hmaCluster = _robot.Indicators.HullMovingAverage(_bars.ClosePrices, _config.HmaClusterPeriod); - - _currentDynamicRange = 5.0 * _symbol.PipSize; - _deviationConditionMetInCurrentCycle = false; - _isTradingAllowedBasedOnPrevCycle = false; - - int startIndex = Math.Max(_config.SmaBiasPeriod, _config.HmaBiasPeriod); - startIndex = Math.Max(startIndex, _config.BiasDeviationAvgPeriod); + Print("Initializing HmaClusterSR with Optimized Engine. Symbol: {0}", Symbol.Name); - for (int i = startIndex; i < _bars.Count; i++) - { - UpdateFilterState(i); - UpdateClusterData(i); - } - - _bars.BarOpened += OnBarOpened; - } - - public void Stop() - { - _bars.BarOpened -= OnBarOpened; - } - - private void OnBarOpened(BarOpenedEventArgs obj) - { - try - { - int index = _bars.Count - 2; - if (index < _config.BiasDeviationAvgPeriod) return; - - UpdateFilterState(index); - UpdateClusterData(index); - - var clusters = CalculateClusters(index); - - // 1. Dynamic SL/TP Management - if (!_config.SendTelegramOnly && _config.UseDynamicPositionManagement && clusters.Count >= 2) - { - ManagePositions(clusters); - } - - var currentBias = GetCurrentBias(index); - - // 2. Check for Profit Close on Bias Flip - if (!_config.SendTelegramOnly && _config.CloseProfitOnBiasFlip) - { - CloseReversedPositions(currentBias); - } - - // 3. New Entry Logic - ManageOrders(currentBias, index, clusters); - } - catch (Exception ex) - { - _errorCallback?.Invoke($"Runtime Error ({_config.SymbolName}): {ex.Message}\n{ex.StackTrace}"); - } - } - - private void CloseReversedPositions(Bias currentBias) - { - if (currentBias == Bias.Neutral) return; - - foreach (var pos in _robot.Positions) - { - if (pos.SymbolName != _config.SymbolName || pos.Label != Label) continue; - if (pos.NetProfit <= 0) continue; - - bool close = false; - - if (currentBias == Bias.Short && pos.TradeType == TradeType.Buy) - close = true; - else if (currentBias == Bias.Long && pos.TradeType == TradeType.Sell) - close = true; - - if (close) - { - var result = _robot.ClosePosition(pos); - if (result.IsSuccessful) - { - string msg = $"🔒 CLOSE PROFIT (Bias Flip) @ {_config.SymbolName}\n" + - $"Profit: {pos.NetProfit:F2}"; - _ = SendTelegramMessageAsync(msg); - } - } - } - } - - private void UpdateFilterState(int index) - { - double currHma = _hmaBias.Result[index]; - double currSma = _smaBias.Result[index]; - double prevHma = _hmaBias.Result[index - 1]; - double prevSma = _smaBias.Result[index - 1]; - - double currentBiasDeviation = Math.Abs(currHma - currSma); + _hma = Indicators.HullMovingAverage(Bars.ClosePrices, HmaPeriod); - _deviationQueue.Enqueue(currentBiasDeviation); - _runningDeviationSum += currentBiasDeviation; - - if (_deviationQueue.Count > _config.BiasDeviationAvgPeriod) - { - double removed = _deviationQueue.Dequeue(); - _runningDeviationSum -= removed; - } - - double averageDeviation = (_deviationQueue.Count > 0) - ? _runningDeviationSum / _deviationQueue.Count - : 0.0; - - bool currHmaAbove = currHma > currSma; - bool prevHmaAbove = prevHma > prevSma; - - if (currHmaAbove != prevHmaAbove) - { - _isTradingAllowedBasedOnPrevCycle = _deviationConditionMetInCurrentCycle; - _deviationConditionMetInCurrentCycle = false; - } - - if (currentBiasDeviation > averageDeviation) - { - _deviationConditionMetInCurrentCycle = true; - } - } - - private Bias GetCurrentBias(int index) - { - double hma = _hmaBias.Result[index]; - double sma = _smaBias.Result[index]; - double prevSma = _smaBias.Result[index - 1]; - - if ((hma > sma) && (sma > prevSma)) return Bias.Long; - if ((hma < sma) && (sma < prevSma)) return Bias.Short; - - return Bias.Neutral; - } - - private void ManagePositions(List clusters) - { - double pNow = _symbol.Bid; - - foreach (var pos in _robot.Positions) - { - if (pos.Label != Label || pos.SymbolName != _config.SymbolName) continue; - - ClusterLevel? newSl = null; - ClusterLevel? newTp = null; - - 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) - { - 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 // Sell - { - 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; - lowestTpPrice = 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.Ask && (finalTp == 0 || finalTp < _symbol.Ask)) - { - _robot.ModifyPosition(pos, finalSl, finalTp, ProtectionType.Absolute); - } - } - } - } - } - - private void ManageOrders(Bias bias, int index, List clusters) - { - CleanupOrders(bias); - - if (_config.UseBiasDeviationFilter && !_isTradingAllowedBasedOnPrevCycle) - return; - - if (bias == Bias.Neutral) return; - - if (!_config.SendTelegramOnly) - { - bool hasLong = _robot.Positions.Any(p => p.SymbolName == _config.SymbolName && p.Label == Label && p.TradeType == TradeType.Buy); - bool hasShort = _robot.Positions.Any(p => p.SymbolName == _config.SymbolName && p.Label == Label && p.TradeType == TradeType.Sell); - - if ((bias == Bias.Long && hasLong) || (bias == Bias.Short && hasShort)) - return; - } - - if (clusters.Count < 2) return; - - double pNow = _bars.ClosePrices[index]; - - if (bias == Bias.Short) - ProcessShortSetup(clusters, pNow); - else if (bias == Bias.Long) - ProcessLongSetup(clusters, pNow); - } - - private void CleanupOrders(Bias currentBias) - { - if (_config.SendTelegramOnly) return; - - foreach (var order in _robot.PendingOrders) - { - if (order.Label != Label || order.SymbolName != _config.SymbolName) continue; - - if (currentBias == Bias.Long && order.TradeType == TradeType.Sell) - _robot.CancelPendingOrder(order); - else if (currentBias == Bias.Short && order.TradeType == TradeType.Buy) - _robot.CancelPendingOrder(order); - else if (currentBias == Bias.Neutral) - _robot.CancelPendingOrder(order); - } - } - - private void ProcessShortSetup(List clusters, double pNow) - { - ClusterLevel? entry = null; - ClusterLevel? sl = null; - ClusterLevel? tp = null; - - double highestEntryPrice = double.MinValue; - double lowestSlPrice = double.MaxValue; - double lowestTpPrice = double.MaxValue; - - foreach (var c in clusters) - { - if (c.Price > pNow) - { - if ((c.Significance >= _config.EntrySigThreshold) && (c.Price > highestEntryPrice)) - { - entry = c; - highestEntryPrice = c.Price; - } - if ((c.Significance < _config.SlSigThreshold) && (c.Price < lowestSlPrice)) - { - sl = c; - lowestSlPrice = c.Price; - } - } - } - - if (entry == null || sl == null) return; - - foreach (var c in clusters) - { - if ((c.Price < entry.Value.Price) && (c.Significance >= _config.EntrySigThreshold)) - { - if (c.Price < lowestTpPrice) - { - tp = c; - lowestTpPrice = c.Price; - } - } - } - - if (tp != null && (sl.Value.Price > entry.Value.Price)) - { - double risk = sl.Value.Price - entry.Value.Price; - double reward = entry.Value.Price - tp.Value.Price; - - if (risk <= reward) - UpdateOrPlaceLimitOrder(TradeType.Sell, entry.Value.Price, sl.Value.Price, tp.Value.Price); - } - } - - private void ProcessLongSetup(List clusters, double pNow) - { - ClusterLevel? entry = null; - ClusterLevel? sl = null; - ClusterLevel? tp = null; - - double lowestEntryPrice = double.MaxValue; - double highestSlPrice = double.MinValue; - double highestTpPrice = double.MinValue; - - foreach (var c in clusters) - { - if (c.Price < pNow) - { - if ((c.Significance >= _config.EntrySigThreshold) && (c.Price < lowestEntryPrice)) - { - entry = c; - lowestEntryPrice = c.Price; - } - if ((c.Significance < _config.SlSigThreshold) && (c.Price > highestSlPrice)) - { - sl = c; - highestSlPrice = c.Price; - } - } - } - - if (entry == null || sl == null) return; - - foreach (var c in clusters) - { - if ((c.Price > entry.Value.Price) && (c.Significance >= _config.EntrySigThreshold)) - { - if (c.Price > highestTpPrice) - { - tp = c; - highestTpPrice = c.Price; - } - } - } - - if (tp != null && (sl.Value.Price < entry.Value.Price)) - { - double risk = entry.Value.Price - sl.Value.Price; - double reward = tp.Value.Price - entry.Value.Price; - - if (risk <= reward) - UpdateOrPlaceLimitOrder(TradeType.Buy, entry.Value.Price, sl.Value.Price, tp.Value.Price); - } - } - - private void UpdateOrPlaceLimitOrder(TradeType type, double entry, double sl, double tp) - { - double slDistPips = Math.Abs(entry - sl) / _symbol.PipSize; - if (slDistPips <= 0) return; - - double riskAmount = _robot.Account.Balance * (_config.RiskPercent / 100.0); - double volume = _symbol.VolumeForFixedRisk(riskAmount, slDistPips); + // Calculator initialisieren mit der Kapazität aus den Parametern + _calculator = new ClusterCalculator(MaxPoints); - volume = _symbol.NormalizeVolumeInUnits(volume, RoundingMode.Down); - if (volume < _symbol.VolumeInUnitsMin) return; - - double lots = _symbol.VolumeInUnitsToQuantity(volume); - - if (_config.SendTelegramOnly) - { - string directionStr = type == TradeType.Buy ? "BUY" : "SELL"; - string directionIcon = type == TradeType.Buy ? "📈" : "📉"; - string msg = $"{directionIcon} {directionStr} Signal @ {_config.SymbolName}\n\n" + - $"Entry: {entry}\n" + - $"SL: {sl}\n" + - $"TP: {tp}\n" + - $"Vol: {lots:F2} Lots"; - - _ = SendTelegramMessageAsync(msg); - return; - } - - var existingOrder = _robot.PendingOrders.FirstOrDefault(o => o.SymbolName == _config.SymbolName && o.Label == Label && o.TradeType == type); - - if (existingOrder != null) - { - bool volumeChanged = Math.Abs(existingOrder.VolumeInUnits - volume) > _symbol.VolumeInUnitsStep; - bool entryChanged = Math.Abs(existingOrder.TargetPrice - entry) > _symbol.TickSize; - bool slChanged = Math.Abs((existingOrder.StopLoss ?? 0) - sl) > _symbol.TickSize; - bool tpChanged = Math.Abs((existingOrder.TakeProfit ?? 0) - tp) > _symbol.TickSize; - - if (volumeChanged || entryChanged || slChanged || tpChanged) - { - _robot.ModifyPendingOrder(existingOrder, entry, sl, tp, ProtectionType.Absolute, null, volume); - } - } - else - { - _robot.Print("[SIGNAL] {0} {1} | Entry: {2} | SL: {3} | TP: {4} | Vol: {5:F2} Lots", - (type == TradeType.Buy ? "BUY" : "SELL"), _config.SymbolName, entry, sl, tp, lots); - - _robot.PlaceLimitOrder(type, _config.SymbolName, volume, entry, Label, sl, tp, ProtectionType.Absolute); - } + _currentDynamicRange = 5.0 * Symbol.PipSize; } - private async Task SendTelegramMessageAsync(string message) + public override void Calculate(int index) { - if (_robot.IsBacktesting) return; - if (string.IsNullOrWhiteSpace(_botToken) || string.IsNullOrWhiteSpace(_chatId)) return; + if (index < 1) return; - try - { - string url = $"https://api.telegram.org/bot{_botToken}/sendMessage?chat_id={_chatId}&text={Uri.EscapeDataString(message)}&parse_mode=HTML"; - HttpResponseMessage response = await _httpClient.GetAsync(url); - - if (!response.IsSuccessStatusCode) - { - _errorCallback?.Invoke($"Telegram Error: {response.StatusCode}"); - } - } - catch (Exception ex) - { - _errorCallback?.Invoke($"Telegram Exception: {ex.Message}"); - } - } + double currentHma = _hma.Result[index]; + double prevHma = _hma.Result[index - 1]; + + if (double.IsNaN(currentHma)) return; - private void UpdateClusterData(int index) - { - double currentHma = _hmaCluster.Result[index]; - double prevHma = _hmaCluster.Result[index - 1]; bool currentDirectionUp = (currentHma > prevHma); if (_isUpTrend == null) @@ -784,22 +79,7 @@ namespace cAlgo.Robots if (currentDirectionUp != _isUpTrend) { - double amp = Math.Abs(_trendExtremum - _lastExtremumPrice); - if (amp > 0) - { - _amplitudes.Add(amp); - if (_amplitudes.Count > 50) _amplitudes.RemoveAt(0); - - double sum = 0; - for (int i = 0; i < _amplitudes.Count; i++) sum += _amplitudes[i]; - _currentDynamicRange = (sum / _amplitudes.Count) * 0.5; - } - _extremaPoints.Add(new ExtremumPoint { Price = _trendExtremum, Index = _trendExtremumIndex, Type = _isUpTrend.Value ? PointType.Peak : PointType.Trough }); - if (_extremaPoints.Count > _config.MaxPoints) _extremaPoints.RemoveAt(0); - - _lastExtremumPrice = _trendExtremum; - _isUpTrend = currentDirectionUp; - SetExtremum(index); + HandleTrendReversal(index, currentDirectionUp); } else { @@ -807,69 +87,132 @@ namespace cAlgo.Robots } } + private void HandleTrendReversal(int index, bool currentDirectionUp) + { + // 1. Amplitude berechnen & Dynamische Range updaten + double amplitude = Math.Abs(_trendExtremum - _lastExtremumPrice); + if (amplitude > 0) + { + _amplitudes.Add(amplitude); + if (_amplitudes.Count > AmplitudePeriod) _amplitudes.RemoveAt(0); + + // Simples Average hier direkt berechnen, da es nur ein UI-Scaling ist + double avgAmp = _amplitudes.Count > 0 ? _amplitudes.Average() : 5.0 * Symbol.PipSize; + _currentDynamicRange = avgAmp * RangeMultiplier; + } + + // 2. Punkt in die optimierte Engine pushen + // ACHTUNG: AddPoint sortiert automatisch ein (BinarySearch) + _calculator.AddPoint(new ExtremumPoint + { + Price = _trendExtremum, + Index = _trendExtremumIndex, + Type = _isUpTrend.Value ? PointType.Peak : PointType.Trough + }); + + _lastExtremumPrice = _trendExtremum; + + // 3. Cluster neu berechnen & Zeichnen + UpdateClusters(); + + // 4. Reset für neuen Trend + _isUpTrend = currentDirectionUp; + SetExtremum(index); + } + private void SetExtremum(int index) { - _trendExtremum = _isUpTrend.Value ? _bars.HighPrices[index] : _bars.LowPrices[index]; + _trendExtremum = _isUpTrend.Value ? Bars.HighPrices[index] : Bars.LowPrices[index]; _trendExtremumIndex = index; } private void UpdateExtremum(int index) { - if (_isUpTrend.Value && (_bars.HighPrices[index] > _trendExtremum)) + if (_isUpTrend.Value && Bars.HighPrices[index] > _trendExtremum) { - _trendExtremum = _bars.HighPrices[index]; + _trendExtremum = Bars.HighPrices[index]; _trendExtremumIndex = index; } - else if (!_isUpTrend.Value && (_bars.LowPrices[index] < _trendExtremum)) + else if (!_isUpTrend.Value && Bars.LowPrices[index] < _trendExtremum) { - _trendExtremum = _bars.LowPrices[index]; + _trendExtremum = Bars.LowPrices[index]; _trendExtremumIndex = index; } } - private List CalculateClusters(int currentIndex) + private void UpdateClusters() { - int count = _extremaPoints.Count; - if (count < 2) return new List(); + // Abrufen der aktuellen Markt-Situation + int currentIndex = Bars.Count - 1; + double currentPrice = Bars.ClosePrices[currentIndex]; - double currentPrice = _bars.ClosePrices[currentIndex]; - double range = _currentDynamicRange; + // Engine aufrufen + // DecayPeriod ist wichtig für das interne Pruning der Engine + var result = _calculator.Calculate( + currentIndex, + currentPrice, + _currentDynamicRange, + DecayPeriod, + MaxZones + ); - // Score-First / Global Density Approach (Matches Indicator) - var candidates = _extremaPoints - .Select(p => { - double weightedScore = _extremaPoints - .Where(other => Math.Abs(other.Price - p.Price) <= range) - .Sum(other => GetWeight(other, currentIndex, currentPrice)); - - return new { Price = p.Price, Score = weightedScore }; - }) - .OrderByDescending(z => z.Score) - .ToList(); - - var topZones = new List(); - foreach (var zone in candidates) + if (result.Zones.Count == 0) { - // Filter Overlap - if (!topZones.Any(z => Math.Abs(z.Price - zone.Price) < range)) + ClearLines(); + return; + } + + DrawSignificance(result.Zones, result.TotalWeight); + } + + private void DrawSignificance(List zones, double totalWeightSum) + { + Color baseColor = Color.Aqua; + + // Wir iterieren bis MaxZones oder Listen-Ende. + // Die Engine gibt maximal 'MaxZones' zurück, aber sicher ist sicher. + int count = Math.Min(zones.Count, MaxZones); + + for (int i = 0; i < MaxZones; i++) + { + string lineId = $"SR_Line_{i}"; + string textId = $"SR_Text_{i}"; + + if (i < count && zones[i].Score > 0) { - // Normalize Score relative to total Weight of all points (Matches Indicator Normalization) - double totalWeightSum = _extremaPoints.Sum(p => GetWeight(p, currentIndex, currentPrice)); - double sigPercent = (totalWeightSum > 0) ? (zone.Score / totalWeightSum) * 100.0 : 0; + var zone = zones[i]; - topZones.Add(new ClusterLevel { Price = zone.Price, Significance = sigPercent }); + // Verhindere Division durch Null + double absSignificance = totalWeightSum > 0 ? zone.Score / totalWeightSum : 0; + + // Transparenz basierend auf Stärke + int alpha = (int)(Math.Sqrt(absSignificance) * 255); + alpha = Math.Clamp(alpha, 40, 255); + + Color sigColor = Color.FromArgb(alpha, baseColor.R, baseColor.G, baseColor.B); + + // Zeichnen + Chart.DrawHorizontalLine(lineId, zone.Price, sigColor, 2, LineStyle.Solid); + + string label = $" {absSignificance:P1}"; + Chart.DrawText(textId, label, Chart.LastVisibleBarIndex, zone.Price, sigColor); + } + else + { + // Aufräumen nicht benutzter Linien-Slots + Chart.RemoveObject(lineId); + Chart.RemoveObject(textId); } } - - return topZones; } - private double GetWeight(ExtremumPoint point, int currentIndex, double currentPrice) + private void ClearLines() { - double weight = Math.Max(0.0, 1.0 - ((double)(currentIndex - point.Index) / _config.DecayPeriod)); - if ((point.Type == PointType.Peak) && (point.Price < currentPrice)) weight *= 2.0; - else if ((point.Type == PointType.Trough) && (point.Price > currentPrice)) weight *= 2.0; - return weight; + for (int i = 0; i < MaxZones; i++) + { + Chart.RemoveObject($"SR_Line_{i}"); + Chart.RemoveObject($"SR_Text_{i}"); + } } } } \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.csproj b/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.csproj index da1fef1..866383b 100644 --- a/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.csproj +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/HmaClusterSR.csproj @@ -1,9 +1,14 @@ + net6.0 - - + + + ..\..\..\Common\MSLib\obj\Debug\net6.0\MSLib.dll + + + \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..32c95f9 --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.AssemblyInfo.cs b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.AssemblyInfo.cs new file mode 100644 index 0000000..ff2bfe8 --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("HmaClusterSR")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("HmaClusterSR")] +[assembly: System.Reflection.AssemblyTitleAttribute("HmaClusterSR")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.AssemblyInfoInputs.cache b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.AssemblyInfoInputs.cache new file mode 100644 index 0000000..81b1cbc --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +9e01ea14fd7f1cf3abff0b8c1e9bec07e427b59e diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.GeneratedMSBuildEditorConfig.editorconfig b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..04fe673 --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,10 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = HmaClusterSR +build_property.ProjectDir = C:\Users\Brummel\Documents\cAlgo\Sources\Indicators\HmaClusterSR\HmaClusterSR\ diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.assets.cache b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.assets.cache new file mode 100644 index 0000000..b1b7b3c Binary files /dev/null and b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.assets.cache differ diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.csproj.AssemblyReference.cache b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.csproj.AssemblyReference.cache new file mode 100644 index 0000000..50043b7 Binary files /dev/null and b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/Debug/net6.0/HmaClusterSR.csproj.AssemblyReference.cache differ diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.dgspec.json b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.dgspec.json new file mode 100644 index 0000000..5046328 --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.dgspec.json @@ -0,0 +1,66 @@ +{ + "format": 1, + "restore": { + "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj": {} + }, + "projects": { + "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj", + "projectName": "HmaClusterSR", + "projectPath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj", + "packagesPath": "C:\\Users\\Brummel\\.nuget\\packages\\", + "outputPath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\Brummel\\AppData\\Roaming\\NuGet\\NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "cTrader.Automate": { + "target": "Package", + "version": "[*, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\6.0.200\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.g.props b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.g.props new file mode 100644 index 0000000..0b161ac --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.g.props @@ -0,0 +1,21 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\Brummel\.nuget\packages\ + PackageReference + 6.1.0 + + + + + + + + + C:\Users\Brummel\.nuget\packages\ctrader.automate\1.0.14 + + \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.g.targets b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.g.targets new file mode 100644 index 0000000..46f142c --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/HmaClusterSR.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/project.assets.json b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/project.assets.json new file mode 100644 index 0000000..de99536 --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/project.assets.json @@ -0,0 +1,139 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "cTrader.Automate/1.0.14": { + "type": "package", + "compile": { + "lib/net6.0/cAlgo.API.dll": {} + }, + "runtime": { + "lib/net6.0/cAlgo.API.dll": {} + }, + "build": { + "build/cTrader.Automate.props": {}, + "build/cTrader.Automate.targets": {} + } + } + } + }, + "libraries": { + "cTrader.Automate/1.0.14": { + "sha512": "eNwE7WL90MGBKb5MuLAtZLdQy0vxkI5EVhLWAQ9S83EAdYkGAzdccvGFLk2oqmtSGBtD+gEpyrJUW/ej4dI4jw==", + "type": "package", + "path": "ctrader.automate/1.0.14", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/cTrader.Automate.props", + "build/cTrader.Automate.targets", + "ctrader.automate.1.0.14.nupkg.sha512", + "ctrader.automate.nuspec", + "eula.md", + "icon.png", + "lib/net40/cAlgo.API.dll", + "lib/net40/cAlgo.API.xml", + "lib/net6.0/cAlgo.API.dll", + "lib/net6.0/cAlgo.API.xml", + "tools/net472/Core.AlgoFormat.Compose.Reflection.dll", + "tools/net472/Core.AlgoFormat.Writer.dll", + "tools/net472/Core.AlgoFormat.dll", + "tools/net472/Core.Domain.Primitives.dll", + "tools/net472/Newtonsoft.Json.dll", + "tools/net472/System.Buffers.dll", + "tools/net472/System.Collections.Immutable.dll", + "tools/net472/System.Memory.dll", + "tools/net472/System.Numerics.Vectors.dll", + "tools/net472/System.Reflection.Metadata.dll", + "tools/net472/System.Reflection.MetadataLoadContext.dll", + "tools/net472/System.Runtime.CompilerServices.Unsafe.dll", + "tools/net472/cTrader.Automate.Sdk.Tasks.dll", + "tools/net6.0/Core.AlgoFormat.Compose.Reflection.dll", + "tools/net6.0/Core.AlgoFormat.Writer.dll", + "tools/net6.0/Core.AlgoFormat.dll", + "tools/net6.0/Core.Connection.Protobuf.Common.dll", + "tools/net6.0/Core.Domain.Primitives.dll", + "tools/net6.0/Microsoft.Win32.SystemEvents.dll", + "tools/net6.0/Newtonsoft.Json.dll", + "tools/net6.0/System.Drawing.Common.dll", + "tools/net6.0/System.Reflection.MetadataLoadContext.dll", + "tools/net6.0/System.Security.Permissions.dll", + "tools/net6.0/System.Windows.Extensions.dll", + "tools/net6.0/cTrader.Automate.Sdk.Tasks.dll", + "tools/net6.0/protobuf-net.Core.dll", + "tools/net6.0/protobuf-net.dll", + "tools/net6.0/runtimes/unix/lib/net6.0/System.Drawing.Common.dll", + "tools/net6.0/runtimes/win/lib/net6.0/Microsoft.Win32.SystemEvents.dll", + "tools/net6.0/runtimes/win/lib/net6.0/System.Drawing.Common.dll", + "tools/net6.0/runtimes/win/lib/net6.0/System.Windows.Extensions.dll" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "cTrader.Automate >= *" + ] + }, + "packageFolders": { + "C:\\Users\\Brummel\\.nuget\\packages\\": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj", + "projectName": "HmaClusterSR", + "projectPath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj", + "packagesPath": "C:\\Users\\Brummel\\.nuget\\packages\\", + "outputPath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\Brummel\\AppData\\Roaming\\NuGet\\NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "cTrader.Automate": { + "target": "Package", + "version": "[*, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\6.0.200\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/project.nuget.cache b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/project.nuget.cache new file mode 100644 index 0000000..e377815 --- /dev/null +++ b/Sources/Indicators/HmaClusterSR/HmaClusterSR/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "44vzUq/Lw+XLcrX6CWh7QZnxKTbL7SBSGBbM9ijWJIaHajpDybp1KWXAjmIYPIEKiHbzs2dgB4Wmenl5+uQxng==", + "success": true, + "projectFilePath": "C:\\Users\\Brummel\\Documents\\cAlgo\\Sources\\Indicators\\HmaClusterSR\\HmaClusterSR\\HmaClusterSR.csproj", + "expectedPackageFiles": [ + "C:\\Users\\Brummel\\.nuget\\packages\\ctrader.automate\\1.0.14\\ctrader.automate.1.0.14.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/Sources/Robots/HmaClusterBot.algo b/Sources/Robots/HmaClusterBot.algo index c70f58c..0bc74a9 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 6a1f1b9..bb96d2a 100644 --- a/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.cs +++ b/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.cs @@ -7,6 +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 namespace cAlgo.Robots { @@ -71,12 +72,12 @@ namespace cAlgo.Robots protected override void OnStart() { - try + try { if (string.IsNullOrWhiteSpace(SymbolsCsv)) { Print("CSV is empty. Running in Single-Symbol Mode on Chart Symbol."); - + var config = new StrategyConfig { SymbolName = SymbolName, @@ -129,6 +130,10 @@ 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)) { string formattedMsg = $"⚠️ ERROR @ {DateTime.UtcNow:HH:mm:ss} UTC\n\n{message}"; @@ -138,6 +143,8 @@ namespace cAlgo.Robots private async Task SendTelegramRawAsync(string token, string chatId, string message) { + if (IsBacktesting) return; + try { string url = $"https://api.telegram.org/bot{token}/sendMessage?chat_id={chatId}&text={Uri.EscapeDataString(message)}&parse_mode=HTML"; @@ -152,7 +159,7 @@ namespace cAlgo.Robots private void ParseCsvAndCreateStrategies() { var normalizedCsv = SymbolsCsv.Replace("\n", ",").Replace("\r", ","); - + var tokens = normalizedCsv.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .Where(t => !string.IsNullOrEmpty(t)) @@ -195,9 +202,8 @@ namespace cAlgo.Robots BiasDeviationAvgPeriod = int.Parse(tokens[i + 7], CultureInfo.InvariantCulture), UseDynamicPositionManagement = bool.Parse(tokens[i + 8]), SendTelegramOnly = bool.Parse(tokens[i + 9]), - - // Defaults from global params - CloseProfitOnBiasFlip = CloseProfitOnBiasFlip, + + CloseProfitOnBiasFlip = CloseProfitOnBiasFlip, RiskPercent = RiskPercent, MaxPoints = MaxPoints, DecayPeriod = DecayPeriod @@ -239,16 +245,8 @@ namespace cAlgo.Robots { #region Types & Fields - private enum PointType { Peak, Trough } private enum Bias { Long, Short, Neutral } - private struct ExtremumPoint - { - public double Price; - public int Index; - public PointType Type; - } - public struct ClusterLevel { public double Price; @@ -270,13 +268,14 @@ namespace cAlgo.Robots private readonly Queue _deviationQueue = new Queue(); private double _runningDeviationSum; - + private bool _deviationConditionMetInCurrentCycle; private bool _isTradingAllowedBasedOnPrevCycle; - private readonly List _extremaPoints = new(); + // --- OPTIMIERUNG: Nutzt Calculator statt Liste --- + private readonly Myc.ClusterCalculator _clusterCalculator; private readonly List _amplitudes = new(); - + private double _trendExtremum; private int _trendExtremumIndex; private double _lastExtremumPrice; @@ -288,12 +287,12 @@ namespace cAlgo.Robots #endregion public ClusterStrategy( - Robot robot, - Symbol symbol, - Bars bars, - StrategyConfig config, - HttpClient httpClient, - string token, + Robot robot, + Symbol symbol, + Bars bars, + StrategyConfig config, + HttpClient httpClient, + string token, string chatId, Action errorCallback) { @@ -305,17 +304,20 @@ namespace cAlgo.Robots _botToken = token; _chatId = chatId; _errorCallback = errorCallback; + + // Calculator mit Reserve initialisieren + _clusterCalculator = new Myc.ClusterCalculator(_config.MaxPoints + 200); } public void Start() { int requiredBars = Math.Max(_config.SmaBiasPeriod, _config.HmaBiasPeriod); - requiredBars = Math.Max(requiredBars, _config.BiasDeviationAvgPeriod) + 10; + requiredBars = Math.Max(requiredBars, _config.BiasDeviationAvgPeriod) + 10; while (_bars.Count < requiredBars) { int loaded = _bars.LoadMoreHistory(); - if (loaded == 0) + if (loaded == 0) { _errorCallback?.Invoke($"Not enough history for {_config.SymbolName}. Loaded: {_bars.Count}, Req: {requiredBars}"); return; @@ -332,11 +334,11 @@ namespace cAlgo.Robots int startIndex = Math.Max(_config.SmaBiasPeriod, _config.HmaBiasPeriod); startIndex = Math.Max(startIndex, _config.BiasDeviationAvgPeriod); - + for (int i = startIndex; i < _bars.Count; i++) { UpdateFilterState(i); - UpdateClusterData(i); + UpdateClusterData(i); } _bars.BarOpened += OnBarOpened; @@ -356,24 +358,21 @@ namespace cAlgo.Robots UpdateFilterState(index); UpdateClusterData(index); - + var clusters = CalculateClusters(index); - // 1. Dynamic SL/TP Management if (!_config.SendTelegramOnly && _config.UseDynamicPositionManagement && clusters.Count >= 2) { ManagePositions(clusters); } - + var currentBias = GetCurrentBias(index); - // 2. Check for Profit Close on Bias Flip if (!_config.SendTelegramOnly && _config.CloseProfitOnBiasFlip) { CloseReversedPositions(currentBias); } - // 3. New Entry Logic with FIXED Orphan-Cleanup and Validations ManageOrders(currentBias, index, clusters); } catch (Exception ex) @@ -389,7 +388,7 @@ namespace cAlgo.Robots foreach (var pos in _robot.Positions) { if (pos.SymbolName != _config.SymbolName || pos.Label != Label) continue; - if (pos.NetProfit <= 0) continue; + if (pos.NetProfit <= 0) continue; bool close = false; @@ -405,7 +404,7 @@ namespace cAlgo.Robots { string msg = $"🔒 CLOSE PROFIT (Bias Flip) @ {_config.SymbolName}\n" + $"Profit: {pos.NetProfit:F2}"; - _ = SendTelegramMessageAsync(msg); + _ = SendTelegramMessageAsync(msg); } } } @@ -419,7 +418,7 @@ namespace cAlgo.Robots double prevSma = _smaBias.Result[index - 1]; double currentBiasDeviation = Math.Abs(currHma - currSma); - + _deviationQueue.Enqueue(currentBiasDeviation); _runningDeviationSum += currentBiasDeviation; @@ -429,8 +428,8 @@ namespace cAlgo.Robots _runningDeviationSum -= removed; } - double averageDeviation = (_deviationQueue.Count > 0) - ? _runningDeviationSum / _deviationQueue.Count + double averageDeviation = (_deviationQueue.Count > 0) + ? _runningDeviationSum / _deviationQueue.Count : 0.0; bool currHmaAbove = currHma > currSma; @@ -462,7 +461,7 @@ namespace cAlgo.Robots private void ManagePositions(List clusters) { - double pNow = _symbol.Bid; + double pNow = _symbol.Bid; foreach (var pos in _robot.Positions) { @@ -509,7 +508,7 @@ namespace cAlgo.Robots } } } - else // Sell + else { double lowestSlPrice = double.MaxValue; double lowestTpPrice = double.MaxValue; @@ -552,10 +551,9 @@ namespace cAlgo.Robots private void ManageOrders(Bias bias, int index, List clusters) { - // Standard Cleanup: Orders in wrong direction (Bias Change) CleanupWrongBiasOrders(bias); - if (_config.UseBiasDeviationFilter && !_isTradingAllowedBasedOnPrevCycle) + if (_config.UseBiasDeviationFilter && !_isTradingAllowedBasedOnPrevCycle) return; if (bias == Bias.Neutral) return; @@ -565,11 +563,9 @@ namespace cAlgo.Robots bool hasLong = _robot.Positions.Any(p => p.SymbolName == _config.SymbolName && p.Label == Label && p.TradeType == TradeType.Buy); bool hasShort = _robot.Positions.Any(p => p.SymbolName == _config.SymbolName && p.Label == Label && p.TradeType == TradeType.Sell); - // --- FIX 1: Open Positions Cleanup --- - // If we are already invested, we ensure no pending orders for the same direction are lingering around. if (bias == Bias.Long && hasLong) { - CancelPendingOrders(TradeType.Buy); + CancelPendingOrders(TradeType.Buy); return; } if (bias == Bias.Short && hasShort) @@ -723,38 +719,18 @@ namespace cAlgo.Robots { var existingOrder = _robot.PendingOrders.FirstOrDefault(o => o.SymbolName == _config.SymbolName && o.Label == Label && o.TradeType == type); - // --- FIX 4: Market Proximity Check --- - // If the limit price is invalid (e.g. Buy Limit above Ask), we must abort/cancel. - bool priceInvalid = false; - double buffer = _symbol.PipSize; + double buffer = _symbol.PipSize; + if (type == TradeType.Buy && entry >= (_symbol.Ask - buffer)) return; + if (type == TradeType.Sell && entry <= (_symbol.Bid + buffer)) return; - if (type == TradeType.Buy && entry >= (_symbol.Ask - buffer)) priceInvalid = true; - if (type == TradeType.Sell && entry <= (_symbol.Bid + buffer)) priceInvalid = true; - - if (priceInvalid) - { - if (existingOrder != null) _robot.CancelPendingOrder(existingOrder); - return; - } - - // --- FIX 3: SL Distance Check --- double slDistPips = Math.Abs(entry - sl) / _symbol.PipSize; - if (slDistPips <= 0) - { - if (existingOrder != null) _robot.CancelPendingOrder(existingOrder); - return; - } + if (slDistPips <= 0) return; - // --- FIX 2: Volume Check --- double riskAmount = _robot.Account.Balance * (_config.RiskPercent / 100.0); double volume = _symbol.VolumeForFixedRisk(riskAmount, slDistPips); volume = _symbol.NormalizeVolumeInUnits(volume, RoundingMode.Down); - if (volume < _symbol.VolumeInUnitsMin) - { - if (existingOrder != null) _robot.CancelPendingOrder(existingOrder); - return; - } + if (volume < _symbol.VolumeInUnitsMin) return; double lots = _symbol.VolumeInUnitsToQuantity(volume); @@ -763,11 +739,11 @@ namespace cAlgo.Robots string directionStr = type == TradeType.Buy ? "BUY" : "SELL"; string directionIcon = type == TradeType.Buy ? "📈" : "📉"; string msg = $"{directionIcon} {directionStr} Signal @ {_config.SymbolName}\n\n" + - $"Entry: {entry}\n" + - $"SL: {sl}\n" + - $"TP: {tp}\n" + - $"Vol: {lots:F2} Lots"; - + $"Entry: {entry}\n" + + $"SL: {sl}\n" + + $"TP: {tp}\n" + + $"Vol: {lots:F2} Lots"; + _ = SendTelegramMessageAsync(msg); return; } @@ -784,16 +760,13 @@ namespace cAlgo.Robots var result = _robot.ModifyPendingOrder(existingOrder, entry, sl, tp, ProtectionType.Absolute, null, volume); if (!result.IsSuccessful) { - // Fallback: If modify fails (e.g. spread jump), cancel it to avoid stale orders + // Falls Modifikation fehlschlägt (z.B. Spread), löschen wir die Order, um keine veralteten Levels zu handeln _robot.CancelPendingOrder(existingOrder); } } } else { - _robot.Print("[SIGNAL] {0} {1} | Entry: {2} | SL: {3} | TP: {4} | Vol: {5:F2} Lots", - (type == TradeType.Buy ? "BUY" : "SELL"), _config.SymbolName, entry, sl, tp, lots); - _robot.PlaceLimitOrder(type, _config.SymbolName, volume, entry, Label, sl, tp, ProtectionType.Absolute); } } @@ -807,7 +780,7 @@ namespace cAlgo.Robots { string url = $"https://api.telegram.org/bot{_botToken}/sendMessage?chat_id={_chatId}&text={Uri.EscapeDataString(message)}&parse_mode=HTML"; HttpResponseMessage response = await _httpClient.GetAsync(url); - + if (!response.IsSuccessStatusCode) { _errorCallback?.Invoke($"Telegram Error: {response.StatusCode}"); @@ -842,11 +815,18 @@ namespace cAlgo.Robots if (_amplitudes.Count > 50) _amplitudes.RemoveAt(0); double sum = 0; - for (int i = 0; i < _amplitudes.Count; i++) sum += _amplitudes[i]; + for(int i=0; i<_amplitudes.Count; i++) sum += _amplitudes[i]; _currentDynamicRange = (sum / _amplitudes.Count) * 0.5; + if (_currentDynamicRange < _symbol.PipSize) _currentDynamicRange = _symbol.PipSize; } - _extremaPoints.Add(new ExtremumPoint { Price = _trendExtremum, Index = _trendExtremumIndex, Type = _isUpTrend.Value ? PointType.Peak : PointType.Trough }); - if (_extremaPoints.Count > _config.MaxPoints) _extremaPoints.RemoveAt(0); + + // Neuen Punkt in den optimierten Calculator einspeisen + _clusterCalculator.AddPoint(new Myc.ExtremumPoint + { + Price = _trendExtremum, + Index = _trendExtremumIndex, + Type = _isUpTrend.Value ? Myc.PointType.Peak : Myc.PointType.Trough + }); _lastExtremumPrice = _trendExtremum; _isUpTrend = currentDirectionUp; @@ -880,57 +860,23 @@ namespace cAlgo.Robots private List CalculateClusters(int currentIndex) { - int count = _extremaPoints.Count; - if (count == 0) return new List(); - double currentPrice = _bars.ClosePrices[currentIndex]; - double[] weights = new double[count]; - double totalWeightSum = 0; - for (int i = 0; i < count; i++) + var result = _clusterCalculator.Calculate( + currentIndex, + currentPrice, + _currentDynamicRange, + _config.DecayPeriod, + 100 + ); + + if (result.TotalWeight == 0 || result.Zones.Count == 0) return new List(); + + return result.Zones.Select(z => new ClusterLevel { - weights[i] = GetWeight(_extremaPoints[i], currentIndex, currentPrice); - totalWeightSum += weights[i]; - } - - if (totalWeightSum == 0) return new List(); - - var zones = new List(); - for (int i = count - 1; i >= 0; i--) - { - var p = _extremaPoints[i]; - - bool exists = false; - for (int j = 0; j < zones.Count; j++) - { - if (Math.Abs(zones[j].Price - p.Price) < _currentDynamicRange) - { - exists = true; - break; - } - } - if (exists) continue; - - double score = 0; - for (int k = 0; k < count; k++) - { - if (Math.Abs(_extremaPoints[k].Price - p.Price) <= _currentDynamicRange) - { - score += weights[k]; - } - } - - zones.Add(new ClusterLevel { Price = p.Price, Significance = (score / totalWeightSum) * 100.0 }); - } - return zones; - } - - private double GetWeight(ExtremumPoint point, int currentIndex, double currentPrice) - { - double weight = Math.Max(0.0, 1.0 - ((double)(currentIndex - point.Index) / _config.DecayPeriod)); - if ((point.Type == PointType.Peak) && (point.Price < currentPrice)) weight *= 2.0; - else if ((point.Type == PointType.Trough) && (point.Price > currentPrice)) weight *= 2.0; - return weight; + Price = z.Price, + Significance = (z.Score / result.TotalWeight) * 100.0 + }).ToList(); } } } \ No newline at end of file diff --git a/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.csproj b/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.csproj index c8ec96f..866383b 100644 --- a/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.csproj +++ b/Sources/Robots/HmaClusterBot/HmaClusterBot/HmaClusterBot.csproj @@ -6,4 +6,9 @@ + + + ..\..\..\Common\MSLib\obj\Debug\net6.0\MSLib.dll + + \ No newline at end of file