Merge pull request #84 from djbadders/develop

Fixed issues where wrong lines were processed + minor UI fix for lists
This commit is contained in:
HojouFotytu 2019-03-06 16:48:37 +09:00 committed by GitHub
commit bb7a2bca30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 210 additions and 127 deletions

View File

@ -373,7 +373,7 @@ namespace Core.Helper
{
for (int i = 0; i < tokenList.Count; i++)
{
result += tokenList[i].Trim() + separator;
result += tokenList[i].Trim() + (i < (tokenList.Count - 1) ? separator : "");
}
if (cropDoubleSeparators) result = result.Replace(separator + separator, "");
@ -637,14 +637,11 @@ namespace Core.Helper
if (!property.ToString().Equals("true", StringComparison.InvariantCultureIgnoreCase) && !property.ToString().Equals("false", StringComparison.InvariantCultureIgnoreCase))
{
try
{
double resultDouble = Convert.ToDouble(property);
result = resultDouble.ToString(new System.Globalization.CultureInfo("en-US"));
}
catch
{
}
double resultDouble;
if (double.TryParse(property.ToString(), out resultDouble))
{
result = ((decimal)resultDouble).ToString();
}
}
else
{

View File

@ -61,6 +61,7 @@ namespace Core.Main
private Dictionary<string, List<MarketTrendChange>> _globalMarketTrendChanges = new Dictionary<string, List<MarketTrendChange>>();
private Dictionary<string, int> _singleMarketSettingsCount = new Dictionary<string, int>();
Dictionary<string, List<SingleMarketSetting>> _triggeredSingleMarketSettings = new Dictionary<string, List<SingleMarketSetting>>();
private static readonly object _lockObj = new object();
public LogHelper Log
{
@ -581,12 +582,32 @@ namespace Core.Main
SettingsFiles.CheckPresets(this.PTMagicConfiguration, this.Log, true);
// Start the _preset folder file watcher.
SettingsFiles.PresetFileWatcher.Changed += PresetFileWatcher_OnChanged;
SettingsFiles.PresetFileWatcher.EnableRaisingEvents = true;
// Force settings refresh first time
EnforceSettingsReapply = true;
// Start polling
this.StartPTMagicIntervalTimer();
return result;
}
// File watcher event handlers
private void PresetFileWatcher_OnChanged(object source, FileSystemEventArgs e)
{
// Disable the file watcher whilst we deal with the event
SettingsFiles.PresetFileWatcher.EnableRaisingEvents = false;
// Reprocess now
PTMagicIntervalTimer_Elapsed(new object(), null);
// Enable the file watcher again
SettingsFiles.PresetFileWatcher.EnableRaisingEvents = true;
}
public bool RunStartupChecks()
{
bool result = true;
@ -615,12 +636,12 @@ namespace Core.Main
{
this.PTMagicConfiguration = new PTMagicConfiguration();
this.Log.DoLogInfo( "Configuration loaded. Found " +
this.PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends != null ? this.PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.Count.ToString() : "0" +
" Market Trends, " +
this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings != null ? this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Count.ToString() : "0" +
" Global Settings and " +
this.PTMagicConfiguration.AnalyzerSettings.SingleMarketSettings != null ? this.PTMagicConfiguration.AnalyzerSettings.SingleMarketSettings.Count.ToString() : "0" +
this.Log.DoLogInfo("Configuration loaded. Found " +
this.PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends != null ? this.PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.Count.ToString() : "0" +
" Market Trends, " +
this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings != null ? this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Count.ToString() : "0" +
" Global Settings and " +
this.PTMagicConfiguration.AnalyzerSettings.SingleMarketSettings != null ? this.PTMagicConfiguration.AnalyzerSettings.SingleMarketSettings.Count.ToString() : "0" +
" Single Market Settings.");
}
catch (Exception ex)
@ -819,91 +840,91 @@ namespace Core.Main
// Check if the bot is idle
if (this.State == Constants.PTMagicBotState_Idle)
{
this.RunCount++;
bool headerLinesAdded = false;
this.EnforceSettingsReapply = this.HaveSettingsChanged();
if (PTMagicConfiguration.GeneralSettings.Application.IsEnabled)
// Only let one thread change the settings at once
lock (_lockObj)
{
this.RunCount++;
// Validate settings
this.ValidateSettings();
bool headerLinesAdded = false;
this.EnforceSettingsReapply = this.HaveSettingsChanged() || this.EnforceSettingsReapply;
// Start the process
this.Log.DoLogInfo("");
this.Log.DoLogInfo("##########################################################");
this.Log.DoLogInfo("#********************************************************#");
this.Log.DoLogInfo("Starting market trend check with Version " + this.CurrentVersion.Major + "." + this.CurrentVersion.Minor + "." + this.CurrentVersion.Build);
if (PTMagicConfiguration.GeneralSettings.Application.IsEnabled)
{
// Change state to "Running"
this.State = Constants.PTMagicBotState_Running;
// Validate settings
this.ValidateSettings();
this.LastRuntime = DateTime.UtcNow;
// Start the process
this.Log.DoLogInfo("");
this.Log.DoLogInfo("##########################################################");
this.Log.DoLogInfo("#********************************************************#");
this.Log.DoLogInfo("Starting market trend check with Version " + this.CurrentVersion.Major + "." + this.CurrentVersion.Minor + "." + this.CurrentVersion.Build);
this.LastRuntimeSummary = new Summary();
this.LastRuntimeSummary.LastRuntime = this.LastRuntime;
this.LastRuntimeSummary.Version = this.CurrentVersion.Major.ToString() + "." + this.CurrentVersion.Minor.ToString() + "." + this.CurrentVersion.Build.ToString();
// Change state to "Running"
this.State = Constants.PTMagicBotState_Running;
// Check for latest GitHub version
this.CheckLatestGitHubVersion(this.LastRuntimeSummary.Version);
this.LastRuntime = DateTime.UtcNow;
// Get latest main fiat currency exchange rate
this.GetMainFiatCurrencyDetails();
this.LastRuntimeSummary = new Summary();
this.LastRuntimeSummary.LastRuntime = this.LastRuntime;
this.LastRuntimeSummary.Version = this.CurrentVersion.Major.ToString() + "." + this.CurrentVersion.Minor.ToString() + "." + this.CurrentVersion.Build.ToString();
// Get current PT properties
string pairsPropertiesPath = this.PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + this.PairsFileName;
string dcaPropertiesPath = this.PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + this.DCAFileName;
string indicatorsPropertiesPath = this.PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + this.IndicatorsFileName;
// Check for latest GitHub version
this.CheckLatestGitHubVersion(this.LastRuntimeSummary.Version);
this.LoadCurrentProfitTrailerProperties(pairsPropertiesPath, dcaPropertiesPath, indicatorsPropertiesPath);
// Get latest main fiat currency exchange rate
this.GetMainFiatCurrencyDetails();
// Loading SMS Summaries
this.LoadSMSSummaries();
// Load current PT files
this.LoadCurrentProfitTrailerProperties();
// Get saved market info
this.MarketInfos = BaseAnalyzer.GetMarketInfosFromFile(this.PTMagicConfiguration, this.Log);
// Loading SMS Summaries
this.LoadSMSSummaries();
// Build exchange market data
this.BuildMarketData();
// Get saved market info
this.MarketInfos = BaseAnalyzer.GetMarketInfosFromFile(this.PTMagicConfiguration, this.Log);
// Get markets from PT properties
this.BuildMarketList();
this.ValidateMarketList();
// Build exchange market data
this.BuildMarketData();
// Build global market trends configured in settings
this.BuildGlobalMarketTrends();
// Get markets from PT properties
this.BuildMarketList();
this.ValidateMarketList();
// Check for global settings triggers
GlobalSetting triggeredSetting = this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Find(s => s.SettingName.Equals(this.DefaultSettingName, StringComparison.InvariantCultureIgnoreCase));
List<string> matchedTriggers = new List<string>();
this.CheckGlobalSettingsTriggers(ref triggeredSetting, ref matchedTriggers);
// Build global market trends configured in settings
this.BuildGlobalMarketTrends();
// Activate global setting
this.ActivateSetting(ref headerLinesAdded, ref triggeredSetting, ref matchedTriggers);
// Check for global settings triggers
GlobalSetting triggeredSetting = this.PTMagicConfiguration.AnalyzerSettings.GlobalSettings.Find(s => s.SettingName.Equals(this.DefaultSettingName, StringComparison.InvariantCultureIgnoreCase));
List<string> matchedTriggers = new List<string>();
this.CheckGlobalSettingsTriggers(ref triggeredSetting, ref matchedTriggers);
// Check for single market trend triggers
this.ApplySingleMarketSettings();
// Activate global setting
this.ActivateSetting(ref headerLinesAdded, ref triggeredSetting, ref matchedTriggers);
// Save new properties to Profit Trailer
this.SaveProfitTrailerProperties(headerLinesAdded, pairsPropertiesPath, dcaPropertiesPath, indicatorsPropertiesPath);
// Check for single market trend triggers
this.ApplySingleMarketSettings();
// Save Single Market Settings Summary
this.SaveSingleMarketSettingsSummary();
// Save new properties to Profit Trailer
this.SaveProfitTrailerProperties(headerLinesAdded);
// Save Runtime Summary
this.SaveRuntimeSummary(headerLinesAdded);
// Save Single Market Settings Summary
this.SaveSingleMarketSettingsSummary();
// Cleanup to free memory in between intervals
this.Cleanup();
// Save Runtime Summary
this.SaveRuntimeSummary(headerLinesAdded);
// Change state to Finished / Stopped
this.State = Constants.PTMagicBotState_Idle;
}
else
{
this.State = Constants.PTMagicBotState_Idle;
Log.DoLogWarn("PTMagic disabled, shutting down until next raid...");
// Cleanup to free memory in between intervals
this.Cleanup();
// Change state to Finished / Stopped
this.State = Constants.PTMagicBotState_Idle;
}
else
{
this.State = Constants.PTMagicBotState_Idle;
Log.DoLogWarn("PTMagic disabled, shutting down until next raid...");
}
}
}
else
@ -1074,11 +1095,23 @@ namespace Core.Main
}
}
private void LoadCurrentProfitTrailerProperties(string pairsPropertiesPath, string dcaPropertiesPath, string indicatorsPropertiesPath)
private void GetProfitTrailerPropertiesPaths(out string pairsPropertiesPath, out string dcaPropertiesPath, out string indicatorsPropertiesPath)
{
// Get current PT properties
pairsPropertiesPath = this.PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + this.PairsFileName;
dcaPropertiesPath = this.PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + this.DCAFileName;
indicatorsPropertiesPath = this.PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerPath + Constants.PTPathTrading + Path.DirectorySeparatorChar + this.IndicatorsFileName;
}
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...");
// 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);
@ -1332,21 +1365,26 @@ namespace Core.Main
private void ActivateSetting(ref bool headerLinesAdded, ref GlobalSetting triggeredSetting, ref List<string> 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;
}
if (this.EnforceSettingsReapply)
{
this.Log.DoLogInfo("Reapply '" + activeSettingName + "' as the settings.analyzer.json or a preset file got changed.");
}
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))
{
this.Log.DoLogInfo("Setting '" + activeSettingName + "' currently active. Checking for flood protection...");
// Check if we need to force a refresh of the settings
if (this.EnforceSettingsReapply)
{
this.Log.DoLogInfo("Reapplying '" + activeSettingName + "' as the settings.analyzer.json or a preset file got changed.");
}
else
{
this.Log.DoLogInfo("Setting '" + 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))
@ -1357,9 +1395,12 @@ namespace Core.Main
// Check if flood protection is active
if (this.EnforceSettingsReapply || !this.LastSetting.Equals(triggeredSetting.SettingName, StringComparison.InvariantCultureIgnoreCase) || this.LastSettingsChange <= DateTime.UtcNow.AddMinutes(-PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes))
{
// Setting not set => Change setting
this.Log.DoLogInfo("Switching global settings to '" + triggeredSetting.SettingName + "'...");
if (!EnforceSettingsReapply)
{
this.Log.DoLogInfo("Switching global settings to '" + triggeredSetting.SettingName + "'...");
}
SettingsHandler.CompileProperties(this, triggeredSetting);
this.GlobalSettingWritten = true;
this.Log.DoLogInfo("Setting '" + triggeredSetting.SettingName + "' now active!");
@ -1368,35 +1409,44 @@ namespace Core.Main
this.LastRuntimeSummary.CurrentGlobalSetting = triggeredSetting;
// Build Telegram message
string telegramMessage = this.PTMagicConfiguration.GeneralSettings.Application.InstanceName + ": Setting switched to '*" + SystemHelper.SplitCamelCase(triggeredSetting.SettingName) + "*'.";
if (matchedTriggers.Count > 0)
string telegramMessage;
if (!EnforceSettingsReapply)
{
telegramMessage += "\n\n*Matching Triggers:*";
foreach (string triggerResult in matchedTriggers)
telegramMessage = this.PTMagicConfiguration.GeneralSettings.Application.InstanceName + ": Setting switched to '*" + SystemHelper.SplitCamelCase(triggeredSetting.SettingName) + "*'.";
if (matchedTriggers.Count > 0)
{
telegramMessage += "\n" + triggerResult;
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")) + "%";
}
}
}
if (this.AverageMarketTrendChanges.Keys.Count > 0)
else
{
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")) + "%";
}
telegramMessage = this.PTMagicConfiguration.GeneralSettings.Application.InstanceName + ": Reapplying settings '*" + SystemHelper.SplitCamelCase(triggeredSetting.SettingName) + "*'.";
}
// 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;
}
else
{
// Flood protection
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;
@ -1982,8 +2032,12 @@ namespace Core.Main
}
}
private void SaveProfitTrailerProperties(bool headerLinesAdded, string pairsPropertiesPath, string dcaPropertiesPath, string indicatorsPropertiesPath)
private void SaveProfitTrailerProperties(bool headerLinesAdded)
{
// Get current PT properties
string pairsPropertiesPath, dcaPropertiesPath, indicatorsPropertiesPath;
GetProfitTrailerPropertiesPaths(out pairsPropertiesPath, out dcaPropertiesPath, out indicatorsPropertiesPath);
if (headerLinesAdded || this.GlobalSettingWritten || this.SingleMarketSettingWritten)
{
// Save current PT properties to API (Valid for PT 2.x and above)

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Security.Permissions;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
@ -17,6 +18,27 @@ namespace Core.ProfitTrailer
{
public static class SettingsFiles
{
private static FileSystemWatcher _presetFileWatcher;
public static FileSystemWatcher PresetFileWatcher
{
get
{
if (_presetFileWatcher == null)
{
_presetFileWatcher = new FileSystemWatcher()
{
Path = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathPresets,
NotifyFilter = NotifyFilters.LastWrite,
Filter = "",
IncludeSubdirectories = true
};
}
return _presetFileWatcher;
}
}
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;
@ -34,7 +56,6 @@ namespace Core.ProfitTrailer
SettingsFiles.WriteHeaderLines(inditactorsPropertiesPath, "Default", systemConfiguration);
}
return result;
}

View File

@ -29,7 +29,7 @@ namespace Core.ProfitTrailer
private static string CalculatePropertyValue(string settingProperty, string oldValueString, string newValueString, out string configPropertyKey)
{
int valueMode = Constants.ValueModeDefault;
configPropertyKey = settingProperty;
configPropertyKey = settingProperty.Trim();
string result = null;
// Determine the mode for changing the value
@ -87,6 +87,8 @@ namespace Core.ProfitTrailer
}
break;
default:
// Raw value no processing required
result = newValueString;
break;
}
}
@ -138,24 +140,34 @@ namespace Core.ProfitTrailer
{
string result = "";
foreach (string line in ptmagicInstance.PairsLines)
if ((ptmagicInstance.PairsLines == null) || ptmagicInstance.PTMagicConfiguration.GeneralSettings.Application.TestMode)
{
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;
}
// Return current active setting
result = ptmagicInstance.ActiveSetting;
}
if (result.Equals(""))
else
{
SettingsHandler.WriteHeaderLines("Pairs", ptmagicInstance);
SettingsHandler.WriteHeaderLines("DCA", ptmagicInstance);
SettingsHandler.WriteHeaderLines("Indicators", ptmagicInstance);
headerLinesAdded = true;
// 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;
@ -339,28 +351,27 @@ namespace Core.ProfitTrailer
string propertyKey;
var lineParts = line.Trim().Split("=");
string linePropertyName = lineParts[0].Trim();
string newValueString = SystemHelper.PropertyToString(properties[settingProperty]);
string oldValueString = line.Substring(line.IndexOf("=") + 1).Trim();
string oldValueString = lineParts[1].Trim();
newValueString = CalculatePropertyValue(settingProperty, oldValueString, newValueString, out propertyKey);
if (line.Contains(propertyKey, StringComparison.InvariantCultureIgnoreCase))
if (linePropertyName.Equals(propertyKey, StringComparison.InvariantCultureIgnoreCase))
{
madeSubstitutions = true;
line = propertyKey + " = " + newValueString;
string previousLine = result.Last();
if (previousLine.IndexOf("PTMagic Changed Line", StringComparison.InvariantCultureIgnoreCase) > -1)
if (previousLine.IndexOf("PTMagic changed line", StringComparison.InvariantCultureIgnoreCase) > -1)
{
previousLine = "# PTMagic changed line for setting '" + settingName + "' on " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
result.RemoveAt(result.Count - 1);
result.Add(previousLine);
}
else
{
string editLine = "# PTMagic changed line for setting '" + settingName + "' on " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
result.Add(editLine);
result.Add(String.Format("# PTMagic changed {5} for setting '{0}' from value '{1}' to '{2}' on {3} {4}", settingName, oldValueString, newValueString, DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), linePropertyName));
}
result.Add(line);
}