diff --git a/Core/Main/PTMagic.cs b/Core/Main/PTMagic.cs index 9c88b8a..eea3e5f 100644 --- a/Core/Main/PTMagic.cs +++ b/Core/Main/PTMagic.cs @@ -40,7 +40,8 @@ namespace Core.Main private DateTime _lastVersionCheck = Constants.confMinDate; private DateTime _lastFiatCurrencyCheck = Constants.confMinDate; private string _lastSetting = ""; - private string _activeSetting = ""; + private string _activeSettingName = ""; + private GlobalSetting _activeSetting = null; private string _defaultSettingName = ""; private string _pairsFileName = "PAIRS.PROPERTIES"; private string _dcaFileName = "DCA.PROPERTIES"; @@ -255,19 +256,7 @@ namespace Core.Main } } - public string LastSetting - { - get - { - return _lastSetting; - } - set - { - _lastSetting = value; - } - } - - public string ActiveSetting + public GlobalSetting ActiveSetting { get { @@ -279,6 +268,18 @@ namespace Core.Main } } + public string ActiveSettingName + { + get + { + return _activeSettingName; + } + set + { + _activeSettingName = value; + } + } + public string PairsFileName { get @@ -589,6 +590,11 @@ namespace Core.Main // Force settings refresh first time EnforceSettingsReapply = true; + // Set the Active config + this.ActiveSetting = this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Find(s => s.SettingName.Equals(this.DefaultSettingName, StringComparison.InvariantCultureIgnoreCase)); + this.ActiveSettingName = ActiveSetting.SettingName; + this.LastSettingsChange = DateTime.UtcNow; + // Start polling this.StartPTMagicIntervalTimer(); @@ -846,12 +852,10 @@ namespace Core.Main { this.RunCount++; - bool headerLinesAdded = false; this.EnforceSettingsReapply = this.HaveSettingsChanged() || this.EnforceSettingsReapply; if (PTMagicConfiguration.GeneralSettings.Application.IsEnabled) { - // Validate settings this.ValidateSettings(); @@ -901,19 +905,19 @@ namespace Core.Main this.CheckGlobalSettingsTriggers(ref triggeredSetting, ref matchedTriggers); // Activate global setting - this.ActivateSetting(ref headerLinesAdded, ref triggeredSetting, ref matchedTriggers); + this.ActivateSetting(ref triggeredSetting, ref matchedTriggers); // Check for single market trend triggers this.ApplySingleMarketSettings(); // Save new properties to Profit Trailer - this.SaveProfitTrailerProperties(headerLinesAdded); + this.SaveProfitTrailerProperties(); // Save Single Market Settings Summary this.SaveSingleMarketSettingsSummary(); // Save Runtime Summary - this.SaveRuntimeSummary(headerLinesAdded); + this.SaveRuntimeSummary(); // Cleanup to free memory in between intervals this.Cleanup(); @@ -1107,15 +1111,10 @@ namespace Core.Main private void LoadCurrentProfitTrailerProperties() { // Load current PT properties from API (Valid for PT 2.x and above) - this.Log.DoLogInfo("Loading current Profit Trailer properties from API..."); + this.Log.DoLogInfo("Loading current Profit Trailer properties from preset files..."); - // Get current PT properties - string pairsPropertiesPath, dcaPropertiesPath, indicatorsPropertiesPath; - GetProfitTrailerPropertiesPaths(out pairsPropertiesPath, out dcaPropertiesPath, out indicatorsPropertiesPath); - - this.PairsLines = SettingsAPI.GetPropertyLinesFromAPI("PAIRS", this.PTMagicConfiguration, this.Log); - this.DCALines = SettingsAPI.GetPropertyLinesFromAPI("DCA", this.PTMagicConfiguration, this.Log); - this.IndicatorsLines = SettingsAPI.GetPropertyLinesFromAPI("INDICATORS", this.PTMagicConfiguration, this.Log); + // Get current preset file PT properties + SettingsHandler.CompileProperties(this, this.ActiveSetting, this.LastSettingsChange.ToLocalTime()); if (this.PairsLines != null && this.DCALines != null && this.IndicatorsLines != null) { @@ -1363,21 +1362,13 @@ namespace Core.Main } } - private void ActivateSetting(ref bool headerLinesAdded, ref GlobalSetting triggeredSetting, ref List matchedTriggers) + private void ActivateSetting(ref GlobalSetting triggeredSetting, ref List matchedTriggers) { - // Get the current active setting - string activeSettingName = SettingsHandler.GetActiveSetting(this, ref headerLinesAdded); - if (String.IsNullOrEmpty(activeSettingName) && this.PTMagicConfiguration.GeneralSettings.Application.TestMode) - { - activeSettingName = this.ActiveSetting; - } - GlobalSetting activeSetting = this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Find(s => s.SettingName.Equals(activeSettingName, StringComparison.InvariantCultureIgnoreCase)); - // Do we need to write the settings? - if (this.EnforceSettingsReapply || !activeSettingName.Equals(triggeredSetting.SettingName, StringComparison.InvariantCultureIgnoreCase)) + if (this.EnforceSettingsReapply || !this.ActiveSettingName.Equals(triggeredSetting.SettingName, StringComparison.InvariantCultureIgnoreCase)) { // Check if we need to force a refresh of the settings - this.Log.DoLogInfo("Setting '" + activeSettingName + "' currently active. Checking for flood protection..."); + this.Log.DoLogInfo("Setting '" + this.ActiveSettingName + "' currently active. Checking for flood protection..."); // If the setting we are about to activate is the default one, do not list matched triggers if (triggeredSetting.SettingName.Equals(this.DefaultSettingName, StringComparison.InvariantCultureIgnoreCase)) @@ -1389,7 +1380,7 @@ namespace Core.Main if (this.EnforceSettingsReapply || this.LastSettingsChange <= DateTime.UtcNow.AddMinutes(-PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes)) { // Setting not set => Change setting - if (!EnforceSettingsReapply) + if (!this.ActiveSettingName.Equals(triggeredSetting.SettingName, StringComparison.InvariantCultureIgnoreCase)) { this.Log.DoLogInfo("Switching global settings to '" + triggeredSetting.SettingName + "'..."); } @@ -1398,44 +1389,51 @@ namespace Core.Main this.Log.DoLogInfo("Applying '" + triggeredSetting.SettingName + "' as the settings.analyzer.json or a preset file got changed."); } - SettingsHandler.CompileProperties(this, triggeredSetting); + // Get file lines from the preset files + SettingsHandler.CompileProperties(this, triggeredSetting, DateTime.Now); this.GlobalSettingWritten = true; - this.Log.DoLogInfo("Setting '" + triggeredSetting.SettingName + "' now active!"); + // Record the switch in the runtime summary this.LastRuntimeSummary.LastGlobalSettingSwitch = this.LastRuntimeSummary.LastRuntime; this.LastRuntimeSummary.CurrentGlobalSetting = triggeredSetting; - // Build Telegram message - string telegramMessage; - telegramMessage = this.PTMagicConfiguration.GeneralSettings.Application.InstanceName + ": Setting switched to '*" + SystemHelper.SplitCamelCase(triggeredSetting.SettingName) + "*'."; - - if (matchedTriggers.Count > 0) - { - telegramMessage += "\n\n*Matching Triggers:*"; - foreach (string triggerResult in matchedTriggers) - { - telegramMessage += "\n" + triggerResult; - } - } - - if (this.AverageMarketTrendChanges.Keys.Count > 0) - { - telegramMessage += "\n\n*Market Trends:*"; - foreach (string key in this.AverageMarketTrendChanges.Keys) - { - telegramMessage += "\n" + key + ": " + this.AverageMarketTrendChanges[key].ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%"; - } - } - - // Send Telegram message - if (this.PTMagicConfiguration.GeneralSettings.Telegram.IsEnabled) - { - TelegramHelper.SendMessage(this.PTMagicConfiguration.GeneralSettings.Telegram.BotToken, this.PTMagicConfiguration.GeneralSettings.Telegram.ChatId, telegramMessage, this.PTMagicConfiguration.GeneralSettings.Telegram.SilentMode, this.Log); - } - // Record last settings run - this.LastSetting = activeSettingName; this.LastSettingsChange = DateTime.UtcNow; + + // Build Telegram message + try + { + string telegramMessage; + telegramMessage = this.PTMagicConfiguration.GeneralSettings.Application.InstanceName + ": Setting switched to '*" + SystemHelper.SplitCamelCase(triggeredSetting.SettingName) + "*'."; + + if (matchedTriggers.Count > 0) + { + telegramMessage += "\n\n*Matching Triggers:*"; + foreach (string triggerResult in matchedTriggers) + { + telegramMessage += "\n" + triggerResult; + } + } + + if (this.AverageMarketTrendChanges.Keys.Count > 0) + { + telegramMessage += "\n\n*Market Trends:*"; + foreach (string key in this.AverageMarketTrendChanges.Keys) + { + telegramMessage += "\n" + key + ": " + this.AverageMarketTrendChanges[key].ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%"; + } + } + + // Send Telegram message + if (this.PTMagicConfiguration.GeneralSettings.Telegram.IsEnabled) + { + TelegramHelper.SendMessage(this.PTMagicConfiguration.GeneralSettings.Telegram.BotToken, this.PTMagicConfiguration.GeneralSettings.Telegram.ChatId, telegramMessage, this.PTMagicConfiguration.GeneralSettings.Telegram.SilentMode, this.Log); + } + } + catch (Exception ex) + { + this.Log.DoLogCritical("Failed to send Telegram message", ex); + } } else { @@ -1443,7 +1441,7 @@ namespace Core.Main this.Log.DoLogInfo("Flood protection active until " + this.LastSettingsChange.AddMinutes(PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes).ToString() + " (UTC). Not switching settings to '" + triggeredSetting.SettingName + "'!"); this.LastRuntimeSummary.FloodProtectedSetting = triggeredSetting; - this.LastRuntimeSummary.CurrentGlobalSetting = activeSetting; + this.LastRuntimeSummary.CurrentGlobalSetting = this.ActiveSetting; } } else @@ -1456,7 +1454,9 @@ namespace Core.Main this.LastRuntimeSummary.CurrentGlobalSetting = triggeredSetting; } - this.ActiveSetting = this.LastRuntimeSummary.CurrentGlobalSetting.SettingName; + // Set Active settings + this.ActiveSetting = this.LastRuntimeSummary.CurrentGlobalSetting; + this.ActiveSettingName = this.ActiveSetting.SettingName; } private void ApplySingleMarketSettings() @@ -1494,17 +1494,17 @@ namespace Core.Main // Check ignore global settings List ignoredGlobalSettings = SystemHelper.ConvertTokenStringToList(marketSetting.IgnoredGlobalSettings, ","); - if (ignoredGlobalSettings.Contains(this.ActiveSetting)) + if (ignoredGlobalSettings.Contains(this.ActiveSettingName)) { - this.Log.DoLogDebug("'" + marketPair + "' - '" + this.ActiveSetting + "' - Is ignored in '" + marketSetting.SettingName + "'."); + this.Log.DoLogDebug("'" + marketPair + "' - '" + this.ActiveSettingName + "' - Is ignored in '" + marketSetting.SettingName + "'."); continue; } // Check allowed global settings List allowedGlobalSettings = SystemHelper.ConvertTokenStringToList(marketSetting.AllowedGlobalSettings, ","); - if (allowedGlobalSettings.Count > 0 && !allowedGlobalSettings.Contains(this.ActiveSetting)) + if (allowedGlobalSettings.Count > 0 && !allowedGlobalSettings.Contains(this.ActiveSettingName)) { - this.Log.DoLogDebug("'" + marketPair + "' - '" + this.ActiveSetting + "' - Is not allowed in '" + marketSetting.SettingName + "'."); + this.Log.DoLogDebug("'" + marketPair + "' - '" + this.ActiveSettingName + "' - Is not allowed in '" + marketSetting.SettingName + "'."); continue; } @@ -2025,25 +2025,28 @@ namespace Core.Main } } - private void SaveProfitTrailerProperties(bool headerLinesAdded) + private void SaveProfitTrailerProperties() { // Get current PT properties string pairsPropertiesPath, dcaPropertiesPath, indicatorsPropertiesPath; GetProfitTrailerPropertiesPaths(out pairsPropertiesPath, out dcaPropertiesPath, out indicatorsPropertiesPath); - if (headerLinesAdded || this.GlobalSettingWritten || this.SingleMarketSettingWritten) + if (this.GlobalSettingWritten || this.SingleMarketSettingWritten) { // Save current PT properties to API (Valid for PT 2.x and above) this.Log.DoLogInfo("Saving properties using API..."); // Send all Properties - if (!this.PTMagicConfiguration.GeneralSettings.Application.TestMode) SettingsAPI.SendPropertyLinesToAPI(this.PairsLines, this.DCALines, this.IndicatorsLines, this.PTMagicConfiguration, this.Log); + if (!this.PTMagicConfiguration.GeneralSettings.Application.TestMode) + { + SettingsAPI.SendPropertyLinesToAPI(this.PairsLines, this.DCALines, this.IndicatorsLines, this.PTMagicConfiguration, this.Log); + } this.Log.DoLogInfo("Properties saved!"); } else { - this.Log.DoLogInfo("Nothing changed, no files touched!"); + this.Log.DoLogInfo("Nothing changed, no config written!"); } } @@ -2058,7 +2061,7 @@ namespace Core.Main this.Log.DoLogInfo("Single Market Settings Summary saved."); } - private void SaveRuntimeSummary(bool headerLinesAdded) + private void SaveRuntimeSummary() { DateTime endTime = DateTime.UtcNow; int elapsedSeconds = (int)Math.Round(endTime.Subtract(this.LastRuntime).TotalSeconds, 0); @@ -2523,7 +2526,7 @@ namespace Core.Main this.Log.DoLogInfo("+ Time spent: " + SystemHelper.GetProperDurationTime(elapsedSeconds)); this.Log.DoLogInfo("+ Active setting: " + this.LastRuntimeSummary.CurrentGlobalSetting.SettingName); this.Log.DoLogInfo("+ Global setting changed: " + ((this.LastRuntimeSummary.LastGlobalSettingSwitch == this.LastRuntimeSummary.LastRuntime) ? "Yes" : "No") + " " + ((this.LastRuntimeSummary.FloodProtectedSetting != null) ? "(Flood protection!)" : "")); - this.Log.DoLogInfo("+ Files changed: " + (((headerLinesAdded || this.GlobalSettingWritten || this.SingleMarketSettingWritten) && !this.PTMagicConfiguration.GeneralSettings.Application.TestMode) ? "Yes" : "No")); + this.Log.DoLogInfo("+ Files changed: " + (((this.GlobalSettingWritten || this.SingleMarketSettingWritten) && !this.PTMagicConfiguration.GeneralSettings.Application.TestMode) ? "Yes" : "No")); this.Log.DoLogInfo("+ Markets with active single market settings: " + this.TriggeredSingleMarketSettings.Count.ToString()); foreach (string activeSMS in this.SingleMarketSettingsCount.Keys) { diff --git a/Core/ProfitTrailer/SettingsFiles.cs b/Core/ProfitTrailer/SettingsFiles.cs index cbae25a..e9350e4 100644 --- a/Core/ProfitTrailer/SettingsFiles.cs +++ b/Core/ProfitTrailer/SettingsFiles.cs @@ -39,31 +39,11 @@ namespace Core.ProfitTrailer } } - public static string GetActiveSetting(PTMagicConfiguration systemConfiguration, string pairsFileName, string dcaFileName, string indicatorsFileName, LogHelper log) - { - string pairsPropertiesPath = systemConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + pairsFileName; - - string result = SettingsFiles.GetActiveSettingFromFile(pairsPropertiesPath, systemConfiguration, log); - - if (result.Equals("")) - { - SettingsFiles.WriteHeaderLines(pairsPropertiesPath, "Default", systemConfiguration); - - string dcaPropertiesPath = systemConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + dcaFileName; - SettingsFiles.WriteHeaderLines(dcaPropertiesPath, "Default", systemConfiguration); - - string inditactorsPropertiesPath = systemConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + indicatorsFileName; - SettingsFiles.WriteHeaderLines(inditactorsPropertiesPath, "Default", systemConfiguration); - } - - return result; - } - public static void WriteHeaderLines(string filePath, string settingName, PTMagicConfiguration systemConfiguration) { // Writing Header lines List lines = File.ReadAllLines(filePath).ToList(); - lines.Insert(0, ""); + lines.Insert(0, "#"); lines.Insert(0, "# ####################################"); lines.Insert(0, "# PTMagic_LastChanged = " + DateTime.UtcNow.ToShortDateString() + " " + DateTime.UtcNow.ToShortTimeString()); lines.Insert(0, "# PTMagic_ActiveSetting = " + SystemHelper.StripBadCode(settingName, Constants.WhiteListProperties)); @@ -150,7 +130,6 @@ namespace Core.ProfitTrailer } } - if (forceCheck) { log.DoLogInfo("Checking automated settings for presets..."); diff --git a/Core/ProfitTrailer/SettingsHandler.cs b/Core/ProfitTrailer/SettingsHandler.cs index 39a5d1c..43d1cd7 100644 --- a/Core/ProfitTrailer/SettingsHandler.cs +++ b/Core/ProfitTrailer/SettingsHandler.cs @@ -136,55 +136,15 @@ namespace Core.ProfitTrailer return result; } - public static string GetActiveSetting(PTMagic ptmagicInstance, ref bool headerLinesAdded) + public static void WriteHeaderLines(string settingsName, DateTime settingsChangeTimestamp, List lines) { - string result = ""; - - if ((ptmagicInstance.PairsLines == null) || ptmagicInstance.PTMagicConfiguration.GeneralSettings.Application.TestMode) - { - // Return current active setting - result = ptmagicInstance.ActiveSetting; - } - else - { - // Determine from file lines - foreach (string line in ptmagicInstance.PairsLines) - { - if (line.IndexOf("PTMagic_ActiveSetting", StringComparison.InvariantCultureIgnoreCase) > -1) - { - result = line.Replace("PTMagic_ActiveSetting", "", StringComparison.InvariantCultureIgnoreCase); - result = result.Replace("#", ""); - result = result.Replace("=", "").Trim(); - result = SystemHelper.StripBadCode(result, Constants.WhiteListProperties); - break; - } - } - - if (result.Equals("")) - { - SettingsHandler.WriteHeaderLines("Pairs", ptmagicInstance); - SettingsHandler.WriteHeaderLines("DCA", ptmagicInstance); - SettingsHandler.WriteHeaderLines("Indicators", ptmagicInstance); - headerLinesAdded = true; - } - - } - - return result; - } - - public static void WriteHeaderLines(string fileType, PTMagic ptmagicInstance) - { - List fileLines = (List)ptmagicInstance.GetType().GetProperty(fileType + "Lines").GetValue(ptmagicInstance, null); - // Writing Header lines - fileLines.Insert(0, "#"); - fileLines.Insert(0, "# ####################################"); - fileLines.Insert(0, "# PTMagic_LastChanged = " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString()); - fileLines.Insert(0, "# PTMagic_ActiveSetting = " + SystemHelper.StripBadCode(ptmagicInstance.DefaultSettingName, Constants.WhiteListProperties)); - fileLines.Insert(0, "# ####################################"); - - ptmagicInstance.GetType().GetProperty(fileType + "Lines").SetValue(ptmagicInstance, fileLines); + lines.Insert(0, "#"); + lines.Insert(0, "# ####################################"); + lines.Insert(0, "# PTMagic_LastChanged = " + settingsChangeTimestamp.ToShortDateString() + " " + settingsChangeTimestamp.ToShortTimeString()); + lines.Insert(0, "# PTMagic_ActiveSetting = " + SystemHelper.StripBadCode(settingsName, Constants.WhiteListProperties)); + lines.Insert(0, "# ####### PTMagic Current Setting ########"); + lines.Insert(0, "# ####################################"); } public static Dictionary GetPropertiesAsDictionary(List propertyLines) @@ -229,27 +189,25 @@ namespace Core.ProfitTrailer return result; } - public static void CompileProperties(PTMagic ptmagicInstance, GlobalSetting setting) + public static void CompileProperties(PTMagic ptmagicInstance, GlobalSetting setting, DateTime settingTimestamp) { - SettingsHandler.BuildPropertyLines("Pairs", ptmagicInstance, setting); - SettingsHandler.BuildPropertyLines("DCA", ptmagicInstance, setting); - SettingsHandler.BuildPropertyLines("Indicators", ptmagicInstance, setting); + SettingsHandler.BuildPropertyLines("Pairs", ptmagicInstance, setting, settingTimestamp); + SettingsHandler.BuildPropertyLines("DCA", ptmagicInstance, setting, settingTimestamp); + SettingsHandler.BuildPropertyLines("Indicators", ptmagicInstance, setting, settingTimestamp); } - public static void BuildPropertyLines(string fileType, PTMagic ptmagicInstance, GlobalSetting setting) + public static void BuildPropertyLines(string fileType, PTMagic ptmagicInstance, GlobalSetting setting, DateTime settingLastChanged) { + bool headerLinesExist = false; List result = new List(); - List fileLines = (List)ptmagicInstance.GetType().GetProperty(fileType + "Lines").GetValue(ptmagicInstance, null); Dictionary properties = (Dictionary)setting.GetType().GetProperty(fileType + "Properties").GetValue(setting, null); if (properties != null) { - // Building Properties if (!setting.SettingName.Equals(ptmagicInstance.DefaultSettingName, StringComparison.InvariantCultureIgnoreCase) && ptmagicInstance.PTMagicConfiguration.GeneralSettings.Application.AlwaysLoadDefaultBeforeSwitch && !properties.ContainsKey("File")) { - // Load default settings as basis for the switch GlobalSetting defaultSetting = ptmagicInstance.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Find(a => a.SettingName.Equals(ptmagicInstance.DefaultSettingName, StringComparison.InvariantCultureIgnoreCase)); if (defaultSetting != null) @@ -283,27 +241,23 @@ namespace Core.ProfitTrailer } } - + // Check for PTM header in preset file // Loop through config line by line reprocessing where required. foreach (string line in fileLines) { if (line.IndexOf("PTMagic_ActiveSetting", StringComparison.InvariantCultureIgnoreCase) > -1) { - // Setting current active setting result.Add("# PTMagic_ActiveSetting = " + setting.SettingName); - + headerLinesExist = true; } else if (line.IndexOf("PTMagic_LastChanged", StringComparison.InvariantCultureIgnoreCase) > -1) { - // Setting last change datetime - result.Add("# PTMagic_LastChanged = " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString()); - + result.Add("# PTMagic_LastChanged = " + settingLastChanged.ToShortDateString() + " " + settingLastChanged.ToShortTimeString()); } else if (line.IndexOf("PTMagic_SingleMarketSettings", StringComparison.InvariantCultureIgnoreCase) > -1) { - // Single Market Settings will get overwritten every single run => crop the lines break; } @@ -342,6 +296,13 @@ namespace Core.ProfitTrailer } } + // Write header lines if required + if (!headerLinesExist) + { + WriteHeaderLines(setting.SettingName, settingLastChanged, result); + } + + // Save lines to current context for the file type ptmagicInstance.GetType().GetProperty(fileType + "Lines").SetValue(ptmagicInstance, result); }