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()