2018-05-22 10:11:50 +02:00
using System ;
using System.Collections.Generic ;
using System.Threading ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using Core.Main ;
using Core.Helper ;
using Core.Main.DataObjects.PTMagicData ;
using Core.MarketAnalyzer ;
using Core.ProfitTrailer ;
using Microsoft.Extensions.Configuration ;
using Microsoft.Extensions.DependencyInjection ;
using Newtonsoft.Json ;
2018-12-15 22:07:29 +01:00
namespace Core.Main
{
public class PTMagic
{
2018-05-22 10:11:50 +02:00
2018-12-15 22:07:29 +01:00
public PTMagic ( LogHelper log )
{
2018-05-22 10:11:50 +02:00
this . Log = log ;
}
#region Properties
private LogHelper _log ;
private PTMagicConfiguration _systemConfiguration ;
private System . Timers . Timer _timer ;
private Summary _lastRuntimeSummary = null ;
private int _state = 0 ;
private int _runCount = 0 ;
private int _totalElapsedSeconds = 0 ;
private bool _globalSettingWritten = false ;
private bool _singleMarketSettingWritten = false ;
private bool _enforceSettingsReapply = false ;
private DateTime _lastRuntime = Constants . confMinDate ;
private DateTime _lastSettingsChange = Constants . confMinDate ;
private DateTime _lastSettingFileCheck = Constants . confMinDate ;
private DateTime _lastVersionCheck = Constants . confMinDate ;
private DateTime _lastFiatCurrencyCheck = Constants . confMinDate ;
private string _lastSetting = "" ;
private string _activeSetting = "" ;
private string _defaultSettingName = "" ;
private string _pairsFileName = "PAIRS.PROPERTIES" ;
private string _dcaFileName = "DCA.PROPERTIES" ;
private string _indicatorsFileName = "INDICATORS.PROPERTIES" ;
private Version _currentVersion = null ;
private string _latestVersion = "" ;
private string _lastMainFiatCurrency = "USD" ;
private double _lastMainFiatCurrencyExchangeRate = 1 ;
private List < SingleMarketSettingSummary > _singleMarketSettingSummaries = new List < SingleMarketSettingSummary > ( ) ;
private List < string > _pairsLines = null ;
private List < string > _dcaLines = null ;
private List < string > _indicatorsLines = null ;
private List < string > _exchangeMarketList = null ;
private List < string > _marketList = new List < string > ( ) ;
private Dictionary < string , MarketInfo > _marketInfos = new Dictionary < string , MarketInfo > ( ) ;
private Dictionary < string , double > _averageMarketTrendChanges = new Dictionary < string , double > ( ) ;
private Dictionary < string , List < MarketTrendChange > > _singleMarketTrendChanges = new Dictionary < string , List < MarketTrendChange > > ( ) ;
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 > > ( ) ;
2019-03-05 23:55:46 +01:00
private static readonly object _lockObj = new object ( ) ;
2018-05-22 10:11:50 +02:00
2018-12-15 22:07:29 +01:00
public LogHelper Log
{
get
{
2018-05-22 10:11:50 +02:00
return _log ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_log = value ;
}
}
2018-12-15 22:07:29 +01:00
public PTMagicConfiguration PTMagicConfiguration
{
get
{
2018-05-22 10:11:50 +02:00
return _systemConfiguration ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_systemConfiguration = value ;
}
}
2018-12-15 22:07:29 +01:00
public System . Timers . Timer Timer
{
get
{
2018-05-22 10:11:50 +02:00
return _timer ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_timer = value ;
}
}
2018-12-15 22:07:29 +01:00
public Summary LastRuntimeSummary
{
get
{
2018-05-22 10:11:50 +02:00
return _lastRuntimeSummary ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastRuntimeSummary = value ;
}
}
2018-12-15 22:07:29 +01:00
public int State
{
get
{
2018-05-22 10:11:50 +02:00
return _state ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_state = value ;
}
}
2018-12-15 22:07:29 +01:00
public int RunCount
{
get
{
2018-05-22 10:11:50 +02:00
return _runCount ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_runCount = value ;
}
}
2018-12-15 22:07:29 +01:00
public int TotalElapsedSeconds
{
get
{
2018-05-22 10:11:50 +02:00
return _totalElapsedSeconds ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_totalElapsedSeconds = value ;
}
}
2018-12-15 22:07:29 +01:00
public bool GlobalSettingWritten
{
get
{
2018-05-22 10:11:50 +02:00
return _globalSettingWritten ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_globalSettingWritten = value ;
}
}
2018-12-15 22:07:29 +01:00
public bool SingleMarketSettingWritten
{
get
{
2018-05-22 10:11:50 +02:00
return _singleMarketSettingWritten ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_singleMarketSettingWritten = value ;
}
}
2018-12-15 22:07:29 +01:00
public bool EnforceSettingsReapply
{
get
{
2018-05-22 10:11:50 +02:00
return _enforceSettingsReapply ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_enforceSettingsReapply = value ;
}
}
2018-12-15 22:07:29 +01:00
public DateTime LastSettingsChange
{
get
{
2018-05-22 10:11:50 +02:00
return _lastSettingsChange ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastSettingsChange = value ;
}
}
2018-12-15 22:07:29 +01:00
public DateTime LastVersionCheck
{
get
{
2018-05-22 10:11:50 +02:00
return _lastVersionCheck ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastVersionCheck = value ;
}
}
2018-12-15 22:07:29 +01:00
public DateTime LastFiatCurrencyCheck
{
get
{
2018-05-22 10:11:50 +02:00
return _lastFiatCurrencyCheck ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastFiatCurrencyCheck = value ;
}
}
2018-12-15 22:07:29 +01:00
public DateTime LastSettingFileCheck
{
get
{
2018-05-22 10:11:50 +02:00
return _lastSettingFileCheck ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastSettingFileCheck = value ;
}
}
2018-12-15 22:07:29 +01:00
public DateTime LastRuntime
{
get
{
2018-05-22 10:11:50 +02:00
return _lastRuntime ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastRuntime = value ;
}
}
2018-12-15 22:07:29 +01:00
public string DefaultSettingName
{
get
{
2018-05-22 10:11:50 +02:00
return _defaultSettingName ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_defaultSettingName = value ;
}
}
2018-12-15 22:07:29 +01:00
public string LastSetting
{
get
{
2018-05-22 10:11:50 +02:00
return _lastSetting ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastSetting = value ;
}
}
2018-12-15 22:07:29 +01:00
public string ActiveSetting
{
get
{
2018-05-22 10:11:50 +02:00
return _activeSetting ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_activeSetting = value ;
}
}
2018-12-15 22:07:29 +01:00
public string PairsFileName
{
get
{
2018-05-22 10:11:50 +02:00
return _pairsFileName ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_pairsFileName = value ;
}
}
2018-12-15 22:07:29 +01:00
public string DCAFileName
{
get
{
2018-05-22 10:11:50 +02:00
return _dcaFileName ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_dcaFileName = value ;
}
}
2018-12-15 22:07:29 +01:00
public string IndicatorsFileName
{
get
{
2018-05-22 10:11:50 +02:00
return _indicatorsFileName ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_indicatorsFileName = value ;
}
}
2018-12-15 22:07:29 +01:00
public Version CurrentVersion
{
get
{
2018-05-22 10:11:50 +02:00
return _currentVersion ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_currentVersion = value ;
}
}
2018-12-15 22:07:29 +01:00
public string LatestVersion
{
get
{
2018-05-22 10:11:50 +02:00
return _latestVersion ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_latestVersion = value ;
}
}
2018-12-15 22:07:29 +01:00
public string LastMainFiatCurrency
{
get
{
2018-05-22 10:11:50 +02:00
return _lastMainFiatCurrency ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastMainFiatCurrency = value ;
}
}
2018-12-15 22:07:29 +01:00
public double LastMainFiatCurrencyExchangeRate
{
get
{
2018-05-22 10:11:50 +02:00
return _lastMainFiatCurrencyExchangeRate ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_lastMainFiatCurrencyExchangeRate = value ;
}
}
2018-12-15 22:07:29 +01:00
public List < SingleMarketSettingSummary > SingleMarketSettingSummaries
{
get
{
2018-05-22 10:11:50 +02:00
return _singleMarketSettingSummaries ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_singleMarketSettingSummaries = value ;
}
}
2018-12-15 22:07:29 +01:00
public List < string > PairsLines
{
get
{
2018-05-22 10:11:50 +02:00
return _pairsLines ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_pairsLines = value ;
}
}
2018-12-15 22:07:29 +01:00
public List < string > DCALines
{
get
{
2018-05-22 10:11:50 +02:00
return _dcaLines ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_dcaLines = value ;
}
}
2018-12-15 22:07:29 +01:00
public List < string > IndicatorsLines
{
get
{
2018-05-22 10:11:50 +02:00
return _indicatorsLines ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_indicatorsLines = value ;
}
}
2018-12-15 22:07:29 +01:00
public List < string > ExchangeMarketList
{
get
{
2018-05-22 10:11:50 +02:00
return _exchangeMarketList ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_exchangeMarketList = value ;
}
}
2018-12-15 22:07:29 +01:00
public List < string > MarketList
{
get
{
2018-05-22 10:11:50 +02:00
return _marketList ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_marketList = value ;
}
}
2018-12-15 22:07:29 +01:00
public Dictionary < string , MarketInfo > MarketInfos
{
get
{
2018-05-22 10:11:50 +02:00
return _marketInfos ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_marketInfos = value ;
}
}
2018-12-15 22:07:29 +01:00
public Dictionary < string , List < MarketTrendChange > > SingleMarketTrendChanges
{
get
{
2018-05-22 10:11:50 +02:00
return _singleMarketTrendChanges ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_singleMarketTrendChanges = value ;
}
}
2018-12-15 22:07:29 +01:00
public Dictionary < string , List < MarketTrendChange > > GlobalMarketTrendChanges
{
get
{
2018-05-22 10:11:50 +02:00
return _globalMarketTrendChanges ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_globalMarketTrendChanges = value ;
}
}
2018-12-15 22:07:29 +01:00
public Dictionary < string , double > AverageMarketTrendChanges
{
get
{
2018-05-22 10:11:50 +02:00
return _averageMarketTrendChanges ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_averageMarketTrendChanges = value ;
}
}
2018-12-15 22:07:29 +01:00
public Dictionary < string , int > SingleMarketSettingsCount
{
get
{
2018-05-22 10:11:50 +02:00
return _singleMarketSettingsCount ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_singleMarketSettingsCount = value ;
}
}
2018-12-15 22:07:29 +01:00
public Dictionary < string , List < SingleMarketSetting > > TriggeredSingleMarketSettings
{
get
{
2018-05-22 10:11:50 +02:00
return _triggeredSingleMarketSettings ;
}
2018-12-15 22:07:29 +01:00
set
{
2018-05-22 10:11:50 +02:00
_triggeredSingleMarketSettings = value ;
}
}
#endregion
#region PTMagic Startup Methods
2019-02-04 01:17:38 +01:00
2019-02-20 13:38:32 +01:00
private static int ExponentialDelay ( int failedAttempts , int maxDelayInSeconds = 900 )
2019-02-04 01:17:38 +01:00
{
2019-02-20 13:35:58 +01:00
//Attempt 1 0s 0s
//Attempt 2 2s 2s
//Attempt 3 4s 4s
//Attempt 4 8s 8s
//Attempt 5 16s 16s
//Attempt 6 32s 32s
2019-02-04 01:17:38 +01:00
2019-02-20 13:35:58 +01:00
//Attempt 7 64s 1m 4s
//Attempt 8 128s 2m 8s
//Attempt 9 256s 4m 16s
//Attempt 10 512 8m 32s
//Attempt 11 1024 17m 4s
2019-02-04 01:17:38 +01:00
2019-02-20 13:35:58 +01:00
var delayInSeconds = ( ( 1d / 2d ) * ( Math . Pow ( 2d , failedAttempts ) - 1d ) ) ;
2019-02-04 01:17:38 +01:00
2019-02-20 13:35:58 +01:00
return maxDelayInSeconds < delayInSeconds
? maxDelayInSeconds
: ( int ) delayInSeconds ;
2019-02-04 01:17:38 +01:00
}
2018-12-15 22:07:29 +01:00
public bool StartProcess ( )
{
2018-05-22 10:11:50 +02:00
bool result = true ;
this . Log . DoLogInfo ( "" ) ;
this . Log . DoLogInfo ( " ██████╗ ████████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗" ) ;
this . Log . DoLogInfo ( " ██╔══██╗╚══██╔══╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝" ) ;
this . Log . DoLogInfo ( " ██████╔╝ ██║ ██╔████╔██║███████║██║ ███╗██║██║ " ) ;
this . Log . DoLogInfo ( " ██╔═══╝ ██║ ██║╚██╔╝██║██╔══██║██║ ██║██║██║ " ) ;
this . Log . DoLogInfo ( " ██║ ██║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗" ) ;
this . Log . DoLogInfo ( " ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝" ) ;
this . Log . DoLogInfo ( " Version " + this . CurrentVersion . Major + "." + this . CurrentVersion . Minor + "." + this . CurrentVersion . Build ) ;
this . Log . DoLogInfo ( "" ) ;
this . Log . DoLogInfo ( "Starting PTMagic in " + Directory . GetCurrentDirectory ( ) ) ;
2018-05-28 10:02:31 +02:00
this . Log . DoLogInfo ( "with .NET Core: " + Path . GetDirectoryName ( typeof ( object ) . Assembly . Location ) ) ;
2018-05-26 06:53:25 +02:00
2018-12-15 22:07:29 +01:00
if ( ! this . RunStartupChecks ( ) )
{
2018-05-22 10:11:50 +02:00
return false ;
}
2018-12-15 22:07:29 +01:00
if ( ! this . InitializeConfiguration ( ) )
{
2018-05-22 10:11:50 +02:00
return false ;
}
2018-06-05 08:55:25 +02:00
2019-02-04 01:17:38 +01:00
bool configCheckResult = this . RunConfigurationChecks ( ) ;
if ( ! configCheckResult )
2018-12-15 22:07:29 +01:00
{
2019-02-04 01:17:38 +01:00
// Config check failed so retry using an exponential back off until it passes; max retry time 15 mins.
int configRetryCount = 1 ;
int delaySeconds ;
2018-06-05 08:55:25 +02:00
2019-02-04 01:17:38 +01:00
while ( ! configCheckResult )
2018-12-15 22:07:29 +01:00
{
2019-02-04 01:17:38 +01:00
delaySeconds = ExponentialDelay ( configRetryCount ) ;
this . Log . DoLogError ( "Configuration check retry " + configRetryCount + " failed, starting next retry in " + delaySeconds + " seconds..." ) ;
Thread . Sleep ( delaySeconds * 1000 ) ;
// Reinit config in case the user changed something
this . InitializeConfiguration ( ) ;
configCheckResult = this . RunConfigurationChecks ( ) ;
configRetryCount + + ;
2018-06-05 08:55:25 +02:00
}
}
2019-02-04 01:17:38 +01:00
this . LastSettingFileCheck = DateTime . UtcNow ;
2018-05-22 10:11:50 +02:00
SettingsFiles . CheckPresets ( this . PTMagicConfiguration , this . Log , true ) ;
2019-03-05 23:55:46 +01:00
// Start the _preset folder file watcher.
SettingsFiles . PresetFileWatcher . Changed + = PresetFileWatcher_OnChanged ;
SettingsFiles . PresetFileWatcher . EnableRaisingEvents = true ;
// Force settings refresh first time
2019-01-24 15:05:10 +01:00
EnforceSettingsReapply = true ;
2019-03-05 23:55:46 +01:00
// Start polling
2018-05-22 10:11:50 +02:00
this . StartPTMagicIntervalTimer ( ) ;
return result ;
}
2019-03-05 23:55:46 +01:00
// 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 ;
2019-03-06 22:52:04 +01:00
this . Log . DoLogInfo ( "Detected a '" + e . ChangeType . ToString ( ) + "' change in the following preset file: " + e . FullPath ) ;
2019-03-05 23:55:46 +01:00
// Reprocess now
2019-03-09 09:38:46 +01:00
this . EnforceSettingsReapply = true ;
2019-03-05 23:55:46 +01:00
PTMagicIntervalTimer_Elapsed ( new object ( ) , null ) ;
// Enable the file watcher again
SettingsFiles . PresetFileWatcher . EnableRaisingEvents = true ;
}
2018-12-15 22:07:29 +01:00
public bool RunStartupChecks ( )
{
2018-05-22 10:11:50 +02:00
bool result = true ;
// Startup checks
2018-12-15 22:07:29 +01:00
if ( ! File . Exists ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + "settings.general.json" ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogError ( "File 'settings.general.json' not found! Please review the setup steps on the wiki and double check every step that involves copying files!" ) ;
result = false ;
}
2018-12-15 22:07:29 +01:00
if ( ! File . Exists ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + "settings.analyzer.json" ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogError ( "File 'settings.analyzer.json' not found! Please review the setup steps on the wiki and double check every step that involves copying files!" ) ;
result = false ;
}
return result ;
}
2018-12-15 22:07:29 +01:00
public bool InitializeConfiguration ( )
{
2018-05-22 10:11:50 +02:00
bool result = true ;
2018-12-15 22:07:29 +01:00
try
{
2018-05-22 10:11:50 +02:00
this . PTMagicConfiguration = new PTMagicConfiguration ( ) ;
2019-03-05 23:55:46 +01:00
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" +
2019-03-02 09:10:33 +01:00
" Single Market Settings." ) ;
2018-12-15 22:07:29 +01:00
}
catch ( Exception ex )
{
2018-05-22 10:11:50 +02:00
result = false ;
this . Log . DoLogCritical ( "Error loading configuration!" , ex ) ;
throw ( ex ) ;
}
return result ;
}
2018-12-15 22:07:29 +01:00
public bool RunConfigurationChecks ( )
{
2018-05-22 10:11:50 +02:00
bool result = true ;
2019-01-13 13:43:47 +01:00
//Import Initial ProfitTrailer Information(Deactivated for now)
//SettingsAPI.GetInitialProfitTrailerSettings(this.PTMagicConfiguration);
2019-01-07 15:33:02 +01:00
2018-05-22 10:11:50 +02:00
// Check for valid default setting
GlobalSetting defaultSetting = this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings . Find ( s = > s . SettingName . Equals ( "default" , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( defaultSetting = = null )
{
2018-05-22 10:11:50 +02:00
defaultSetting = this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings . Find ( s = > s . SettingName . IndexOf ( "default" , StringComparison . InvariantCultureIgnoreCase ) > - 1 ) ;
2018-12-15 22:07:29 +01:00
if ( defaultSetting ! = null )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "No setting named 'default' found, taking '" + defaultSetting . SettingName + "' as default." ) ;
this . DefaultSettingName = defaultSetting . SettingName ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogError ( "No 'default' setting found! Terminating process..." ) ;
result = false ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . DefaultSettingName = defaultSetting . SettingName ;
}
// Check if exchange is valid
if ( ! this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Binance" , StringComparison . InvariantCultureIgnoreCase )
& & ! this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Bittrex" , StringComparison . InvariantCultureIgnoreCase )
2018-12-15 22:07:29 +01:00
& & ! this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Poloniex" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogError ( "Exchange '" + this . PTMagicConfiguration . GeneralSettings . Application . Exchange + "' specified in settings.general.json is invalid! Terminating process..." ) ;
result = false ;
}
// Check if the program is enabled
2018-12-15 22:07:29 +01:00
if ( this . PTMagicConfiguration . GeneralSettings . Application . IsEnabled )
{
2019-02-20 13:35:58 +01:00
try
2018-12-15 22:07:29 +01:00
{
2019-02-20 13:35:58 +01:00
if ( this . PTMagicConfiguration . GeneralSettings . Application . TestMode ) this . Log . DoLogInfo ( "TESTMODE ENABLED - No files will be changed!" ) ;
// Check for PT Directory
DirectoryInfo ptRoot = new DirectoryInfo ( this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerPath ) ;
if ( ptRoot . Exists )
{
this . Log . DoLogInfo ( "Profit Trailer directory found" ) ;
result = RunProfitTrailerSettingsAPIChecks ( ) ;
}
else
{
this . Log . DoLogError ( "Profit Trailer directory not found (" + this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerPath + ")" ) ;
result = false ;
}
// Check for CoinMarketCap API Key
if ( ! String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . CoinMarketCapAPIKey ) )
{
this . Log . DoLogInfo ( "CoinMarketCap API KEY found" ) ;
}
else
{
this . Log . DoLogInfo ( "No CoinMarketCap API KEY specified! You can't use CoinMarketCap in your settings.analyzer.json" ) ;
}
// Check for CurrencyConverterApi Key
if ( ! this . PTMagicConfiguration . GeneralSettings . Application . FreeCurrencyConverterAPIKey . Equals ( "" ) )
{
this . Log . DoLogInfo ( "FreeCurrencyConverterApi KEY found" ) ;
}
else
{
this . Log . DoLogInfo ( "No FreeCurrencyConverterApi KEY specified, you can only use USD; apply for a key at: https://freecurrencyrates.com/en" ) ;
}
2018-12-15 22:07:29 +01:00
}
2019-02-21 05:52:07 +01:00
catch ( System . NullReferenceException )
2018-12-15 22:07:29 +01:00
{
2019-02-20 13:35:58 +01:00
this . Log . DoLogError ( "PTM failed to read the Config File. That means something in the File is either missing or incorrect. If this happend after an update please take a look at the release notes at: https://github.com/PTMagicians/PTMagic/releases" ) ;
2019-03-09 12:00:35 +01:00
Console . WriteLine ( "Press enter to close the Application..." ) ;
Console . ReadLine ( ) ;
Environment . Exit ( 0 ) ;
2018-05-22 10:11:50 +02:00
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "PTMagic disabled, shutting down..." ) ;
result = false ;
}
return result ;
}
2019-01-07 15:33:02 +01:00
private bool RunProfitTrailerSettingsAPIChecks ( )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
bool result = true ;
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "========== STARTING CHECKS FOR Profit Trailer ==========" ) ;
2018-05-22 10:11:50 +02:00
2019-01-07 15:33:02 +01:00
// Check for PT license key
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerLicense ) )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "Profit Trailer check: Profit Trailer license found" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogError ( "Profit Trailer check: No Profit Trailer license key specified! The license key is necessary to adjust your Profit Trailer settings" ) ;
2018-05-22 10:11:50 +02:00
result = false ;
}
2018-12-15 22:07:29 +01:00
2019-01-07 15:33:02 +01:00
//Check for ptServerAPIToken
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerServerAPIToken ) )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "Profit Trailer check: Profit Trailer Server API Token Specified" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-02-04 01:17:38 +01:00
this . Log . DoLogError ( "Profit Trailer check: No Server API Token specified. Please configure ProfitTrailerServerAPIToken in settings.general.json , ensuring it has to be the same Token as in the Profit Trailer Config File!" ) ;
2018-05-22 10:11:50 +02:00
result = false ;
}
// Check for PT default setting key
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerDefaultSettingName ) )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "Profit Trailer check: Profit Trailer default setting name specified" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogError ( "Profit Trailer check: No Profit Trailer default setting name specified! The default setting name is necessary to adjust your Profit Trailer settings since 2.0" ) ;
2018-05-22 10:11:50 +02:00
result = false ;
}
// Check for PT monitor
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerMonitorURL ) )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "Profit Trailer check: Profit Trailer monitor URL found" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogError ( "Profit Trailer check: No Profit Trailer monitor URL specified! The monitor URL is necessary to adjust your Profit Trailer settings since 2.0" ) ;
2018-05-22 10:11:50 +02:00
result = false ;
}
// Check if PT monitor is reachable
2018-12-15 22:07:29 +01:00
if ( SystemHelper . UrlIsReachable ( this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerMonitorURL ) )
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "Profit Trailer check: Profit Trailer monitor connection test succeeded" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogError ( "Profit Trailer check: Your Profit Trailer monitor (" + this . PTMagicConfiguration . GeneralSettings . Application . ProfitTrailerMonitorURL + ") is not available! Make sure your Profit Trailer bot is up and running and your monitor is accessible." ) ;
2018-05-22 10:11:50 +02:00
result = false ;
}
2018-06-05 08:55:25 +02:00
2018-12-15 22:07:29 +01:00
if ( result )
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "========== CHECKS FOR Profit Trailer COMPLETED! ==========" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "========== CHECKS FOR Profit Trailer FAILED! ==========" ) ;
2018-06-05 08:55:25 +02:00
}
2018-05-22 10:11:50 +02:00
return result ;
}
2018-12-15 22:07:29 +01:00
public void StartPTMagicIntervalTimer ( )
{
2018-05-22 10:11:50 +02:00
this . Timer = new System . Timers . Timer ( this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes * 60 * 1000 ) ;
this . Timer . Enabled = true ;
this . Timer . Elapsed + = new System . Timers . ElapsedEventHandler ( this . PTMagicIntervalTimer_Elapsed ) ;
this . Log . DoLogInfo ( "Checking market trends every " + this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes . ToString ( ) + " minutes..." ) ;
// Fire the first start immediately
this . PTMagicIntervalTimer_Elapsed ( null , null ) ;
}
#endregion
#region PTMagic Interval Methods
2018-06-05 08:55:25 +02:00
2018-12-15 22:07:29 +01:00
public void PTMagicIntervalTimer_Elapsed ( object sender , System . Timers . ElapsedEventArgs e )
{
2018-05-22 10:11:50 +02:00
// Check if the bot is idle
2018-12-15 22:07:29 +01:00
if ( this . State = = Constants . PTMagicBotState_Idle )
{
2019-03-05 23:55:46 +01:00
// Only let one thread change the settings at once
lock ( _lockObj )
2018-12-15 22:07:29 +01:00
{
2019-03-05 23:55:46 +01:00
this . RunCount + + ;
2019-02-20 13:35:58 +01:00
2019-03-05 23:55:46 +01:00
bool headerLinesAdded = false ;
this . EnforceSettingsReapply = this . HaveSettingsChanged ( ) | | this . EnforceSettingsReapply ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
if ( PTMagicConfiguration . GeneralSettings . Application . IsEnabled )
{
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Validate settings
this . ValidateSettings ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// 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 ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Change state to "Running"
this . State = Constants . PTMagicBotState_Running ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
this . LastRuntime = DateTime . UtcNow ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
this . LastRuntimeSummary = new Summary ( ) ;
this . LastRuntimeSummary . LastRuntime = this . LastRuntime ;
this . LastRuntimeSummary . Version = this . CurrentVersion . Major . ToString ( ) + "." + this . CurrentVersion . Minor . ToString ( ) + "." + this . CurrentVersion . Build . ToString ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Check for latest GitHub version
this . CheckLatestGitHubVersion ( this . LastRuntimeSummary . Version ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Get latest main fiat currency exchange rate
this . GetMainFiatCurrencyDetails ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Load current PT files
this . LoadCurrentProfitTrailerProperties ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Loading SMS Summaries
this . LoadSMSSummaries ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Get saved market info
this . MarketInfos = BaseAnalyzer . GetMarketInfosFromFile ( this . PTMagicConfiguration , this . Log ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Build exchange market data
this . BuildMarketData ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Get markets from PT properties
this . BuildMarketList ( ) ;
this . ValidateMarketList ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Build global market trends configured in settings
this . BuildGlobalMarketTrends ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// 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 ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Activate global setting
this . ActivateSetting ( ref headerLinesAdded , ref triggeredSetting , ref matchedTriggers ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Check for single market trend triggers
this . ApplySingleMarketSettings ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Save new properties to Profit Trailer
this . SaveProfitTrailerProperties ( headerLinesAdded ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Save Single Market Settings Summary
this . SaveSingleMarketSettingsSummary ( ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Save Runtime Summary
this . SaveRuntimeSummary ( headerLinesAdded ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// 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..." ) ;
}
2018-05-22 10:11:50 +02:00
}
2018-12-15 22:07:29 +01:00
}
else
{
if ( this . RunCount > 1 )
{
2018-05-22 10:11:50 +02:00
Log . DoLogWarn ( "PTMagic already raiding since " + this . LastRuntime . ToString ( ) + " - Process frozen? Checking things..." ) ;
2018-12-15 22:07:29 +01:00
if ( File . Exists ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar + "LastRuntimeSummary.json" ) )
{
2018-05-22 10:11:50 +02:00
FileInfo fiLastSummary = new FileInfo ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar + "LastRuntimeSummary.json" ) ;
2019-02-18 00:08:11 +01:00
if ( fiLastSummary . LastWriteTimeUtc < DateTime . UtcNow . AddMinutes ( - ( this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes * 2 ) ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
Log . DoLogWarn ( "PTMagic seems to have frozen after raid " + this . RunCount . ToString ( ) + ", but don't worry I will sacrifice some Magicbots to get this running again..." ) ;
this . State = Constants . PTMagicBotState_Idle ;
Log . DoLogInfo ( "PTMagic status resetted, waiting for the next raid to be good to go again." ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
Log . DoLogWarn ( "No LastRuntimeSummary.json found after raid " + this . RunCount . ToString ( ) + ", trying to reset PT Magic status..." ) ;
this . State = Constants . PTMagicBotState_Idle ;
Log . DoLogInfo ( "PTMagic status resetted, waiting for the next raid to be good to go again." ) ;
}
}
}
}
2018-12-15 22:07:29 +01:00
private bool HaveSettingsChanged ( )
{
2018-05-22 10:11:50 +02:00
bool result = false ;
FileInfo generalSettingsFile = new FileInfo ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + "settings.general.json" ) ;
FileInfo analyzerSettingsFile = new FileInfo ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + "settings.analyzer.json" ) ;
2019-03-09 09:38:46 +01:00
if ( generalSettingsFile . LastWriteTimeUtc > this . LastSettingFileCheck | | analyzerSettingsFile . LastWriteTimeUtc > this . LastSettingFileCheck )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
Log . DoLogInfo ( "Detected configuration changes. Reloading settings..." ) ;
2018-12-15 22:07:29 +01:00
try
{
2018-05-22 10:11:50 +02:00
PTMagicConfiguration = new PTMagicConfiguration ( ) ;
GlobalSetting defaultSetting = this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings . Find ( s = > s . SettingName . Equals ( "default" , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( defaultSetting = = null )
{
2018-05-22 10:11:50 +02:00
defaultSetting = this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings . Find ( s = > s . SettingName . IndexOf ( "default" , StringComparison . InvariantCultureIgnoreCase ) > - 1 ) ;
2018-12-15 22:07:29 +01:00
if ( defaultSetting ! = null )
{
2018-05-22 10:11:50 +02:00
Log . DoLogDebug ( "No setting named 'default' found, taking '" + defaultSetting . SettingName + "' as default." ) ;
this . DefaultSettingName = defaultSetting . SettingName ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
Log . DoLogError ( "No 'default' setting found! Terminating process..." ) ;
this . Timer . Stop ( ) ;
Exception ex = new Exception ( "No 'default' setting found!Terminating process..." ) ;
throw ex ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . DefaultSettingName = defaultSetting . SettingName ;
}
Log . DoLogInfo ( "New configuration reloaded." ) ;
2019-02-04 01:17:38 +01:00
this . LastSettingFileCheck = DateTime . UtcNow ;
2018-05-22 10:11:50 +02:00
result = true ;
2018-12-15 22:07:29 +01:00
if ( this . Timer . Interval ! = this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes * 60 * 1000 )
{
2018-05-22 10:11:50 +02:00
Log . DoLogInfo ( "Setting for 'IntervalMinutes' changed in MarketAnalyzer, setting new timer..." ) ;
this . Timer . Stop ( ) ;
this . Timer . Interval = this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes * 60 * 1000 ;
this . Timer . Start ( ) ;
Log . DoLogInfo ( "New timer set to " + this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes . ToString ( ) + " minutes." ) ;
}
SettingsFiles . CheckPresets ( this . PTMagicConfiguration , this . Log , true ) ;
2018-12-15 22:07:29 +01:00
}
catch ( Exception ex )
{
2018-05-22 10:11:50 +02:00
Log . DoLogCritical ( "Error loading new configuration!" , ex ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
result = SettingsFiles . CheckPresets ( this . PTMagicConfiguration , this . Log , false ) ;
}
return result ;
}
2018-12-15 22:07:29 +01:00
private void ValidateSettings ( )
{
2019-01-13 13:43:47 +01:00
//Reimport Initial ProfitTrailer Information(Deactivated for now)
//SettingsAPI.GetInitialProfitTrailerSettings(this.PTMagicConfiguration);
2019-01-07 19:00:40 +01:00
2018-05-22 10:11:50 +02:00
// Check for a valid exchange
2018-12-15 22:07:29 +01:00
if ( this . PTMagicConfiguration . GeneralSettings . Application . Exchange = = null )
{
2018-05-22 10:11:50 +02:00
Log . DoLogError ( "Your setting for Application.Exchange in settings.general.json is invalid (null)! Terminating process." ) ;
this . Timer . Stop ( ) ;
Exception ex = new Exception ( "Your setting for Application.Exchange in settings.general.json is invalid (null)! Terminating process." ) ;
throw ex ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-02-04 01:17:38 +01:00
if ( String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . Exchange ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
Log . DoLogError ( "Your setting for Application.Exchange in settings.general.json is invalid (empty)! Terminating process." ) ;
this . Timer . Stop ( ) ;
Exception ex = new Exception ( "Your setting for Application.Exchange in settings.general.json is invalid (empty)! Terminating process." ) ;
throw ex ;
2018-12-15 22:07:29 +01:00
}
else
{
if ( ! this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Binance" , StringComparison . InvariantCultureIgnoreCase ) & & ! this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Bittrex" , StringComparison . InvariantCultureIgnoreCase ) & & ! this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Poloniex" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
Log . DoLogError ( "Your setting for Application.Exchange in settings.general.json is invalid (" + this . PTMagicConfiguration . GeneralSettings . Application . Exchange + ")! Terminating process." ) ;
this . Timer . Stop ( ) ;
Exception ex = new Exception ( "Your setting for Application.Exchange in settings.general.json is invalid (" + this . PTMagicConfiguration . GeneralSettings . Application . Exchange + ")! Terminating process." ) ;
throw ex ;
}
}
}
}
2018-12-15 22:07:29 +01:00
private void CheckLatestGitHubVersion ( string currentVersion )
{
2018-05-22 10:11:50 +02:00
// Get latest version number
2019-02-04 01:17:38 +01:00
if ( this . LastVersionCheck < DateTime . UtcNow . AddMinutes ( - 30 ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
this . LatestVersion = BaseAnalyzer . GetLatestGitHubRelease ( this . Log , currentVersion ) ;
2019-02-04 01:17:38 +01:00
this . LastVersionCheck = DateTime . UtcNow ;
2018-12-15 22:07:29 +01:00
if ( ! SystemHelper . IsRecentVersion ( currentVersion , this . LatestVersion ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "Your bot is out of date! The most recent version of PTMagic is " + this . LatestVersion ) ;
}
}
}
2018-12-15 22:07:29 +01:00
private void GetMainFiatCurrencyDetails ( )
{
2018-05-22 10:11:50 +02:00
this . LastRuntimeSummary . MainFiatCurrency = this . LastMainFiatCurrency ;
this . LastRuntimeSummary . MainFiatCurrencyExchangeRate = this . LastMainFiatCurrencyExchangeRate ;
2019-02-04 01:17:38 +01:00
if ( this . LastFiatCurrencyCheck < DateTime . UtcNow . AddHours ( - 12 ) & & ! this . PTMagicConfiguration . GeneralSettings . Application . MainFiatCurrency . Equals ( "USD" , StringComparison . InvariantCultureIgnoreCase ) )
2018-12-15 22:07:29 +01:00
{
try
{
2018-05-22 10:11:50 +02:00
this . LastRuntimeSummary . MainFiatCurrency = this . PTMagicConfiguration . GeneralSettings . Application . MainFiatCurrency ;
2019-02-17 15:45:00 +01:00
this . LastRuntimeSummary . MainFiatCurrencyExchangeRate = BaseAnalyzer . GetMainFiatCurrencyRate ( this . PTMagicConfiguration . GeneralSettings . Application . MainFiatCurrency , this . PTMagicConfiguration . GeneralSettings . Application . FreeCurrencyConverterAPIKey , this . Log ) ;
2018-05-22 10:11:50 +02:00
this . LastMainFiatCurrency = this . LastRuntimeSummary . MainFiatCurrency ;
this . LastMainFiatCurrencyExchangeRate = this . LastRuntimeSummary . MainFiatCurrencyExchangeRate ;
2019-02-04 01:17:38 +01:00
this . LastFiatCurrencyCheck = DateTime . UtcNow ;
2018-12-15 22:07:29 +01:00
}
catch ( Exception ex )
{
2018-05-22 10:11:50 +02:00
// Fallback to USD in case something went wrong
this . Log . DoLogError ( "Fixer.io exchange rate check error: " + ex . Message ) ;
this . LastRuntimeSummary . MainFiatCurrency = "USD" ;
this . LastRuntimeSummary . MainFiatCurrencyExchangeRate = 1 ;
this . LastMainFiatCurrency = "USD" ;
this . LastMainFiatCurrencyExchangeRate = 1 ;
}
}
}
2019-03-05 23:55:46 +01:00
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 ( )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
// Load current PT properties from API (Valid for PT 2.x and above)
this . Log . DoLogInfo ( "Loading current Profit Trailer properties from API..." ) ;
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Get current PT properties
string pairsPropertiesPath , dcaPropertiesPath , indicatorsPropertiesPath ;
GetProfitTrailerPropertiesPaths ( out pairsPropertiesPath , out dcaPropertiesPath , out indicatorsPropertiesPath ) ;
2019-01-07 15:33:02 +01:00
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 ) ;
2018-05-22 10:11:50 +02:00
2018-12-15 22:07:29 +01:00
if ( this . PairsLines ! = null & & this . DCALines ! = null & & this . IndicatorsLines ! = null )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Properties loaded - P (" + this . PairsLines . Count . ToString ( ) + " lines) - D (" + this . DCALines . Count . ToString ( ) + " lines) - I (" + this . IndicatorsLines . Count . ToString ( ) + " lines)." ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogError ( "Unable to load all Profit Trailer properties! Waiting for the next interval to retry..." ) ;
Exception ex = new Exception ( "Unable to load all Profit Trailer properties! Waiting for the next interval to retry..." ) ;
this . State = 0 ;
throw ex ;
}
// Get market from PT properties
this . LastRuntimeSummary . MainMarket = SettingsHandler . GetMainMarket ( this . PTMagicConfiguration , this . PairsLines , this . Log ) ;
}
2018-12-15 22:07:29 +01:00
private void LoadSMSSummaries ( )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Loading Single Market Setting Summaries..." ) ;
this . SingleMarketSettingSummaries = new List < SingleMarketSettingSummary > ( ) ;
2018-12-15 22:07:29 +01:00
if ( File . Exists ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar + "SingleMarketSettingSummary.json" ) )
{
try
{
2018-05-22 10:11:50 +02:00
Dictionary < string , bool > smsVerificationResult = new Dictionary < string , bool > ( ) ;
// Cleanup SMS Summaries in case a SMS got removed
2018-12-15 22:07:29 +01:00
foreach ( SingleMarketSettingSummary smsSummary in JsonConvert . DeserializeObject < List < SingleMarketSettingSummary > > ( System . IO . File . ReadAllText ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar + "SingleMarketSettingSummary.json" ) ) )
{
2018-05-22 10:11:50 +02:00
string smsName = smsSummary . SingleMarketSetting . SettingName ;
bool smsIsValid = false ;
2018-12-15 22:07:29 +01:00
if ( smsVerificationResult . ContainsKey ( smsName ) )
{
2018-05-22 10:11:50 +02:00
smsIsValid = smsVerificationResult [ smsName ] ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
SingleMarketSetting sms = this . PTMagicConfiguration . AnalyzerSettings . SingleMarketSettings . Find ( s = > s . SettingName . Equals ( smsName ) ) ;
2018-12-15 22:07:29 +01:00
if ( sms ! = null )
{
2018-05-22 10:11:50 +02:00
smsIsValid = true ;
smsVerificationResult . Add ( smsName , true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
smsVerificationResult . Add ( smsName , false ) ;
}
}
2018-12-15 22:07:29 +01:00
if ( smsIsValid )
{
2018-05-22 10:11:50 +02:00
this . SingleMarketSettingSummaries . Add ( smsSummary ) ;
}
}
this . Log . DoLogInfo ( "Single Market Setting Summaries loaded." ) ;
2018-12-15 22:07:29 +01:00
}
catch { }
2018-05-22 10:11:50 +02:00
}
}
2018-12-15 22:07:29 +01:00
private void BuildMarketData ( )
{
2018-12-01 15:05:35 +01:00
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( this . PTMagicConfiguration . GeneralSettings . Application . CoinMarketCapAPIKey ) )
2018-12-15 22:07:29 +01:00
{
// Get most recent market data from CMC
string cmcMarketDataResult = CoinMarketCap . GetMarketData ( this . PTMagicConfiguration , this . Log ) ;
}
else
{
this . Log . DoLogInfo ( "No CMC API-Key specified. No CMC Data will be pulled" ) ;
2018-12-01 15:05:35 +01:00
}
2018-05-22 10:11:50 +02:00
2018-12-15 22:07:29 +01:00
if ( this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Bittrex" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
// Get most recent market data from Bittrex
this . ExchangeMarketList = Bittrex . GetMarketData ( this . LastRuntimeSummary . MainMarket , this . MarketInfos , this . PTMagicConfiguration , this . Log ) ;
2018-12-15 22:07:29 +01:00
}
else if ( this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Binance" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
// Get most recent market data from Binance
this . ExchangeMarketList = Binance . GetMarketData ( this . LastRuntimeSummary . MainMarket , this . MarketInfos , this . PTMagicConfiguration , this . Log ) ;
2018-12-15 22:07:29 +01:00
}
else if ( this . PTMagicConfiguration . GeneralSettings . Application . Exchange . Equals ( "Poloniex" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
// Get most recent market data from Poloniex
this . ExchangeMarketList = Poloniex . GetMarketData ( this . LastRuntimeSummary . MainMarket , this . MarketInfos , this . PTMagicConfiguration , this . Log ) ;
}
// Check if problems occured during the Exchange contact
2018-12-15 22:07:29 +01:00
if ( this . ExchangeMarketList = = null )
{
2018-05-22 10:11:50 +02:00
Exception ex = new Exception ( "Unable to contact " + this . PTMagicConfiguration . GeneralSettings . Application . Exchange + " for fresh market data. Trying again in " + this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes + " minute(s)." ) ;
Log . DoLogError ( ex . Message ) ;
this . State = Constants . PTMagicBotState_Idle ;
throw ex ;
}
}
2018-12-15 22:07:29 +01:00
private void BuildMarketList ( )
{
2018-05-22 10:11:50 +02:00
string marketPairs = SettingsHandler . GetMarketPairs ( this . PTMagicConfiguration , this . PairsLines , this . Log ) ;
2019-02-04 01:17:38 +01:00
if ( marketPairs . ToLower ( ) . Equals ( "all" ) | | marketPairs . ToLower ( ) . Equals ( "false" ) | | marketPairs . ToLower ( ) . Equals ( "true" ) | | String . IsNullOrEmpty ( marketPairs ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
this . MarketList = this . ExchangeMarketList ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-01-07 15:33:02 +01:00
// Since PT 2.0 the main market is no longer included in the market list so we need to rebuild the list
List < string > originalMarketList = SystemHelper . ConvertTokenStringToList ( marketPairs , "," ) ;
foreach ( string market in originalMarketList )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
this . MarketList . Add ( SystemHelper . GetFullMarketName ( this . LastRuntimeSummary . MainMarket , market , this . PTMagicConfiguration . GeneralSettings . Application . Exchange ) ) ;
2018-05-22 10:11:50 +02:00
}
}
}
2018-12-15 22:07:29 +01:00
private void ValidateMarketList ( )
{
2018-05-22 10:11:50 +02:00
// Check if markets are valid for the selected main market
List < string > validMarkets = this . MarketList . FindAll ( m = > m . IndexOf ( this . LastRuntimeSummary . MainMarket , StringComparison . InvariantCultureIgnoreCase ) > - 1 ) ;
2018-12-15 22:07:29 +01:00
if ( validMarkets . Count = = 0 )
{
2018-05-22 10:11:50 +02:00
Exception ex = new Exception ( "No valid pairs found for main market '" + this . LastRuntimeSummary . MainMarket + "' in configured pars list (" + SystemHelper . ConvertListToTokenString ( this . MarketList , "," , true ) + ")! Terminating process..." ) ;
Log . DoLogError ( ex . Message ) ;
this . State = Constants . PTMagicBotState_Idle ;
this . Timer . Stop ( ) ;
throw ex ;
}
}
2018-12-15 22:07:29 +01:00
private void BuildGlobalMarketTrends ( )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Build global market trends..." ) ;
this . SingleMarketTrendChanges = BaseAnalyzer . BuildMarketTrends ( "Exchange" , this . LastRuntimeSummary . MainMarket , this . MarketList , "Volume" , false , new Dictionary < string , List < MarketTrendChange > > ( ) , this . PTMagicConfiguration , this . Log ) ;
this . GlobalMarketTrendChanges = new Dictionary < string , List < MarketTrendChange > > ( ) ;
// CoinMarketCap
this . GlobalMarketTrendChanges = BaseAnalyzer . BuildMarketTrends ( "CoinMarketCap" , this . LastRuntimeSummary . MainMarket , new List < string > ( ) , "" , true , this . GlobalMarketTrendChanges , this . PTMagicConfiguration , this . Log ) ;
// Bittrex
2018-12-15 22:07:29 +01:00
foreach ( MarketTrend marketTrend in this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . MarketTrends . FindAll ( mt = > mt . Platform . Equals ( "Exchange" , StringComparison . InvariantCultureIgnoreCase ) ) )
{
if ( this . SingleMarketTrendChanges . ContainsKey ( marketTrend . Name ) )
{
2018-05-22 10:11:50 +02:00
int maxMarkets = this . SingleMarketTrendChanges [ marketTrend . Name ] . Count ;
2018-12-15 22:07:29 +01:00
if ( marketTrend . MaxMarkets > 0 & & marketTrend . MaxMarkets < = this . SingleMarketTrendChanges [ marketTrend . Name ] . Count )
{
2018-05-22 10:11:50 +02:00
maxMarkets = marketTrend . MaxMarkets ;
}
this . GlobalMarketTrendChanges . Add ( marketTrend . Name , this . SingleMarketTrendChanges [ marketTrend . Name ] . Take ( maxMarkets ) . ToList ( ) ) ;
}
}
this . AverageMarketTrendChanges = BaseAnalyzer . BuildGlobalMarketTrends ( this . GlobalMarketTrendChanges , this . PTMagicConfiguration , this . Log ) ;
this . Log . DoLogInfo ( "Global market trends built." ) ;
}
2018-12-15 22:07:29 +01:00
private void CheckGlobalSettingsTriggers ( ref GlobalSetting triggeredSetting , ref List < string > matchedTriggers )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Checking global settings triggers..." ) ;
2018-12-15 22:07:29 +01:00
foreach ( GlobalSetting globalSetting in this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings )
{
2018-05-22 10:11:50 +02:00
// Reset triggers for each setting
matchedTriggers = new List < string > ( ) ;
2018-12-15 22:07:29 +01:00
if ( globalSetting . Triggers . Count > 0 )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Checking triggers for '" + globalSetting . SettingName + "'..." ) ;
List < bool > triggerResults = new List < bool > ( ) ;
2018-12-15 22:07:29 +01:00
foreach ( Trigger trigger in globalSetting . Triggers )
{
2018-05-22 10:11:50 +02:00
MarketTrend marketTrend = this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . MarketTrends . Find ( mt = > mt . Name = = trigger . MarketTrendName ) ;
2018-12-15 22:07:29 +01:00
if ( marketTrend ! = null )
{
2018-05-22 10:11:50 +02:00
// Get market trend change for trigger
2018-12-15 22:07:29 +01:00
if ( this . AverageMarketTrendChanges . ContainsKey ( marketTrend . Name ) )
{
2018-05-22 10:11:50 +02:00
double averageMarketTrendChange = this . AverageMarketTrendChanges [ marketTrend . Name ] ;
2018-12-15 22:07:29 +01:00
if ( averageMarketTrendChange > = trigger . MinChange & & averageMarketTrendChange < trigger . MaxChange )
{
2018-05-22 10:11:50 +02:00
// Trigger met!
this . Log . DoLogInfo ( "Trigger '" + trigger . MarketTrendName + "' triggered! TrendChange = " + averageMarketTrendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
string triggerContent = trigger . MarketTrendName + " - " ;
2018-12-15 22:07:29 +01:00
if ( trigger . MinChange ! = Constants . MinTrendChange )
{
2018-05-22 10:11:50 +02:00
triggerContent + = " - Min: " + trigger . MinChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ;
}
2018-12-15 22:07:29 +01:00
if ( trigger . MaxChange ! = Constants . MaxTrendChange )
{
2018-05-22 10:11:50 +02:00
triggerContent + = " - Max: " + trigger . MaxChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ;
}
matchedTriggers . Add ( triggerContent ) ;
triggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "Trigger '" + trigger . MarketTrendName + "' not triggered. TrendChange = " + averageMarketTrendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogError ( "Trigger '" + trigger . MarketTrendName + "' not found in this.AverageMarketTrendChanges[] (" + SystemHelper . ConvertListToTokenString ( this . AverageMarketTrendChanges . Keys . ToList ( ) , "," , true ) + "). Unable to load recent trends?" ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "Market Trend '" + trigger . MarketTrendName + "' not found! Trigger ignored!" ) ;
triggerResults . Add ( false ) ;
}
}
// Check if all triggers have to get triggered or just one
bool settingTriggered = false ;
2018-12-15 22:07:29 +01:00
switch ( globalSetting . TriggerConnection . ToLower ( ) )
{
2018-05-22 10:11:50 +02:00
case "and" :
settingTriggered = triggerResults . FindAll ( tr = > tr = = false ) . Count = = 0 ;
break ;
case "or" :
settingTriggered = triggerResults . FindAll ( tr = > tr = = true ) . Count > 0 ;
break ;
}
// Setting got triggered -> Activate it!
2018-12-15 22:07:29 +01:00
if ( settingTriggered )
{
2018-05-22 10:11:50 +02:00
triggeredSetting = globalSetting ;
break ;
}
}
}
}
2018-12-15 22:07:29 +01:00
private void ActivateSetting ( ref bool headerLinesAdded , ref GlobalSetting triggeredSetting , ref List < string > matchedTriggers )
{
2019-03-05 23:55:46 +01:00
// Get the current active setting
2018-05-23 06:23:10 +02:00
string activeSettingName = SettingsHandler . GetActiveSetting ( this , ref headerLinesAdded ) ;
2019-02-04 01:17:38 +01:00
if ( String . IsNullOrEmpty ( activeSettingName ) & & this . PTMagicConfiguration . GeneralSettings . Application . TestMode )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
activeSettingName = this . ActiveSetting ;
}
GlobalSetting activeSetting = this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings . Find ( s = > s . SettingName . Equals ( activeSettingName , StringComparison . InvariantCultureIgnoreCase ) ) ;
2019-03-05 23:55:46 +01:00
// Do we need to write the settings?
2018-12-15 22:07:29 +01:00
if ( this . EnforceSettingsReapply | | ! activeSettingName . Equals ( triggeredSetting . SettingName , StringComparison . InvariantCultureIgnoreCase ) )
{
2019-03-05 23:55:46 +01:00
// Check if we need to force a refresh of the settings
2019-03-09 09:38:46 +01:00
this . Log . DoLogInfo ( "Setting '" + activeSettingName + "' currently active. Checking for flood protection..." ) ;
2018-05-22 10:11:50 +02:00
// If the setting we are about to activate is the default one, do not list matched triggers
2018-12-15 22:07:29 +01:00
if ( triggeredSetting . SettingName . Equals ( this . DefaultSettingName , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
matchedTriggers = new List < string > ( ) ;
}
// Check if flood protection is active
2019-03-12 22:22:48 +01:00
if ( this . EnforceSettingsReapply | | this . LastSettingsChange < = DateTime . UtcNow . AddMinutes ( - PTMagicConfiguration . GeneralSettings . Application . FloodProtectionMinutes ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
// Setting not set => Change setting
2019-03-05 23:55:46 +01:00
if ( ! EnforceSettingsReapply )
{
this . Log . DoLogInfo ( "Switching global settings to '" + triggeredSetting . SettingName + "'..." ) ;
}
2019-03-09 09:38:46 +01:00
else
{
this . Log . DoLogInfo ( "Applying '" + triggeredSetting . SettingName + "' as the settings.analyzer.json or a preset file got changed." ) ;
}
2019-03-05 23:55:46 +01:00
2018-05-23 07:44:31 +02:00
SettingsHandler . CompileProperties ( this , triggeredSetting ) ;
2018-05-22 10:11:50 +02:00
this . GlobalSettingWritten = true ;
this . Log . DoLogInfo ( "Setting '" + triggeredSetting . SettingName + "' now active!" ) ;
this . LastRuntimeSummary . LastGlobalSettingSwitch = this . LastRuntimeSummary . LastRuntime ;
this . LastRuntimeSummary . CurrentGlobalSetting = triggeredSetting ;
// Build Telegram message
2019-03-05 23:55:46 +01:00
string telegramMessage ;
2019-03-09 09:38:46 +01:00
telegramMessage = this . PTMagicConfiguration . GeneralSettings . Application . InstanceName + ": Setting switched to '*" + SystemHelper . SplitCamelCase ( triggeredSetting . SettingName ) + "*'." ;
2019-03-05 23:55:46 +01:00
2019-03-09 09:38:46 +01:00
if ( matchedTriggers . Count > 0 )
{
telegramMessage + = "\n\n*Matching Triggers:*" ;
foreach ( string triggerResult in matchedTriggers )
2018-12-15 22:07:29 +01:00
{
2019-03-09 09:38:46 +01:00
telegramMessage + = "\n" + triggerResult ;
2018-05-22 10:11:50 +02:00
}
2019-03-09 09:38:46 +01:00
}
2018-05-22 10:11:50 +02:00
2019-03-09 09:38:46 +01:00
if ( this . AverageMarketTrendChanges . Keys . Count > 0 )
{
telegramMessage + = "\n\n*Market Trends:*" ;
foreach ( string key in this . AverageMarketTrendChanges . Keys )
2018-12-15 22:07:29 +01:00
{
2019-03-09 09:38:46 +01:00
telegramMessage + = "\n" + key + ": " + this . AverageMarketTrendChanges [ key ] . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ;
2018-05-22 10:11:50 +02:00
}
}
// Send Telegram message
2019-03-09 09:38:46 +01:00
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 ) ;
}
2018-05-22 10:11:50 +02:00
2019-03-05 23:55:46 +01:00
// Record last settings run
2018-05-22 10:11:50 +02:00
this . LastSetting = activeSettingName ;
this . LastSettingsChange = DateTime . UtcNow ;
2018-12-15 22:07:29 +01:00
}
else
{
2019-03-05 23:55:46 +01:00
// Flood protection
2018-05-22 10:11:50 +02:00
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 ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
matchedTriggers = new List < string > ( ) ;
// Setting already set => Do nothing
this . Log . DoLogInfo ( "Setting '" + triggeredSetting . SettingName + "' already active. No action taken." ) ;
this . LastRuntimeSummary . CurrentGlobalSetting = triggeredSetting ;
}
this . ActiveSetting = this . LastRuntimeSummary . CurrentGlobalSetting . SettingName ;
}
2018-12-15 22:07:29 +01:00
private void ApplySingleMarketSettings ( )
{
if ( this . PTMagicConfiguration . AnalyzerSettings . SingleMarketSettings . Count > 0 )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Checking single market settings triggers for " + this . MarketList . Count . ToString ( ) + " markets..." ) ;
int marketPairProcess = 1 ;
Dictionary < string , List < string > > matchedMarketTriggers = new Dictionary < string , List < string > > ( ) ;
2018-12-15 22:07:29 +01:00
foreach ( string marketPair in this . MarketList )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Checking triggers (" + marketPairProcess . ToString ( ) + "/" + this . MarketList . Count . ToString ( ) + ")..." ) ;
bool stopTriggers = false ;
2018-12-15 22:07:29 +01:00
foreach ( SingleMarketSetting marketSetting in this . PTMagicConfiguration . AnalyzerSettings . SingleMarketSettings )
{
2018-05-22 10:11:50 +02:00
List < string > matchedSingleMarketTriggers = new List < string > ( ) ;
// Check ignore markets
List < string > ignoredMarkets = SystemHelper . ConvertTokenStringToList ( marketSetting . IgnoredMarkets , "," ) ;
2018-12-15 22:07:29 +01:00
if ( ignoredMarkets . Contains ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Is ignored in '" + marketSetting . SettingName + "'." ) ;
continue ;
}
// Check allowed markets
List < string > allowedMarkets = SystemHelper . ConvertTokenStringToList ( marketSetting . AllowedMarkets , "," ) ;
2018-12-15 22:07:29 +01:00
if ( allowedMarkets . Count > 0 & & ! allowedMarkets . Contains ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Is not allowed in '" + marketSetting . SettingName + "'." ) ;
continue ;
}
// Check ignore global settings
List < string > ignoredGlobalSettings = SystemHelper . ConvertTokenStringToList ( marketSetting . IgnoredGlobalSettings , "," ) ;
2018-12-15 22:07:29 +01:00
if ( ignoredGlobalSettings . Contains ( this . ActiveSetting ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + this . ActiveSetting + "' - Is ignored in '" + marketSetting . SettingName + "'." ) ;
continue ;
}
// Check allowed global settings
List < string > allowedGlobalSettings = SystemHelper . ConvertTokenStringToList ( marketSetting . AllowedGlobalSettings , "," ) ;
2018-12-15 22:07:29 +01:00
if ( allowedGlobalSettings . Count > 0 & & ! allowedGlobalSettings . Contains ( this . ActiveSetting ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + this . ActiveSetting + "' - Is not allowed in '" + marketSetting . SettingName + "'." ) ;
continue ;
}
#region Checking Off Triggers
SingleMarketSettingSummary smss = this . SingleMarketSettingSummaries . Find ( s = > s . Market . Equals ( marketPair , StringComparison . InvariantCultureIgnoreCase ) & & s . SingleMarketSetting . SettingName . Equals ( marketSetting . SettingName , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( smss ! = null )
{
if ( marketSetting . OffTriggers ! = null )
{
if ( marketSetting . OffTriggers . Count > 0 )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Checking off triggers '" + marketSetting . SettingName + "'..." ) ;
List < bool > offTriggerResults = new List < bool > ( ) ;
2018-12-15 22:07:29 +01:00
foreach ( OffTrigger offTrigger in marketSetting . OffTriggers )
{
if ( offTrigger . HoursSinceTriggered > 0 )
{
2018-05-22 10:11:50 +02:00
#region Check for Activation time period trigger
int smsActiveHours = ( int ) Math . Floor ( DateTime . UtcNow . Subtract ( smss . ActivationDateTimeUTC ) . TotalHours ) ;
2018-12-15 22:07:29 +01:00
if ( smsActiveHours > = offTrigger . HoursSinceTriggered )
{
2018-05-22 10:11:50 +02:00
// Trigger met!
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS already active for " + smsActiveHours . ToString ( ) + " hours. Trigger matched!" ) ;
offTriggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
// Trigger not met!
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS only active for " + smsActiveHours . ToString ( ) + " hours. Trigger not matched!" ) ;
offTriggerResults . Add ( false ) ;
}
#endregion
2018-12-15 22:07:29 +01:00
}
else if ( offTrigger . Min24hVolume > 0 | | offTrigger . Max24hVolume < Constants . Max24hVolume )
{
2018-05-22 10:11:50 +02:00
#region Check for 24 h volume trigger
List < MarketTrendChange > marketTrendChanges = this . SingleMarketTrendChanges [ this . SingleMarketTrendChanges . Keys . Last ( ) ] ;
2018-12-15 22:07:29 +01:00
if ( marketTrendChanges . Count > 0 )
{
2018-05-22 10:11:50 +02:00
MarketTrendChange mtc = marketTrendChanges . Find ( m = > m . Market . Equals ( marketPair , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( mtc ! = null )
{
if ( mtc . Volume24h > = offTrigger . Min24hVolume & & mtc . Volume24h < = offTrigger . Max24hVolume )
{
2018-05-22 10:11:50 +02:00
// Trigger met!
this . Log . DoLogDebug ( "'" + marketPair + "' - 24h volume off trigger matched! 24h volume = " + mtc . Volume24h . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ) ;
offTriggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
// Trigger not met!
this . Log . DoLogDebug ( "'" + marketPair + "' - 24h volume off trigger not matched! 24h volume = " + mtc . Volume24h . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ) ;
offTriggerResults . Add ( false ) ;
}
}
}
#endregion
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
#region Check for market trend triggers
2018-12-15 22:07:29 +01:00
if ( this . SingleMarketTrendChanges . ContainsKey ( offTrigger . MarketTrendName ) )
{
2018-05-22 10:11:50 +02:00
List < MarketTrendChange > marketTrendChanges = this . SingleMarketTrendChanges [ offTrigger . MarketTrendName ] ;
2018-12-15 22:07:29 +01:00
if ( marketTrendChanges . Count > 0 )
{
2018-05-22 10:11:50 +02:00
double averageMarketTrendChange = marketTrendChanges . Average ( m = > m . TrendChange ) ;
MarketTrendChange mtc = marketTrendChanges . Find ( m = > m . Market . Equals ( marketPair , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( mtc ! = null )
{
2018-05-22 10:11:50 +02:00
// Get trend change according to configured relation
double trendChange = mtc . TrendChange ;
2018-12-15 22:07:29 +01:00
if ( offTrigger . MarketTrendRelation . Equals ( Constants . MarketTrendRelationRelative ) )
{
2018-05-22 10:11:50 +02:00
// Build pair trend change relative to the global market trend
trendChange = trendChange - averageMarketTrendChange ;
2018-12-15 22:07:29 +01:00
}
else if ( offTrigger . MarketTrendRelation . Equals ( Constants . MarketTrendRelationRelativeTrigger ) )
{
2018-05-22 10:11:50 +02:00
// Build pair trend change relative to the trigger price
double currentPrice = mtc . LastPrice ;
double triggerPrice = smss . TriggerSnapshot . LastPrice ;
double triggerTrend = ( currentPrice - triggerPrice ) / triggerPrice * 100 ;
trendChange = triggerTrend ;
}
// Get market trend change for trigger
2018-12-15 22:07:29 +01:00
if ( trendChange > = offTrigger . MinChange & & trendChange < offTrigger . MaxChange )
{
2018-05-22 10:11:50 +02:00
// Trigger met!
this . Log . DoLogDebug ( "'" + marketPair + "' - Off Trigger '" + offTrigger . MarketTrendName + "' triggered! TrendChange (" + offTrigger . MarketTrendRelation + ") = " + trendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
offTriggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Off Trigger '" + offTrigger . MarketTrendName + "' not triggered. TrendChange (" + offTrigger . MarketTrendRelation + ") = " + trendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
offTriggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
offTriggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
offTriggerResults . Add ( false ) ;
}
}
#endregion
}
}
// Check if all off triggers have to get triggered or just one
bool settingOffTriggered = false ;
2018-12-15 22:07:29 +01:00
switch ( marketSetting . OffTriggerConnection . ToLower ( ) )
{
2018-05-22 10:11:50 +02:00
case "and" :
settingOffTriggered = offTriggerResults . FindAll ( tr = > tr = = false ) . Count = = 0 ;
break ;
case "or" :
settingOffTriggered = offTriggerResults . FindAll ( tr = > tr = = true ) . Count > 0 ;
break ;
}
// Setting got off triggered, remove it from the summary
2018-12-15 22:07:29 +01:00
if ( settingOffTriggered )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + marketSetting . SettingName + "' off triggered!" ) ;
this . SingleMarketSettingSummaries . Remove ( smss ) ;
smss = null ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + marketSetting . SettingName + "' not off triggered!" ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + marketSetting . SettingName + "' has no off triggers -> triggering off!" ) ;
this . SingleMarketSettingSummaries . Remove ( smss ) ;
smss = null ;
}
}
}
#endregion
2018-12-15 22:07:29 +01:00
if ( marketSetting . Triggers . Count > 0 & & ! stopTriggers )
{
2018-05-22 10:11:50 +02:00
#region Checking Triggers
this . Log . DoLogDebug ( "'" + marketPair + "' - Checking triggers for '" + marketSetting . SettingName + "'..." ) ;
List < bool > triggerResults = new List < bool > ( ) ;
Dictionary < int , double > relevantTriggers = new Dictionary < int , double > ( ) ;
int triggerIndex = 0 ;
2018-12-15 22:07:29 +01:00
foreach ( Trigger trigger in marketSetting . Triggers )
{
2018-05-22 10:11:50 +02:00
2018-12-15 22:07:29 +01:00
if ( trigger . Min24hVolume > 0 | | trigger . Max24hVolume < Constants . Max24hVolume )
{
2018-05-22 10:11:50 +02:00
#region Check for 24 h volume trigger
List < MarketTrendChange > marketTrendChanges = this . SingleMarketTrendChanges [ this . SingleMarketTrendChanges . Keys . Last ( ) ] ;
2018-12-15 22:07:29 +01:00
if ( marketTrendChanges . Count > 0 )
{
2018-05-22 10:11:50 +02:00
MarketTrendChange mtc = marketTrendChanges . Find ( m = > m . Market . Equals ( marketPair , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( mtc ! = null )
{
2018-05-22 10:11:50 +02:00
2018-12-15 22:07:29 +01:00
if ( mtc . Volume24h > = trigger . Min24hVolume & & mtc . Volume24h < = trigger . Max24hVolume )
{
2018-05-22 10:11:50 +02:00
// Trigger met!
this . Log . DoLogDebug ( "'" + marketPair + "' - 24h volume trigger matched! 24h volume = " + mtc . Volume24h . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ) ;
relevantTriggers . Add ( triggerIndex , mtc . Volume24h ) ;
string triggerContent = "24h Volume" ;
2018-12-15 22:07:29 +01:00
if ( trigger . Min24hVolume > 0 )
{
2018-05-22 10:11:50 +02:00
triggerContent + = " - Min: " + trigger . Min24hVolume . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ;
}
2018-12-15 22:07:29 +01:00
if ( trigger . Max24hVolume < Constants . Max24hVolume )
{
2018-05-22 10:11:50 +02:00
triggerContent + = " - Max: " + trigger . Max24hVolume . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ;
}
matchedSingleMarketTriggers . Add ( marketSetting . SettingName + ": " + triggerContent + " - 24h volume = " + mtc . Volume24h . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ) ;
triggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - 24h volume trigger not matched. 24h volume = " + mtc . Volume24h . ToString ( new System . Globalization . CultureInfo ( "en-US" ) ) + " " + this . LastRuntimeSummary . MainMarket ) ;
triggerResults . Add ( false ) ;
}
}
}
#endregion
2018-12-15 22:07:29 +01:00
}
else if ( trigger . AgeDaysLowerThan > 0 )
{
2018-05-22 10:11:50 +02:00
#region Check for age trigger
MarketInfo marketInfo = null ;
2018-12-15 22:07:29 +01:00
if ( this . MarketInfos . ContainsKey ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
marketInfo = this . MarketInfos [ marketPair ] ;
}
2018-12-15 22:07:29 +01:00
if ( marketInfo ! = null )
{
2019-02-04 01:17:38 +01:00
int marketAge = ( int ) Math . Floor ( DateTime . UtcNow . Subtract ( marketInfo . FirstSeen ) . TotalDays ) ;
2018-12-15 22:07:29 +01:00
if ( marketAge < trigger . AgeDaysLowerThan )
{
2018-05-22 10:11:50 +02:00
matchedSingleMarketTriggers . Add ( marketSetting . SettingName + ": '" + marketPair + "' is only " + marketAge . ToString ( ) + " days old on this exchange. Trigger matched!" ) ;
this . Log . DoLogDebug ( "'" + marketPair + "' - Is only " + marketAge . ToString ( ) + " days old on this exchange. Trigger matched!" ) ;
relevantTriggers . Add ( triggerIndex , marketAge ) ;
triggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Age Trigger not triggered. Is already " + marketAge . ToString ( ) + " days old on this exchange." ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
matchedSingleMarketTriggers . Add ( "Age for '" + marketPair + "' not found, trigger matched just to be safe!" ) ;
this . Log . DoLogDebug ( "'" + marketPair + "' - Age not found, trigger matched just to be safe!" ) ;
triggerResults . Add ( true ) ;
}
#endregion
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
#region Check for market trend triggers
2018-12-15 22:07:29 +01:00
if ( this . SingleMarketTrendChanges . ContainsKey ( trigger . MarketTrendName ) )
{
2018-05-22 10:11:50 +02:00
List < MarketTrendChange > marketTrendChanges = this . SingleMarketTrendChanges [ trigger . MarketTrendName ] ;
2018-12-15 22:07:29 +01:00
if ( marketTrendChanges . Count > 0 )
{
2018-05-22 10:11:50 +02:00
double averageMarketTrendChange = marketTrendChanges . Average ( m = > m . TrendChange ) ;
MarketTrendChange mtc = marketTrendChanges . Find ( m = > m . Market . Equals ( marketPair , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( mtc ! = null )
{
2018-05-22 10:11:50 +02:00
// Get trend change according to configured relation
double trendChange = mtc . TrendChange ;
2018-12-15 22:07:29 +01:00
if ( trigger . MarketTrendRelation . Equals ( Constants . MarketTrendRelationRelative ) )
{
2018-05-22 10:11:50 +02:00
// Build pair trend change relative to the global market trend
trendChange = trendChange - averageMarketTrendChange ;
}
// Get market trend change for trigger
2018-12-15 22:07:29 +01:00
if ( trendChange > = trigger . MinChange & & trendChange < trigger . MaxChange )
{
2018-05-22 10:11:50 +02:00
// Trigger met!
this . Log . DoLogDebug ( "'" + marketPair + "' - Trigger '" + trigger . MarketTrendName + "' triggered! TrendChange (" + trigger . MarketTrendRelation + ") = " + trendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
relevantTriggers . Add ( triggerIndex , trendChange ) ;
string triggerContent = trigger . MarketTrendName + " - " ;
2018-12-15 22:07:29 +01:00
if ( trigger . MinChange ! = Constants . MinTrendChange )
{
2018-05-22 10:11:50 +02:00
triggerContent + = " - Min: " + trigger . MinChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ;
}
2018-12-15 22:07:29 +01:00
if ( trigger . MaxChange ! = Constants . MaxTrendChange )
{
2018-05-22 10:11:50 +02:00
triggerContent + = " - Max: " + trigger . MaxChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ;
}
matchedSingleMarketTriggers . Add ( marketSetting . SettingName + ": " + triggerContent + " - TrendChange (" + trigger . MarketTrendRelation + ") = " + trendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
triggerResults . Add ( true ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - Trigger '" + trigger . MarketTrendName + "' not triggered. TrendChange (" + trigger . MarketTrendRelation + ") = " + trendChange . ToString ( "#,#0.00" , new System . Globalization . CultureInfo ( "en-US" ) ) + "%" ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - No market trend change found for '" + trigger . MarketTrendName + "'! Coin just got released? Trigger ignored!" ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "'" + marketPair + "' - No market trend changes found for '" + trigger . MarketTrendName + "'! Trigger ignored!" ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
MarketTrend marketTrend = this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . MarketTrends . Find ( mt = > mt . Name . Equals ( trigger . MarketTrendName , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( marketTrend ! = null )
{
if ( ! marketTrend . Platform . Equals ( "Exchange" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "Market Trend '" + trigger . MarketTrendName + "' is invalid for single market settings! Only trends using the platform 'Exchange' are valid for single market settings." ) ;
triggerResults . Add ( false ) ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "Market Trend '" + trigger . MarketTrendName + "' not found! Trigger ignored!" ) ;
triggerResults . Add ( false ) ;
}
}
#endregion
}
triggerIndex + + ;
}
// Check if all triggers have to get triggered or just one
bool settingTriggered = false ;
2018-12-15 22:07:29 +01:00
switch ( marketSetting . TriggerConnection . ToLower ( ) )
{
2018-05-22 10:11:50 +02:00
case "and" :
settingTriggered = triggerResults . FindAll ( tr = > tr = = false ) . Count = = 0 ;
break ;
case "or" :
settingTriggered = triggerResults . FindAll ( tr = > tr = = true ) . Count > 0 ;
break ;
}
#endregion
bool isFreshTrigger = true ;
// Setting not triggered -> Check if it is already active as a long term SMS using Off Triggers
2018-12-15 22:07:29 +01:00
if ( ! settingTriggered )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS '" + marketSetting . SettingName + "' not triggered, checking for long term activation." ) ;
2018-12-15 22:07:29 +01:00
if ( smss ! = null )
{
if ( marketSetting . OffTriggers ! = null )
{
if ( marketSetting . OffTriggers . Count > 0 )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS '" + marketSetting . SettingName + "' has off triggers, starting special trigger..." ) ;
// Setting already active and using off triggers -> set as triggered
settingTriggered = true ;
isFreshTrigger = false ;
matchedSingleMarketTriggers = new List < string > ( ) ;
2018-12-15 22:07:29 +01:00
foreach ( string matchedTriggerContent in smss . TriggerSnapshot . MatchedTriggersContent )
{
if ( matchedTriggerContent . StartsWith ( marketSetting . SettingName + ":" ) )
{
2018-05-22 10:11:50 +02:00
matchedSingleMarketTriggers . Add ( matchedTriggerContent ) ;
}
}
int removalLength = matchedSingleMarketTriggers . Count - marketSetting . Triggers . Count ;
2018-12-15 22:07:29 +01:00
if ( removalLength > 0 )
{
2018-05-22 10:11:50 +02:00
matchedSingleMarketTriggers . RemoveRange ( 0 , removalLength ) ;
}
this . Log . DoLogDebug ( "'" + marketPair + "' - Activating SMS '" + marketSetting . SettingName + "' as off triggers are not met." ) ;
}
}
}
}
// Setting got triggered -> Activate it!
2018-12-15 22:07:29 +01:00
if ( settingTriggered )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + marketSetting . SettingName + "' triggered!" ) ;
// Save matched triggers to get displayed in the comment lines
2018-12-15 22:07:29 +01:00
if ( ! matchedMarketTriggers . ContainsKey ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
matchedMarketTriggers . Add ( marketPair , matchedSingleMarketTriggers ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
matchedMarketTriggers [ marketPair ] . AddRange ( matchedSingleMarketTriggers ) ;
}
2018-12-15 22:07:29 +01:00
if ( ! this . TriggeredSingleMarketSettings . ContainsKey ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
List < SingleMarketSetting > smsList = new List < SingleMarketSetting > ( ) ;
smsList . Add ( marketSetting ) ;
this . TriggeredSingleMarketSettings . Add ( marketPair , smsList ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . TriggeredSingleMarketSettings [ marketPair ] . Add ( marketSetting ) ;
}
// Counting triggered setting
2018-12-15 22:07:29 +01:00
if ( ! this . SingleMarketSettingsCount . ContainsKey ( marketSetting . SettingName ) )
{
2018-05-22 10:11:50 +02:00
this . SingleMarketSettingsCount . Add ( marketSetting . SettingName , 1 ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . SingleMarketSettingsCount [ marketSetting . SettingName ] + + ;
}
2018-12-15 22:07:29 +01:00
if ( isFreshTrigger )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS '" + marketSetting . SettingName + "' saving summary data..." ) ;
// Check if this setting is already active for this market
2018-12-15 22:07:29 +01:00
if ( smss = = null | | marketSetting . RefreshOffTriggers )
{
if ( smss = = null )
{
2018-05-22 10:11:50 +02:00
smss = new SingleMarketSettingSummary ( ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . SingleMarketSettingSummaries . Remove ( smss ) ;
}
smss . ActivationDateTimeUTC = DateTime . UtcNow ;
smss . Market = marketPair ;
smss . SingleMarketSetting = marketSetting ;
smss . TriggerSnapshot = new TriggerSnapshot ( ) ;
smss . TriggerSnapshot . Last24hVolume = 0 ;
smss . TriggerSnapshot . LastPrice = 0 ;
smss . TriggerSnapshot . RelevantTriggers = relevantTriggers ;
smss . TriggerSnapshot . MatchedTriggersContent = matchedSingleMarketTriggers ;
List < MarketTrendChange > marketTrendChanges = this . SingleMarketTrendChanges [ this . SingleMarketTrendChanges . Keys . Last ( ) ] ;
2018-12-15 22:07:29 +01:00
if ( marketTrendChanges . Count > 0 )
{
2018-05-22 10:11:50 +02:00
MarketTrendChange mtc = marketTrendChanges . Find ( m = > m . Market . Equals ( marketPair , StringComparison . InvariantCultureIgnoreCase ) ) ;
2018-12-15 22:07:29 +01:00
if ( mtc ! = null )
{
2018-05-22 10:11:50 +02:00
smss . TriggerSnapshot . Last24hVolume = mtc . Volume24h ;
smss . TriggerSnapshot . LastPrice = mtc . LastPrice ;
}
}
this . SingleMarketSettingSummaries . Add ( smss ) ;
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS '" + marketSetting . SettingName + "' summary data saved." ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - SMS '" + marketSetting . SettingName + "' already active for this market and no refresh allowed." ) ;
}
}
// Stop processing other settings if configured
2018-12-15 22:07:29 +01:00
if ( marketSetting . StopProcessWhenTriggered )
{
2018-05-22 10:11:50 +02:00
stopTriggers = true ;
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogDebug ( "'" + marketPair + "' - '" + marketSetting . SettingName + "' not triggered!" ) ;
}
}
}
2018-12-15 22:07:29 +01:00
if ( ( marketPairProcess % 10 ) = = 0 )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "What are you looking at? " + marketPairProcess + "/" + this . MarketList . Count + " markets done..." ) ;
}
marketPairProcess + + ;
}
2018-12-15 22:07:29 +01:00
if ( this . TriggeredSingleMarketSettings . Count > 0 )
{
2018-05-22 10:11:50 +02:00
// Write single market settings
this . Log . DoLogInfo ( "Building single market settings for '" + this . TriggeredSingleMarketSettings . Count . ToString ( ) + "' markets..." ) ;
2018-05-22 13:04:53 +02:00
SettingsHandler . CompileSingleMarketProperties ( this , matchedMarketTriggers ) ;
2018-05-22 10:11:50 +02:00
this . SingleMarketSettingWritten = true ;
this . Log . DoLogInfo ( "Building single market settings completed." ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "No settings triggered for single markets." ) ;
// Remove single market settings if no triggers are met - if necessary
2018-05-22 13:04:53 +02:00
this . SingleMarketSettingWritten = SettingsHandler . RemoveSingleMarketSettings ( this ) ;
2018-05-22 10:11:50 +02:00
}
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "No single market settings found." ) ;
}
}
2019-03-05 23:55:46 +01:00
private void SaveProfitTrailerProperties ( bool headerLinesAdded )
2018-12-15 22:07:29 +01:00
{
2019-03-05 23:55:46 +01:00
// Get current PT properties
string pairsPropertiesPath , dcaPropertiesPath , indicatorsPropertiesPath ;
GetProfitTrailerPropertiesPaths ( out pairsPropertiesPath , out dcaPropertiesPath , out indicatorsPropertiesPath ) ;
2018-12-15 22:07:29 +01:00
if ( headerLinesAdded | | this . GlobalSettingWritten | | this . SingleMarketSettingWritten )
{
2019-01-07 15:33:02 +01:00
// Save current PT properties to API (Valid for PT 2.x and above)
this . Log . DoLogInfo ( "Saving properties using API..." ) ;
2018-05-22 10:11:50 +02:00
2019-01-07 15:33:02 +01:00
// Send all Properties
if ( ! this . PTMagicConfiguration . GeneralSettings . Application . TestMode ) SettingsAPI . SendPropertyLinesToAPI ( this . PairsLines , this . DCALines , this . IndicatorsLines , this . PTMagicConfiguration , this . Log ) ;
2018-05-22 10:11:50 +02:00
2019-01-07 15:33:02 +01:00
this . Log . DoLogInfo ( "Properties saved!" ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Nothing changed, no files touched!" ) ;
}
}
2018-12-15 22:07:29 +01:00
private void SaveSingleMarketSettingsSummary ( )
{
2018-05-22 10:11:50 +02:00
JsonSerializerSettings smsSummaryJsonSettings = new JsonSerializerSettings ( ) ;
smsSummaryJsonSettings . NullValueHandling = NullValueHandling . Ignore ;
smsSummaryJsonSettings . DefaultValueHandling = DefaultValueHandling . Ignore ;
FileHelper . WriteTextToFile ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar , "SingleMarketSettingSummary.json" , JsonConvert . SerializeObject ( this . SingleMarketSettingSummaries , Formatting . None , smsSummaryJsonSettings ) ) ;
this . Log . DoLogInfo ( "Single Market Settings Summary saved." ) ;
}
2018-12-15 22:07:29 +01:00
private void SaveRuntimeSummary ( bool headerLinesAdded )
{
2019-02-04 01:17:38 +01:00
DateTime endTime = DateTime . UtcNow ;
2018-05-22 10:11:50 +02:00
int elapsedSeconds = ( int ) Math . Round ( endTime . Subtract ( this . LastRuntime ) . TotalSeconds , 0 ) ;
this . LastRuntimeSummary . LastRuntimeSeconds = elapsedSeconds ;
this . Log . DoLogInfo ( "Building LastRuntimeSummary.json for your monitor..." ) ;
// Load existing runtime summary and read ongoing data
2018-12-15 22:07:29 +01:00
if ( File . Exists ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar + "LastRuntimeSummary.json" ) )
{
try
{
2018-05-22 10:11:50 +02:00
Summary summary = JsonConvert . DeserializeObject < Summary > ( System . IO . File . ReadAllText ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar + "LastRuntimeSummary.json" ) ) ;
2018-12-15 22:07:29 +01:00
if ( summary ! = null )
{
2018-05-22 10:11:50 +02:00
// Last setting switch in case the app got restarted and has no history
2018-12-15 22:07:29 +01:00
if ( this . LastRuntimeSummary . LastGlobalSettingSwitch = = Constants . confMinDate )
{
2018-05-22 10:11:50 +02:00
this . LastRuntimeSummary . LastGlobalSettingSwitch = summary . LastGlobalSettingSwitch ;
}
// Market trend changes history for graph data
2018-12-15 22:07:29 +01:00
foreach ( string key in summary . MarketTrendChanges . Keys )
{
2019-02-04 01:17:38 +01:00
this . LastRuntimeSummary . MarketTrendChanges . Add ( key , summary . MarketTrendChanges [ key ] . FindAll ( mtc = > mtc . TrendDateTime > = DateTime . UtcNow . AddHours ( - PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . StoreDataMaxHours ) ) ) ;
2018-05-22 10:11:50 +02:00
}
// Global setting summary to be kept
2019-02-04 01:17:38 +01:00
this . LastRuntimeSummary . GlobalSettingSummary . AddRange ( summary . GlobalSettingSummary . FindAll ( gss = > gss . SwitchDateTime > = DateTime . UtcNow . AddHours ( - 96 ) ) ) ;
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Summary: Loaded old LastRuntimeSummary.json to keep data." ) ;
}
2018-12-15 22:07:29 +01:00
}
catch ( Exception ex )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogCritical ( "Summary: Error loading old summary (" + ex . Message + "). Creating new one." , ex ) ;
}
}
this . Log . DoLogInfo ( "Summary: Building global settings summary..." ) ;
// Change setting summary
GlobalSettingSummary lastSettingSummary = null ;
2018-12-15 22:07:29 +01:00
if ( this . LastRuntimeSummary . LastGlobalSettingSwitch = = this . LastRuntimeSummary . LastRuntime | | this . LastRuntimeSummary . GlobalSettingSummary . Count = = 0 )
{
2018-05-22 10:11:50 +02:00
// Setting got switched this run, add a new setting summary
GlobalSettingSummary gss = new GlobalSettingSummary ( ) ;
gss . SettingName = this . LastRuntimeSummary . CurrentGlobalSetting . SettingName ;
gss . SwitchDateTime = this . LastRuntimeSummary . LastRuntime . ToUniversalTime ( ) ;
2018-12-15 22:07:29 +01:00
if ( this . LastRuntimeSummary . GlobalSettingSummary . Count > 0 )
{
2018-05-22 10:11:50 +02:00
lastSettingSummary = this . LastRuntimeSummary . GlobalSettingSummary . OrderByDescending ( lss = > lss . SwitchDateTime ) . First ( ) ;
2019-02-04 01:17:38 +01:00
lastSettingSummary . ActiveSeconds = ( int ) Math . Ceiling ( DateTime . UtcNow . Subtract ( lastSettingSummary . SwitchDateTime ) . TotalSeconds ) ;
2018-05-22 10:11:50 +02:00
}
this . LastRuntimeSummary . GlobalSettingSummary . Add ( gss ) ;
lastSettingSummary = this . LastRuntimeSummary . GlobalSettingSummary . OrderByDescending ( lss = > lss . SwitchDateTime ) . First ( ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
// Setting did not get switched, update data
2018-12-15 22:07:29 +01:00
if ( this . LastRuntimeSummary . GlobalSettingSummary . Count > 0 )
{
2018-05-22 10:11:50 +02:00
lastSettingSummary = this . LastRuntimeSummary . GlobalSettingSummary . OrderByDescending ( lss = > lss . SwitchDateTime ) . First ( ) ;
2019-02-04 01:17:38 +01:00
lastSettingSummary . ActiveSeconds = ( int ) Math . Ceiling ( DateTime . UtcNow . Subtract ( lastSettingSummary . SwitchDateTime ) . TotalSeconds ) ;
2018-05-22 10:11:50 +02:00
}
}
this . Log . DoLogInfo ( "Summary: Built global settings summary." ) ;
this . Log . DoLogInfo ( "Summary: Save market trend changes for summary." ) ;
// Save market trend changes for the summary
2018-12-15 22:07:29 +01:00
foreach ( string key in this . AverageMarketTrendChanges . Keys )
{
2018-05-22 10:11:50 +02:00
List < MarketTrendChange > mtChanges = new List < MarketTrendChange > ( ) ;
2018-12-15 22:07:29 +01:00
if ( this . LastRuntimeSummary . MarketTrendChanges . ContainsKey ( key ) )
{
2018-05-22 10:11:50 +02:00
mtChanges = this . LastRuntimeSummary . MarketTrendChanges [ key ] ;
}
MarketTrendChange newChange = new MarketTrendChange ( ) ;
newChange . MarketTrendName = key ;
newChange . TrendChange = this . AverageMarketTrendChanges [ key ] ;
newChange . TrendDateTime = this . LastRuntimeSummary . LastRuntime ;
mtChanges . Add ( newChange ) ;
2018-12-15 22:07:29 +01:00
if ( lastSettingSummary ! = null )
{
if ( ! lastSettingSummary . MarketTrendChanges . ContainsKey ( key ) )
{
2018-05-22 10:11:50 +02:00
GlobalSetting gs = this . PTMagicConfiguration . AnalyzerSettings . GlobalSettings . Find ( g = > g . SettingName . Equals ( lastSettingSummary . SettingName ) ) ;
2018-12-15 22:07:29 +01:00
if ( gs ! = null )
{
if ( gs . SettingName . Equals ( "Default" , StringComparison . InvariantCultureIgnoreCase ) | | gs . Triggers . Find ( t = > t . MarketTrendName . Equals ( key ) ) ! = null )
{
2018-05-22 10:11:50 +02:00
lastSettingSummary . MarketTrendChanges . Add ( key , newChange ) ;
}
}
}
}
this . LastRuntimeSummary . MarketTrendChanges [ key ] = mtChanges ;
}
this . Log . DoLogInfo ( "Summary: Market trends saved." ) ;
this . Log . DoLogInfo ( "Summary: Getting current global properties..." ) ;
// Get current global settings from PAIRS.PROPERTIES
Dictionary < string , string > pairsProperties = SettingsHandler . GetPropertiesAsDictionary ( this . PairsLines ) ;
Dictionary < string , string > dcaProperties = SettingsHandler . GetPropertiesAsDictionary ( this . DCALines ) ;
string defaultBuyValueString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_buy_value" , "DEFAULT_A_buy_value" ) ;
double defaultBuyValue = SystemHelper . TextToDouble ( defaultBuyValueString , 0 , "en-US" ) ;
string defaultTrailingBuyString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_trailing_buy" , "DEFAULT_trailing_buy" ) ;
double defaultTrailingBuy = SystemHelper . TextToDouble ( defaultTrailingBuyString , 0 , "en-US" ) ;
string defaultSellValueString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_sell_value" , "DEFAULT_A_sell_value" ) ;
double defaultSellValue = SystemHelper . TextToDouble ( defaultSellValueString , 0 , "en-US" ) ;
string defaultTrailingProfitString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_trailing_profit" , "DEFAULT_trailing_profit" ) ;
double defaultTrailingProfit = SystemHelper . TextToDouble ( defaultTrailingProfitString , 0 , "en-US" ) ;
string defaultMaxTradingPairsString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_max_trading_pairs" , "max_trading_pairs" ) ;
double defaultMaxTradingPairs = SystemHelper . TextToDouble ( defaultMaxTradingPairsString , 0 , "en-US" ) ;
string defaultMaxCostString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_max_cost" , "DEFAULT_initial_cost" ) ;
double defaultMaxCost = SystemHelper . TextToDouble ( defaultMaxCostString , 0 , "en-US" ) ;
string defaultMaxCostPercentageString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_max_cost_percentage" , "DEFAULT_initial_cost_percentage" ) ;
double defaultMaxCostPercentage = SystemHelper . TextToDouble ( defaultMaxCostPercentageString , 0 , "en-US" ) ;
string defaultMinBuyVolumeString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_min_buy_volume" , "DEFAULT_min_buy_volume" ) ;
double defaultMinBuyVolume = SystemHelper . TextToDouble ( defaultMinBuyVolumeString , 0 , "en-US" ) ;
string defaultDCALevelString = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "max_buy_times" , "DEFAULT_DCA_max_buy_times" ) ;
double defaultDCALevel = SystemHelper . TextToDouble ( defaultDCALevelString , 0 , "en-US" ) ;
string defaultBuyStrategy = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_buy_strategy" , "DEFAULT_A_buy_strategy" ) ;
string defaultSellStrategy = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_sell_strategy" , "DEFAULT_A_sell_strategy" ) ;
string defaultDCAEnabledString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_DCA_enabled" , "DEFAULT_DCA_enabled" ) ;
bool defaultDCAEnabled = ( defaultDCAEnabledString . Equals ( "false" , StringComparison . InvariantCultureIgnoreCase ) ) ? false : true ;
string defaultSOMActiveString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "ALL_sell_only_mode" , "DEFAULT_sell_only_mode_enabled" ) ;
bool defaultSOMActive = ( defaultSOMActiveString . Equals ( "false" , StringComparison . InvariantCultureIgnoreCase ) ) ? false : true ;
this . LastRuntimeSummary . IsSOMActive = defaultSOMActive ;
string dcaBuyStrategyString = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "buy_strategy" , "DEFAULT_DCA_A_buy_strategy" ) ;
this . LastRuntimeSummary . DCABuyStrategy = dcaBuyStrategyString ;
this . LastRuntimeSummary . BuyValue = defaultBuyValue ;
this . LastRuntimeSummary . TrailingBuy = defaultTrailingBuy ;
this . LastRuntimeSummary . SellValue = defaultSellValue ;
this . LastRuntimeSummary . TrailingProfit = defaultTrailingProfit ;
this . LastRuntimeSummary . MaxTradingPairs = defaultMaxTradingPairs ;
this . LastRuntimeSummary . MaxCost = defaultMaxCost ;
this . LastRuntimeSummary . MaxCostPercentage = defaultMaxCostPercentage ;
this . LastRuntimeSummary . MinBuyVolume = defaultMinBuyVolume ;
this . LastRuntimeSummary . BuyStrategy = defaultBuyStrategy ;
this . LastRuntimeSummary . SellStrategy = defaultSellStrategy ;
this . LastRuntimeSummary . DCALevels = defaultDCALevel ;
double maxDCALevel = this . LastRuntimeSummary . DCALevels ;
if ( maxDCALevel = = 0 ) maxDCALevel = 1000 ;
string dcaDefaultTriggerString = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "buy_trigger" , "DEFAULT_DCA_buy_trigger" ) ;
double dcaDefaultTrigger = SystemHelper . TextToDouble ( dcaDefaultTriggerString , 0 , "en-US" ) ;
this . LastRuntimeSummary . DCATrigger = dcaDefaultTrigger ;
// Get configured DCA triggers
2018-12-15 22:07:29 +01:00
for ( int dca = 1 ; dca < = maxDCALevel ; dca + + )
{
2018-05-22 10:11:50 +02:00
string dcaTriggerString = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "buy_trigger_" + dca . ToString ( ) , "DEFAULT_DCA_buy_trigger_" + dca . ToString ( ) ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( dcaTriggerString ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
double dcaTrigger = SystemHelper . TextToDouble ( dcaTriggerString , 0 , "en-US" ) ;
this . LastRuntimeSummary . DCATriggers . Add ( dca , dcaTrigger ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
if ( this . LastRuntimeSummary . DCALevels = = 0 ) this . LastRuntimeSummary . DCALevels = dca - 1 ;
break ;
}
}
// Get configured DCA percentages
2019-01-07 15:33:02 +01:00
string dcaDefaultPercentageString = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "DEFAULT_DCA_buy_percentage" , "" ) ;
double dcaDefaultPercentage = SystemHelper . TextToDouble ( dcaDefaultPercentageString , 0 , "en-US" ) ;
this . LastRuntimeSummary . DCAPercentage = dcaDefaultPercentage ;
2018-05-22 10:11:50 +02:00
2019-01-07 15:33:02 +01:00
for ( int dca = 1 ; dca < = maxDCALevel ; dca + + )
{
string dcaPercentageString = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "DEFAULT_DCA_buy_percentage_" + dca . ToString ( ) , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( dcaPercentageString ) )
2018-12-15 22:07:29 +01:00
{
2019-01-07 15:33:02 +01:00
double dcaPercentage = SystemHelper . TextToDouble ( dcaPercentageString , 0 , "en-US" ) ;
2018-05-22 10:11:50 +02:00
2019-01-07 15:33:02 +01:00
this . LastRuntimeSummary . DCAPercentages . Add ( dca , dcaPercentage ) ;
}
else
{
if ( this . LastRuntimeSummary . DCALevels = = 0 ) this . LastRuntimeSummary . DCALevels = dca - 1 ;
break ;
2018-05-22 10:11:50 +02:00
}
2018-12-31 04:26:45 +01:00
}
2018-05-22 10:11:50 +02:00
// Get configured Buy Strategies
2018-12-15 22:07:29 +01:00
for ( char c = 'A' ; c < = 'Z' ; c + + )
{
2018-05-22 10:11:50 +02:00
string buyStrategyName = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "DEFAULT_" + c + "_buy_strategy" , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( buyStrategyName ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
StrategySummary buyStrategy = new StrategySummary ( ) ;
buyStrategy . Name = buyStrategyName ;
buyStrategy . Value = SystemHelper . TextToDouble ( SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "DEFAULT_" + c + "_buy_value" , "" ) , 0 , "en-US" ) ;
this . LastRuntimeSummary . BuyStrategies . Add ( buyStrategy ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
break ;
}
}
// Get configured Sell Strategies
2018-12-15 22:07:29 +01:00
for ( char c = 'A' ; c < = 'Z' ; c + + )
{
2018-05-22 10:11:50 +02:00
string sellStrategyName = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "DEFAULT_" + c + "_sell_strategy" , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( sellStrategyName ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
StrategySummary sellStrategy = new StrategySummary ( ) ;
sellStrategy . Name = sellStrategyName ;
sellStrategy . Value = SystemHelper . TextToDouble ( SettingsHandler . GetCurrentPropertyValue ( pairsProperties , "DEFAULT_" + c + "_sell_value" , "" ) , 0 , "en-US" ) ;
this . LastRuntimeSummary . SellStrategies . Add ( sellStrategy ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
break ;
}
}
// Get configured DCA Buy Strategies
2018-12-15 22:07:29 +01:00
for ( char c = 'A' ; c < = 'Z' ; c + + )
{
2018-05-22 10:11:50 +02:00
string buyStrategyName = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "DEFAULT_DCA_" + c + "_buy_strategy" , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( buyStrategyName ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
StrategySummary buyStrategy = new StrategySummary ( ) ;
buyStrategy . Name = buyStrategyName ;
buyStrategy . Value = SystemHelper . TextToDouble ( SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "DEFAULT_DCA_" + c + "_buy_value" , "" ) , 0 , "en-US" ) ;
this . LastRuntimeSummary . DCABuyStrategies . Add ( buyStrategy ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
break ;
}
}
// Get configured DCA Sell Strategies
2018-12-15 22:07:29 +01:00
for ( char c = 'A' ; c < = 'Z' ; c + + )
{
2018-05-22 10:11:50 +02:00
string sellStrategyName = SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "DEFAULT_DCA_" + c + "_sell_strategy" , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( sellStrategyName ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
StrategySummary sellStrategy = new StrategySummary ( ) ;
sellStrategy . Name = sellStrategyName ;
sellStrategy . Value = SystemHelper . TextToDouble ( SettingsHandler . GetCurrentPropertyValue ( dcaProperties , "DEFAULT_DCA_" + c + "_sell_value" , "" ) , 0 , "en-US" ) ;
this . LastRuntimeSummary . DCASellStrategies . Add ( sellStrategy ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
break ;
}
}
// Get current main currency price
Dictionary < string , Market > recentMarkets = BaseAnalyzer . GetMarketDataFromFile ( this . PTMagicConfiguration , this . Log , "Exchange" , DateTime . UtcNow , "Recent" ) ;
2018-12-15 22:07:29 +01:00
if ( recentMarkets . Keys . Count > 0 )
{
2018-05-22 10:11:50 +02:00
this . LastRuntimeSummary . MainMarketPrice = recentMarkets . First ( ) . Value . MainCurrencyPriceUSD ;
2018-12-15 22:07:29 +01:00
if ( ! this . LastRuntimeSummary . MainFiatCurrency . Equals ( "USD" , StringComparison . InvariantCultureIgnoreCase ) )
{
2018-05-22 10:11:50 +02:00
this . LastRuntimeSummary . MainMarketPrice = this . LastRuntimeSummary . MainMarketPrice * this . LastRuntimeSummary . MainFiatCurrencyExchangeRate ;
}
}
this . Log . DoLogInfo ( "Summary: Current global properties saved." ) ;
// Get current single market settings from PAIRS.PROPERTIES for each configured market
2019-03-02 09:10:33 +01:00
this . Log . DoLogInfo ( "Summary: Getting current single market properties..." ) ;
2018-12-15 22:07:29 +01:00
foreach ( string marketPair in this . MarketList )
{
2018-05-22 10:11:50 +02:00
MarketPairSummary mpSummary = new MarketPairSummary ( ) ;
mpSummary . CurrentBuyValue = defaultBuyValue ;
mpSummary . CurrentTrailingBuy = defaultTrailingBuy ;
mpSummary . CurrentSellValue = defaultSellValue ;
mpSummary . CurrentTrailingProfit = defaultTrailingProfit ;
mpSummary . IsDCAEnabled = defaultDCAEnabled ;
mpSummary . IsSOMActive = defaultSOMActive ;
mpSummary . ActiveSingleSettings = new List < SingleMarketSetting > ( ) ;
2018-12-15 22:07:29 +01:00
if ( this . MarketList . Contains ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
// Pair is allowed for trading, check for individual values
mpSummary . IsTradingEnabled = true ;
2018-12-15 22:07:29 +01:00
if ( this . TriggeredSingleMarketSettings . Count > 0 )
{
if ( this . TriggeredSingleMarketSettings . ContainsKey ( marketPair ) )
{
2018-05-22 10:11:50 +02:00
mpSummary . ActiveSingleSettings = this . TriggeredSingleMarketSettings [ marketPair ] ;
}
}
string marketPairSimple = marketPair . Replace ( this . LastRuntimeSummary . MainMarket , "" ) . Replace ( "_" , "" ) . Replace ( "-" , "" ) ;
// Get configured Buy Strategies
2018-12-15 22:07:29 +01:00
for ( char c = 'A' ; c < = 'Z' ; c + + )
{
2018-05-22 10:11:50 +02:00
string buyStrategyName = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPairSimple + "_" + c + "_buy_strategy" , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( buyStrategyName ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
StrategySummary buyStrategy = new StrategySummary ( ) ;
buyStrategy . Name = buyStrategyName ;
buyStrategy . Value = SystemHelper . TextToDouble ( SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_" + c + "_buy_value" , "" ) , 0 , "en-US" ) ;
mpSummary . BuyStrategies . Add ( buyStrategy ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
break ;
}
}
if ( mpSummary . BuyStrategies . Count = = 0 ) mpSummary . BuyStrategies = this . LastRuntimeSummary . BuyStrategies ;
// Get configured Sell Strategies
2018-12-15 22:07:29 +01:00
for ( char c = 'A' ; c < = 'Z' ; c + + )
{
2018-05-22 10:11:50 +02:00
string sellStrategyName = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPairSimple + "_" + c + "_sell_strategy" , "" ) ;
2019-02-04 01:17:38 +01:00
if ( ! String . IsNullOrEmpty ( sellStrategyName ) )
2018-12-15 22:07:29 +01:00
{
2018-05-22 10:11:50 +02:00
StrategySummary sellStrategy = new StrategySummary ( ) ;
sellStrategy . Name = sellStrategyName ;
sellStrategy . Value = SystemHelper . TextToDouble ( SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPairSimple + "_" + c + "_sell_value" , "" ) , 0 , "en-US" ) ;
mpSummary . SellStrategies . Add ( sellStrategy ) ;
2018-12-15 22:07:29 +01:00
}
else
{
2018-05-22 10:11:50 +02:00
break ;
}
}
if ( mpSummary . SellStrategies . Count = = 0 ) mpSummary . SellStrategies = this . LastRuntimeSummary . SellStrategies ;
string pairBuyValueString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPairSimple + "_buy_value" , marketPairSimple + "_A_buy_value" ) ;
double pairBuyValue = SystemHelper . TextToDouble ( pairBuyValueString , 100 , "en-US" ) ;
if ( pairBuyValue < 100 ) mpSummary . CurrentBuyValue = pairBuyValue ;
string pairTrailingBuyString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_trailing_buy" , marketPairSimple + "_trailing_buy" ) ;
double pairTrailingBuy = SystemHelper . TextToDouble ( pairTrailingBuyString , - 1 , "en-US" ) ;
if ( pairTrailingBuy > - 1 ) mpSummary . CurrentTrailingBuy = pairTrailingBuy ;
string pairSellValueString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_sell_value" , marketPairSimple + "_A_sell_value" ) ;
double pairSellValue = SystemHelper . TextToDouble ( pairSellValueString , 0 , "en-US" ) ;
if ( pairSellValue > - 1 ) mpSummary . CurrentSellValue = pairSellValue ;
string pairTrailingProfitString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_trailing_profit" , marketPairSimple + "_trailing_profit" ) ;
double pairTrailingProfit = SystemHelper . TextToDouble ( pairTrailingProfitString , 0 , "en-US" ) ;
if ( pairTrailingProfit > - 1 ) mpSummary . CurrentTrailingProfit = pairTrailingProfit ;
string pairTradingEnabledString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_trading_enabled" , marketPairSimple + "_trading_enabled" ) ;
mpSummary . IsTradingEnabled = ( pairTradingEnabledString . Equals ( "false" , StringComparison . InvariantCultureIgnoreCase ) ) ? false : true ;
string pairDCAEnabledString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_DCA_enabled" , marketPairSimple + "_DCA_enabled" ) ;
mpSummary . IsDCAEnabled = ( pairDCAEnabledString . Equals ( "false" , StringComparison . InvariantCultureIgnoreCase ) ) ? false : defaultDCAEnabled ;
string pairSOMActiveString = SettingsHandler . GetCurrentPropertyValue ( pairsProperties , marketPair + "_sell_only_mode" , marketPairSimple + "_sell_only_mode_enabled" ) ;
mpSummary . IsSOMActive = ( pairSOMActiveString . Equals ( "true" , StringComparison . InvariantCultureIgnoreCase ) ) ? true : false ;
}
// Get market trend values for each market pair
2018-12-15 22:07:29 +01:00
foreach ( string marketTrendName in this . SingleMarketTrendChanges . Keys )
{
if ( this . SingleMarketTrendChanges . ContainsKey ( marketTrendName ) )
{
2018-05-22 10:11:50 +02:00
MarketTrendChange mtc = this . SingleMarketTrendChanges [ marketTrendName ] . Find ( m = > m . Market = = marketPair ) ;
2018-12-15 22:07:29 +01:00
if ( mtc ! = null )
{
2018-05-22 10:11:50 +02:00
double marketTrendChange = mtc . TrendChange ;
mpSummary . MarketTrendChanges . Add ( marketTrendName , marketTrendChange ) ;
mpSummary . LatestPrice = mtc . LastPrice ;
mpSummary . Latest24hVolume = mtc . Volume24h ;
}
}
}
2019-03-09 09:38:46 +01:00
this . LastRuntimeSummary . MarketSummary . Add ( marketPair , mpSummary ) ;
2018-05-22 10:11:50 +02:00
}
this . Log . DoLogInfo ( "Summary: Current single market properties saved." ) ;
string serialziedJson = JsonConvert . SerializeObject ( this . LastRuntimeSummary ) ;
// Save the summary JSON file
2018-12-15 22:07:29 +01:00
try
{
2018-05-22 10:11:50 +02:00
FileHelper . WriteTextToFile ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar , "LastRuntimeSummary.json" , serialziedJson ) ;
this . Log . DoLogInfo ( "Summary: LastRuntimeSummary.json saved." ) ;
2018-12-15 22:07:29 +01:00
}
catch ( Exception ex )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogCritical ( "Exception while writing LastRuntimeSummary.json" , ex ) ;
2018-12-15 22:07:29 +01:00
try
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "Summary: Retrying one more time to save LastRuntimeSummary.json." ) ;
FileHelper . WriteTextToFile ( Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathData + Path . DirectorySeparatorChar , "LastRuntimeSummary.json" , serialziedJson ) ;
this . Log . DoLogInfo ( "Summary: LastRuntimeSummary.json saved." ) ;
2018-12-15 22:07:29 +01:00
}
catch ( Exception ex2 )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogCritical ( "Nope, another Exception while writing LastRuntimeSummary.json" , ex2 ) ;
}
}
string logsPath = Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar + Constants . PTMagicPathLogs + Path . DirectorySeparatorChar ;
2018-12-15 22:07:29 +01:00
if ( Directory . Exists ( logsPath ) )
{
2018-05-22 10:11:50 +02:00
FileHelper . CleanupFiles ( logsPath , 24 * 3 ) ;
this . Log . DoLogInfo ( "Cleaned up logfiles." ) ;
}
this . TotalElapsedSeconds + = elapsedSeconds ;
this . Log . DoLogInfo ( "##########################################################" ) ;
this . Log . DoLogInfo ( "#******************* RAID SUMMARY ********************#" ) ;
this . Log . DoLogInfo ( "+ PT Magic Version: " + this . LastRuntimeSummary . Version ) ;
2018-12-15 22:07:29 +01:00
if ( ! SystemHelper . IsRecentVersion ( this . LastRuntimeSummary . Version , this . LatestVersion ) )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogWarn ( "+ Your version is out of date! The most recent version is " + this . LatestVersion ) ;
}
this . Log . DoLogInfo ( "+ Instance name: " + PTMagicConfiguration . GeneralSettings . Application . InstanceName ) ;
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 ( "+ Markets with active single market settings: " + this . TriggeredSingleMarketSettings . Count . ToString ( ) ) ;
2018-12-15 22:07:29 +01:00
foreach ( string activeSMS in this . SingleMarketSettingsCount . Keys )
{
2018-05-22 10:11:50 +02:00
this . Log . DoLogInfo ( "+ " + activeSMS + ": " + this . SingleMarketSettingsCount [ activeSMS ] . ToString ( ) ) ;
}
this . Log . DoLogInfo ( "+ " + this . TotalElapsedSeconds . ToString ( ) + " Magicbots killed in " + this . RunCount . ToString ( ) + " raids on Cryptodragon's Lair " + this . PTMagicConfiguration . AnalyzerSettings . MarketAnalyzer . IntervalMinutes . ToString ( ) + "." ) ;
this . Log . DoLogInfo ( "" ) ;
this . Log . DoLogInfo ( "DO NOT CLOSE THIS WINDOW! THIS IS THE BOT THAT ANALYZES TRENDS AND CHANGES SETTINGS!" ) ;
this . Log . DoLogInfo ( "" ) ;
this . Log . DoLogInfo ( "#********************************************************#" ) ;
this . Log . DoLogInfo ( "##########################################################" ) ;
this . Log . DoLogInfo ( "" ) ;
}
2018-12-15 22:07:29 +01:00
private void Cleanup ( )
{
2018-05-22 10:11:50 +02:00
this . GlobalSettingWritten = false ;
this . SingleMarketSettingWritten = false ;
this . EnforceSettingsReapply = false ;
this . PairsLines = null ;
this . DCALines = null ;
this . IndicatorsLines = null ;
this . SingleMarketTrendChanges = new Dictionary < string , List < MarketTrendChange > > ( ) ;
this . GlobalMarketTrendChanges = new Dictionary < string , List < MarketTrendChange > > ( ) ;
this . AverageMarketTrendChanges = new Dictionary < string , double > ( ) ;
this . SingleMarketSettingsCount = new Dictionary < string , int > ( ) ;
this . TriggeredSingleMarketSettings = new Dictionary < string , List < SingleMarketSetting > > ( ) ;
this . ExchangeMarketList = null ;
this . MarketList = new List < string > ( ) ;
this . LastRuntimeSummary = null ;
}
#endregion
}
}