From 2db230ac2356e3bb57e0aacf260bd877e67de9bf Mon Sep 17 00:00:00 2001 From: djbadders <34887832+djbadders@users.noreply.github.com> Date: Sun, 13 Oct 2019 16:45:32 +0100 Subject: [PATCH 1/3] Cleaned up and checked compatability with PT 2.4 --- Core/ProfitTrailer/SettingsAPI.cs | 111 +--------------------------- Core/ProfitTrailer/SettingsFiles.cs | 8 -- 2 files changed, 1 insertion(+), 118 deletions(-) diff --git a/Core/ProfitTrailer/SettingsAPI.cs b/Core/ProfitTrailer/SettingsAPI.cs index 4aafa54..dea03b0 100644 --- a/Core/ProfitTrailer/SettingsAPI.cs +++ b/Core/ProfitTrailer/SettingsAPI.cs @@ -1,115 +1,17 @@ using System; using System.Collections.Generic; -using System.Linq; using System.IO; using System.Net; using System.Net.Security; -using System.Security.Cryptography.X509Certificates; -using System.Net.Http; using System.Text; -using System.Threading.Tasks; using Core.Main; using Core.Helper; -using Core.Main.DataObjects.PTMagicData; -using Newtonsoft.Json; namespace Core.ProfitTrailer { public static class SettingsAPI { - public static void GetInitialProfitTrailerSettings(PTMagicConfiguration systemConfiguration) - { - string html = ""; - string url = systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL + "api/data?token=" + systemConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken; - - try - { - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); - request.AutomaticDecompression = DecompressionMethods.GZip; - - WebResponse response = request.GetResponse(); - Stream dataStream = response.GetResponseStream(); - StreamReader reader = new StreamReader(dataStream); - html = reader.ReadToEnd(); - reader.Close(); - response.Close(); - - } - catch (System.Exception) - { - throw; - } - - dynamic json = JsonConvert.DeserializeObject(html); - - systemConfiguration.GeneralSettings.Application.Exchange = json.exchange; - systemConfiguration.GeneralSettings.Application.TimezoneOffset = json.timeZoneOffset; - systemConfiguration.GeneralSettings.Application.StartBalance = json.startBalance; - systemConfiguration.GeneralSettings.Application.MainFiatCurrency = json.settings.currency; - } - public static List GetPropertyLinesFromAPI(string ptFileName, PTMagicConfiguration systemConfiguration, LogHelper log) - { - List result = null; - - try - { - ServicePointManager.Expect100Continue = true; - ServicePointManager.DefaultConnectionLimit = 9999; - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; - ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(CertificateHelper.AllwaysGoodCertificate); - - HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL + "settingsapi/settings/load"); - httpWebRequest.ContentType = "application/x-www-form-urlencoded"; - httpWebRequest.Method = "POST"; - - // PT is using ordinary POST data, not JSON - string query = "fileName=" + ptFileName + "&configName=" + systemConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName + "&license=" + systemConfiguration.GeneralSettings.Application.ProfitTrailerLicense; - byte[] formData = Encoding.ASCII.GetBytes(query); - httpWebRequest.ContentLength = formData.Length; - - using (Stream stream = httpWebRequest.GetRequestStream()) - { - stream.Write(formData, 0, formData.Length); - } - - //using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { - // string json = JsonConvert.SerializeObject(new { - // fileName = ptFileName, - // configName = systemConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName, - // license = systemConfiguration.GeneralSettings.Application.ProfitTrailerLicense - // }); - - // streamWriter.Write(json); - //} - - HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); - using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - string jsonResult = streamReader.ReadToEnd(); - result = JsonConvert.DeserializeObject>(jsonResult); - } - } - catch (WebException ex) - { - // Manual error handling as PT doesn't seem to provide a proper error response... - if (ex.Message.IndexOf("401") > -1) - { - log.DoLogError("Loading " + ptFileName + ".properties failed for setting '" + systemConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName + "': Unauthorized! The specified Profit Trailer license key '" + systemConfiguration.GetProfitTrailerLicenseKeyMasked() + "' is invalid!"); - } - else - { - log.DoLogCritical("Loading " + ptFileName + ".properties failed for setting '" + systemConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName + "': " + ex.Message, ex); - } - - } - catch (Exception ex) - { - log.DoLogCritical("Loading " + ptFileName + ".properties failed for setting '" + systemConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName + "': " + ex.Message, ex); - } - - return result; - } - + // Save config back to Profit Trailer public static void SendPropertyLinesToAPI(List pairsLines, List dcaLines, List indicatorsLines, PTMagicConfiguration systemConfiguration, LogHelper log) { int retryCount = 0; @@ -148,17 +50,6 @@ namespace Core.ProfitTrailer } log.DoLogDebug("Built POST request for Properties"); - //using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { - // string json = JsonConvert.SerializeObject(new { - // fileName = ptFileName, - // configName = systemConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName, - // license = systemConfiguration.GeneralSettings.Application.ProfitTrailerLicense, - // saveData = propertiesString - // }); - - // streamWriter.Write(json); - //} - log.DoLogInfo("Sending Properties..."); HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); log.DoLogInfo("Properties sent!"); diff --git a/Core/ProfitTrailer/SettingsFiles.cs b/Core/ProfitTrailer/SettingsFiles.cs index 9b68e7c..8b7eebc 100644 --- a/Core/ProfitTrailer/SettingsFiles.cs +++ b/Core/ProfitTrailer/SettingsFiles.cs @@ -2,17 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.IO; -using System.Security.Permissions; -using System.Net; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; using Core.Main; using Core.Helper; using Core.Main.DataObjects.PTMagicData; -using Newtonsoft.Json; namespace Core.ProfitTrailer { From 7141b0d2cd124f334bfa1f09beb109bf853e3c56 Mon Sep 17 00:00:00 2001 From: djbadders <34887832+djbadders@users.noreply.github.com> Date: Sun, 13 Oct 2019 18:19:26 +0100 Subject: [PATCH 2/3] Updated to use PT API v2 --- Core/DataObjects/ProfitTrailerData.cs | 95 +++++++++++++-------------- Monitor/_Internal/BasePageModel.cs | 13 +--- 2 files changed, 46 insertions(+), 62 deletions(-) diff --git a/Core/DataObjects/ProfitTrailerData.cs b/Core/DataObjects/ProfitTrailerData.cs index 9e4551a..fb009a6 100644 --- a/Core/DataObjects/ProfitTrailerData.cs +++ b/Core/DataObjects/ProfitTrailerData.cs @@ -4,12 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; -using System.Net.Http; -using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Core.Main.DataObjects.PTMagicData; @@ -31,48 +26,21 @@ namespace Core.Main.DataObjects { _systemConfiguration = systemConfiguration; - string html = ""; - string url = systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL + "api/data?token=" + systemConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken; - - // Get the data from PT - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); - request.AutomaticDecompression = DecompressionMethods.GZip; - request.KeepAlive = true; - - WebResponse response = request.GetResponse(); - Stream dataStream = response.GetResponseStream(); - StreamReader reader = new StreamReader(dataStream); - html = reader.ReadToEnd(); - reader.Close(); - response.Close(); - - // Parse the JSON and build the data sets - dynamic rawPTData = JObject.Parse(html); - Parallel.Invoke(() => - { - _summary = BuildSummaryData(rawPTData); + { + _summary = BuildSummaryData(GetDataFromProfitTrailer("api/v2/data/misc")); }, () => { - if (rawPTData.sellLogData != null) - { - this.BuildSellLogData(rawPTData.sellLogData, _systemConfiguration); - } + this.BuildSellLogData(GetDataFromProfitTrailer("/api/v2/data/sales")); }, () => { - if (rawPTData.bbBuyLogData != null) - { - this.BuildBuyLogData(rawPTData.bbBuyLogData); - } + this.BuildBuyLogData(GetDataFromProfitTrailer("/api/v2/data/pbl", true)); }, () => { - if (rawPTData.dcaLogData != null) - { - this.BuildDCALogData(rawPTData.dcaLogData, rawPTData.gainLogData, rawPTData.pendingLogData, rawPTData.watchModeLogData, _systemConfiguration); - } + this.BuildDCALogData(GetDataFromProfitTrailer("/api/v2/data/dca", true), GetDataFromProfitTrailer("/api/v2/data/pairs", true), GetDataFromProfitTrailer("/api/v2/data/pending", true), GetDataFromProfitTrailer("/api/v2/data/watchmode", true)); }); // Convert local offset time to UTC @@ -182,8 +150,6 @@ namespace Core.Main.DataObjects (this.Summary.DustValue); } - - public double GetSnapshotBalance(DateTime snapshotDateTime) { double result = _systemConfiguration.GeneralSettings.Application.StartBalance; @@ -197,6 +163,38 @@ namespace Core.Main.DataObjects return result; } + private dynamic GetDataFromProfitTrailer(string callPath, bool arrayReturned = false) + { + string rawBody = ""; + string url = string.Format("{0}{1}?token={2}", _systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL, callPath, _systemConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken); + + // Get the data from PT + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.AutomaticDecompression = DecompressionMethods.GZip; + request.KeepAlive = true; + + WebResponse response = request.GetResponse(); + + using (Stream dataStream = response.GetResponseStream()) + { + StreamReader reader = new StreamReader(dataStream); + rawBody = reader.ReadToEnd(); + reader.Close(); + } + + response.Close(); + + // Parse the JSON and build the data sets + if (!arrayReturned) + { + return JObject.Parse(rawBody); + } + else + { + return JArray.Parse(rawBody); + } + } + private SummaryData BuildSummaryData(dynamic PTData) { return new SummaryData() @@ -210,9 +208,9 @@ namespace Core.Main.DataObjects }; } - private void BuildSellLogData(dynamic rawSellLogData, PTMagicConfiguration systemConfiguration) + private void BuildSellLogData(dynamic rawSellLogData) { - foreach (var rsld in rawSellLogData) + foreach (var rsld in rawSellLogData.data) { SellLogData sellLogData = new SellLogData(); sellLogData.SoldAmount = rsld.soldAmount; @@ -236,7 +234,7 @@ namespace Core.Main.DataObjects DateTimeOffset ptSoldDate = DateTimeOffset.Parse(dtDateTime.Year.ToString() + "-" + dtDateTime.Month.ToString("00") + "-" + dtDateTime.Day.ToString("00") + "T" + dtDateTime.Hour.ToString("00") + ":" + dtDateTime.Minute.ToString("00") + ":" + dtDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); // Convert UTC sales time to local offset time - TimeSpan offsetTimeSpan = TimeSpan.Parse(systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); + TimeSpan offsetTimeSpan = TimeSpan.Parse(_systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); ptSoldDate = ptSoldDate.ToOffset(offsetTimeSpan); sellLogData.SoldDate = ptSoldDate.DateTime; @@ -245,7 +243,7 @@ namespace Core.Main.DataObjects } } - private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData, PTMagicConfiguration systemConfiguration) + private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData) { foreach (var rdld in rawDCALogData) { @@ -327,7 +325,7 @@ namespace Core.Main.DataObjects DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rdldDateTime.Year.ToString() + "-" + rdldDateTime.Month.ToString("00") + "-" + rdldDateTime.Day.ToString("00") + "T" + rdldDateTime.Hour.ToString("00") + ":" + rdldDateTime.Minute.ToString("00") + ":" + rdldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); // Convert UTC bought time to local offset time - TimeSpan offsetTimeSpan = TimeSpan.Parse(systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); + TimeSpan offsetTimeSpan = TimeSpan.Parse(_systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(offsetTimeSpan); dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime; @@ -387,7 +385,7 @@ namespace Core.Main.DataObjects DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rpldDateTime.Year.ToString() + "-" + rpldDateTime.Month.ToString("00") + "-" + rpldDateTime.Day.ToString("00") + "T" + rpldDateTime.Hour.ToString("00") + ":" + rpldDateTime.Minute.ToString("00") + ":" + rpldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); // Convert UTC bought time to local offset time - TimeSpan offsetTimeSpan = TimeSpan.Parse(systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); + TimeSpan offsetTimeSpan = TimeSpan.Parse(_systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(offsetTimeSpan); dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime; @@ -447,7 +445,7 @@ namespace Core.Main.DataObjects DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rpldDateTime.Year.ToString() + "-" + rpldDateTime.Month.ToString("00") + "-" + rpldDateTime.Day.ToString("00") + "T" + rpldDateTime.Hour.ToString("00") + ":" + rpldDateTime.Minute.ToString("00") + ":" + rpldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); // Convert UTC bought time to local offset time - TimeSpan offsetTimeSpan = TimeSpan.Parse(systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); + TimeSpan offsetTimeSpan = TimeSpan.Parse(_systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(offsetTimeSpan); dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime; @@ -507,7 +505,7 @@ namespace Core.Main.DataObjects DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rpldDateTime.Year.ToString() + "-" + rpldDateTime.Month.ToString("00") + "-" + rpldDateTime.Day.ToString("00") + "T" + rpldDateTime.Hour.ToString("00") + ":" + rpldDateTime.Minute.ToString("00") + ":" + rpldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); // Convert UTC bought time to local offset time - TimeSpan offsetTimeSpan = TimeSpan.Parse(systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); + TimeSpan offsetTimeSpan = TimeSpan.Parse(_systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(offsetTimeSpan); dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime; @@ -519,9 +517,6 @@ namespace Core.Main.DataObjects _dcaLog.Add(dcaLogData); } - - - } private void BuildBuyLogData(dynamic rawBuyLogData) diff --git a/Monitor/_Internal/BasePageModel.cs b/Monitor/_Internal/BasePageModel.cs index 7557f37..14b5cbf 100644 --- a/Monitor/_Internal/BasePageModel.cs +++ b/Monitor/_Internal/BasePageModel.cs @@ -1,7 +1,6 @@ using System; using System.IO; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -10,8 +9,6 @@ using Core.Main; using Core.Helper; using Core.Main.DataObjects.PTMagicData; using Core.MarketAnalyzer; -using Core.ProfitTrailer; -using Microsoft.Extensions.Primitives; using System.Diagnostics; namespace Monitor._Internal @@ -22,7 +19,6 @@ namespace Monitor._Internal public string PTMagicBasePath = ""; public string PTMagicMonitorBasePath = ""; public PTMagicConfiguration PTMagicConfiguration = null; - public Summary Summary { get; set; } = new Summary(); public LogHelper Log = null; public string LatestVersion = ""; @@ -58,14 +54,7 @@ namespace Monitor._Internal PTMagicBasePath += Path.DirectorySeparatorChar; } - try - { - PTMagicConfiguration = new PTMagicConfiguration(PTMagicBasePath); - } - catch (Exception ex) - { - throw ex; - } + PTMagicConfiguration = new PTMagicConfiguration(PTMagicBasePath); IServiceProvider logProvider = ServiceHelper.BuildLoggerService(PTMagicBasePath); Log = logProvider.GetRequiredService(); From 377e443f6263797486076918dbc23bca41624233 Mon Sep 17 00:00:00 2001 From: djbadders <34887832+djbadders@users.noreply.github.com> Date: Sun, 13 Oct 2019 21:08:48 +0100 Subject: [PATCH 3/3] Performance optimised with caching and async loads --- Core/DataObjects/ProfitTrailerData.cs | 120 ++++++++++++++----- Monitor/Pages/BagAnalyzer.cshtml.cs | 2 +- Monitor/Pages/BuyAnalyzer.cshtml.cs | 2 +- Monitor/Pages/DCACalculator.cshtml.cs | 2 +- Monitor/Pages/SalesAnalyzer.cshtml.cs | 2 +- Monitor/Pages/_get/BagDetails.cshtml.cs | 2 +- Monitor/Pages/_get/BagList.cshtml.cs | 2 +- Monitor/Pages/_get/BuyList.cshtml.cs | 2 +- Monitor/Pages/_get/DashboardBottom.cshtml.cs | 2 +- Monitor/Pages/_get/DashboardTop.cshtml | 6 +- Monitor/Pages/_get/DashboardTop.cshtml.cs | 2 +- Monitor/Pages/_get/SalesList.cshtml.cs | 2 +- Monitor/_Internal/BasePageModel.cs | 20 ++++ Monitor/_Internal/BasePageModelSecure.cs | 11 -- 14 files changed, 123 insertions(+), 54 deletions(-) diff --git a/Core/DataObjects/ProfitTrailerData.cs b/Core/DataObjects/ProfitTrailerData.cs index fb009a6..99a206e 100644 --- a/Core/DataObjects/ProfitTrailerData.cs +++ b/Core/DataObjects/ProfitTrailerData.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Threading.Tasks; +using System.Diagnostics; using Newtonsoft.Json.Linq; using Core.Main.DataObjects.PTMagicData; @@ -21,28 +22,13 @@ namespace Core.Main.DataObjects private PTMagicConfiguration _systemConfiguration = null; private TransactionData _transactionData = null; private DateTimeOffset _dateTimeNow = Constants.confMinDate; + private DateTime _buyLogRefresh = DateTime.UtcNow, _sellLogRefresh = DateTime.UtcNow, _dcaLogRefresh = DateTime.UtcNow, _summaryRefresh = DateTime.UtcNow; + private volatile object _buyLock = new object(), _sellLock = new object(), _dcaLock = new object(), _summaryLock = new object(); public ProfitTrailerData(PTMagicConfiguration systemConfiguration) { _systemConfiguration = systemConfiguration; - Parallel.Invoke(() => - { - _summary = BuildSummaryData(GetDataFromProfitTrailer("api/v2/data/misc")); - }, - () => - { - this.BuildSellLogData(GetDataFromProfitTrailer("/api/v2/data/sales")); - }, - () => - { - this.BuildBuyLogData(GetDataFromProfitTrailer("/api/v2/data/pbl", true)); - }, - () => - { - this.BuildDCALogData(GetDataFromProfitTrailer("/api/v2/data/dca", true), GetDataFromProfitTrailer("/api/v2/data/pairs", true), GetDataFromProfitTrailer("/api/v2/data/pending", true), GetDataFromProfitTrailer("/api/v2/data/watchmode", true)); - }); - // Convert local offset time to UTC TimeSpan offsetTimeSpan = TimeSpan.Parse(systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); _dateTimeNow = DateTimeOffset.UtcNow.ToOffset(offsetTimeSpan); @@ -52,6 +38,19 @@ namespace Core.Main.DataObjects { get { + if (_summary == null || (DateTime.UtcNow > _summaryRefresh)) + { + lock (_summaryLock) + { + // Thread double locking + if (_summary == null || (DateTime.UtcNow > _summaryRefresh)) + { + _summary = BuildSummaryData(GetDataFromProfitTrailer("api/v2/data/misc")); + _summaryRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1); + } + } + } + return _summary; } } @@ -59,6 +58,20 @@ namespace Core.Main.DataObjects { get { + if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh)) + { + lock (_sellLock) + { + // Thread double locking + if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh)) + { + _sellLog.Clear(); + this.BuildSellLogData(GetDataFromProfitTrailer("/api/v2/data/sales")); + _sellLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1); + } + } + } + return _sellLog; } } @@ -67,7 +80,7 @@ namespace Core.Main.DataObjects { get { - return _sellLog.FindAll(sl => sl.SoldDate.Date == _dateTimeNow.DateTime.Date); + return SellLog.FindAll(sl => sl.SoldDate.Date == _dateTimeNow.DateTime.Date); } } @@ -75,7 +88,7 @@ namespace Core.Main.DataObjects { get { - return _sellLog.FindAll(sl => sl.SoldDate.Date == _dateTimeNow.DateTime.AddDays(-1).Date); + return SellLog.FindAll(sl => sl.SoldDate.Date == _dateTimeNow.DateTime.AddDays(-1).Date); } } @@ -83,7 +96,7 @@ namespace Core.Main.DataObjects { get { - return _sellLog.FindAll(sl => sl.SoldDate.Date >= _dateTimeNow.DateTime.AddDays(-7).Date); + return SellLog.FindAll(sl => sl.SoldDate.Date >= _dateTimeNow.DateTime.AddDays(-7).Date); } } @@ -91,7 +104,7 @@ namespace Core.Main.DataObjects { get { - return _sellLog.FindAll(sl => sl.SoldDate.Date >= _dateTimeNow.DateTime.AddDays(-30).Date); + return SellLog.FindAll(sl => sl.SoldDate.Date >= _dateTimeNow.DateTime.AddDays(-30).Date); } } @@ -99,6 +112,40 @@ namespace Core.Main.DataObjects { get { + if (_dcaLog == null || (DateTime.UtcNow > _dcaLogRefresh)) + { + lock (_dcaLock) + { + // Thread double locking + if (_dcaLog == null || (DateTime.UtcNow > _dcaLogRefresh)) + { + dynamic dcaData = null, pairsData = null, pendingData = null, watchData = null; + _dcaLog.Clear(); + + Parallel.Invoke(() => + { + dcaData = GetDataFromProfitTrailer("/api/v2/data/dca", true); + }, + () => + { + pairsData = GetDataFromProfitTrailer("/api/v2/data/pairs", true); + }, + () => + { + pendingData = GetDataFromProfitTrailer("/api/v2/data/pending", true); + + }, + () => + { + watchData = GetDataFromProfitTrailer("/api/v2/data/watchmode", true); + }); + + this.BuildDCALogData(dcaData, pairsData, pendingData, watchData); + _dcaLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.BagAnalyzerRefreshSeconds - 1); + } + } + } + return _dcaLog; } } @@ -107,6 +154,20 @@ namespace Core.Main.DataObjects { get { + if (_buyLog == null || (DateTime.UtcNow > _buyLogRefresh)) + { + lock (_buyLock) + { + // Thread double locking + if (_buyLog == null || (DateTime.UtcNow > _buyLogRefresh)) + { + _buyLog.Clear(); + this.BuildBuyLogData(GetDataFromProfitTrailer("/api/v2/data/pbl", true)); + _buyLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.BuyAnalyzerRefreshSeconds - 1); + } + } + } + return _buyLog; } } @@ -122,31 +183,31 @@ namespace Core.Main.DataObjects public double GetCurrentBalance() { - return + return (this.Summary.Balance + this.Summary.PairsValue + this.Summary.DCAValue + this.Summary.PendingValue + this.Summary.DustValue); } - public double GetPairsBalance() + public double GetPairsBalance() { - return + return (this.Summary.PairsValue); } - public double GetDCABalance() + public double GetDCABalance() { - return + return (this.Summary.DCAValue); } - public double GetPendingBalance() + public double GetPendingBalance() { - return + return (this.Summary.PendingValue); } public double GetDustBalance() { - return + return (this.Summary.DustValue); } @@ -169,6 +230,7 @@ namespace Core.Main.DataObjects string url = string.Format("{0}{1}?token={2}", _systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL, callPath, _systemConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken); // Get the data from PT + Debug.WriteLine(String.Format("{0} - Calling '{1}'", DateTime.UtcNow, url)); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.AutomaticDecompression = DecompressionMethods.GZip; request.KeepAlive = true; diff --git a/Monitor/Pages/BagAnalyzer.cshtml.cs b/Monitor/Pages/BagAnalyzer.cshtml.cs index d45df15..e764992 100644 --- a/Monitor/Pages/BagAnalyzer.cshtml.cs +++ b/Monitor/Pages/BagAnalyzer.cshtml.cs @@ -21,7 +21,7 @@ namespace Monitor.Pages private void BindData() { - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; } } } diff --git a/Monitor/Pages/BuyAnalyzer.cshtml.cs b/Monitor/Pages/BuyAnalyzer.cshtml.cs index 6b3eda4..cf52a2b 100644 --- a/Monitor/Pages/BuyAnalyzer.cshtml.cs +++ b/Monitor/Pages/BuyAnalyzer.cshtml.cs @@ -21,7 +21,7 @@ namespace Monitor.Pages private void BindData() { - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; } } } diff --git a/Monitor/Pages/DCACalculator.cshtml.cs b/Monitor/Pages/DCACalculator.cshtml.cs index 9292df4..726e380 100644 --- a/Monitor/Pages/DCACalculator.cshtml.cs +++ b/Monitor/Pages/DCACalculator.cshtml.cs @@ -19,7 +19,7 @@ namespace Monitor.Pages private void BindData() { - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; } } } diff --git a/Monitor/Pages/SalesAnalyzer.cshtml.cs b/Monitor/Pages/SalesAnalyzer.cshtml.cs index 4e17555..dd8f41a 100644 --- a/Monitor/Pages/SalesAnalyzer.cshtml.cs +++ b/Monitor/Pages/SalesAnalyzer.cshtml.cs @@ -30,7 +30,7 @@ namespace Monitor.Pages private void BindData() { - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; // Convert local offset time to UTC TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); diff --git a/Monitor/Pages/_get/BagDetails.cshtml.cs b/Monitor/Pages/_get/BagDetails.cshtml.cs index cad873d..b6e651b 100644 --- a/Monitor/Pages/_get/BagDetails.cshtml.cs +++ b/Monitor/Pages/_get/BagDetails.cshtml.cs @@ -24,7 +24,7 @@ namespace Monitor.Pages { private void BindData() { DCAMarket = GetStringParameter("m", ""); - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; DCALogData = PTData.DCALog.Find(d => d.Market == DCAMarket); diff --git a/Monitor/Pages/_get/BagList.cshtml.cs b/Monitor/Pages/_get/BagList.cshtml.cs index d4f7e2b..2bd4bf9 100644 --- a/Monitor/Pages/_get/BagList.cshtml.cs +++ b/Monitor/Pages/_get/BagList.cshtml.cs @@ -23,7 +23,7 @@ namespace Monitor.Pages { SortFieldId = GetStringParameter("s", "ProfitPercent"); SortDirection = GetStringParameter("d", "DESC"); - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; } } } diff --git a/Monitor/Pages/_get/BuyList.cshtml.cs b/Monitor/Pages/_get/BuyList.cshtml.cs index 431b28d..5ab9180 100644 --- a/Monitor/Pages/_get/BuyList.cshtml.cs +++ b/Monitor/Pages/_get/BuyList.cshtml.cs @@ -23,7 +23,7 @@ namespace Monitor.Pages { SortFieldId = GetStringParameter("s", "ProfitPercent"); SortDirection = GetStringParameter("d", "DESC"); - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; } } } diff --git a/Monitor/Pages/_get/DashboardBottom.cshtml.cs b/Monitor/Pages/_get/DashboardBottom.cshtml.cs index 0fc1208..56c8386 100644 --- a/Monitor/Pages/_get/DashboardBottom.cshtml.cs +++ b/Monitor/Pages/_get/DashboardBottom.cshtml.cs @@ -28,7 +28,7 @@ namespace Monitor.Pages { } private void BindData() { - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; // Cleanup temp files FileHelper.CleanupFilesMinutes(PTMagicMonitorBasePath + "wwwroot" + System.IO.Path.DirectorySeparatorChar + "assets" + System.IO.Path.DirectorySeparatorChar + "tmp" + System.IO.Path.DirectorySeparatorChar, 5); diff --git a/Monitor/Pages/_get/DashboardTop.cshtml b/Monitor/Pages/_get/DashboardTop.cshtml index 5b2f611..bc1377f 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml +++ b/Monitor/Pages/_get/DashboardTop.cshtml @@ -51,9 +51,7 @@ string buyStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Model.Summary, buyLogEntry.BuyStrategies, buyLogEntry.BuyStrategy, isBuyStrategyTrue, isTrailingBuyActive); if (!Core.ProfitTrailer.StrategyHelper.IsValidStrategy(buyStrategyText, true)) { buyDisabled = true; - } - - buyLogEntry.PercChange = @buyLogEntry.PercChange * 100; + } @if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0) { @@ -61,7 +59,7 @@ } else { @buyLogEntry.Market } - @buyLogEntry.PercChange.ToString("#,#0.00")% + @string.Format("{0}%", (buyLogEntry.PercChange * 100).ToString("#,#0.00")) @if (buyDisabled) { @Html.Raw(buyStrategyText) } else { diff --git a/Monitor/Pages/_get/DashboardTop.cshtml.cs b/Monitor/Pages/_get/DashboardTop.cshtml.cs index d13dfe8..9c4824e 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml.cs +++ b/Monitor/Pages/_get/DashboardTop.cshtml.cs @@ -20,7 +20,7 @@ namespace Monitor.Pages { } private void BindData() { - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; // Convert local offset time to UTC TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); diff --git a/Monitor/Pages/_get/SalesList.cshtml.cs b/Monitor/Pages/_get/SalesList.cshtml.cs index e8333cf..12ab483 100644 --- a/Monitor/Pages/_get/SalesList.cshtml.cs +++ b/Monitor/Pages/_get/SalesList.cshtml.cs @@ -29,7 +29,7 @@ namespace Monitor.Pages { salesDateString = GetStringParameter("d", ""); salesMonthString = GetStringParameter("m", ""); - PTData = new ProfitTrailerData(PTMagicConfiguration); + PTData = this.PtDataObject; if (!salesDateString.Equals("")) { SalesDate = SystemHelper.TextToDateTime(salesDateString, Constants.confMinDate); diff --git a/Monitor/_Internal/BasePageModel.cs b/Monitor/_Internal/BasePageModel.cs index 14b5cbf..b3ee870 100644 --- a/Monitor/_Internal/BasePageModel.cs +++ b/Monitor/_Internal/BasePageModel.cs @@ -10,6 +10,7 @@ using Core.Helper; using Core.Main.DataObjects.PTMagicData; using Core.MarketAnalyzer; using System.Diagnostics; +using Core.Main.DataObjects; namespace Monitor._Internal { @@ -28,6 +29,25 @@ namespace Monitor._Internal public string NotifyType = ""; public string MainFiatCurrencySymbol = "$"; + private volatile object _ptDataLock = new object(); + private static ProfitTrailerData _ptData = null; + + // Profit Trailer data accessor object + public ProfitTrailerData PtDataObject + { + get + { + if (_ptData == null) + { + lock (_ptDataLock) + { + _ptData = new ProfitTrailerData(PTMagicConfiguration); + } + } + + return _ptData; + } + } public void PreInit() { diff --git a/Monitor/_Internal/BasePageModelSecure.cs b/Monitor/_Internal/BasePageModelSecure.cs index a1fc1c4..12ff0ee 100644 --- a/Monitor/_Internal/BasePageModelSecure.cs +++ b/Monitor/_Internal/BasePageModelSecure.cs @@ -1,21 +1,10 @@ using System; -using System.IO; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Core.Main; using Core.Helper; -using Core.Main.DataObjects.PTMagicData; -using Core.MarketAnalyzer; -using Core.ProfitTrailer; -using Microsoft.Extensions.Primitives; namespace Monitor._Internal { - public class BasePageModelSecure : BasePageModel { public void Init()