diff --git a/Core/DataObjects/PTMagicData.cs b/Core/DataObjects/PTMagicData.cs index 3e72643..0aebdc2 100644 --- a/Core/DataObjects/PTMagicData.cs +++ b/Core/DataObjects/PTMagicData.cs @@ -440,6 +440,10 @@ namespace Core.Main.DataObjects.PTMagicData public double FundingThisMonth { get; set; } public double FundingLastMonth { get; set; } public double FundingTotal { get; set; } + public double TotalFundingPerc { get; set; } + public double TotalFundingPercYesterday { get; set; } + public double TotalFundingPercWeek { get; set; } + public double TotalFundingPercToday { get; set; } } public class DailyPNLData @@ -448,6 +452,13 @@ namespace Core.Main.DataObjects.PTMagicData public double CumulativeProfitCurrency { get; set; } public double Order { get; set; } + } + public class DailyTCVData + { + public string Date { get; set; } + public double TCV { get; set; } + public double Order { get; set; } + } public class MonthlyStatsData { @@ -455,6 +466,7 @@ namespace Core.Main.DataObjects.PTMagicData public double TotalProfitCurrency { get; set; } public double TotalSales { get; set; } public double AvgGrowth { get; set; } + public double Order { get; set; } } diff --git a/Core/DataObjects/ProfitTrailerData.cs b/Core/DataObjects/ProfitTrailerData.cs index 0894193..d828a54 100644 --- a/Core/DataObjects/ProfitTrailerData.cs +++ b/Core/DataObjects/ProfitTrailerData.cs @@ -19,6 +19,7 @@ namespace Core.Main.DataObjects private PropertiesData _properties = null; private StatsData _stats = null; private List _dailyPNL = new List(); + private List _dailyTCV = new List(); private List _monthlyStats = new List(); private decimal? _totalProfit = null; public decimal? TotalProfit @@ -39,15 +40,16 @@ namespace Core.Main.DataObjects private PTMagicConfiguration _systemConfiguration = null; private TransactionData _transactionData = null; private DateTime _dailyPNLRefresh = DateTime.UtcNow; + private DateTime _dailyTCVRefresh = DateTime.UtcNow; private DateTime _monthlyStatsRefresh = DateTime.UtcNow; private DateTime _statsRefresh = DateTime.UtcNow; private DateTime _buyLogRefresh = DateTime.UtcNow; private DateTime _sellLogRefresh = DateTime.UtcNow; private DateTime _dcaLogRefresh = DateTime.UtcNow; private DateTime _miscRefresh = DateTime.UtcNow; - private DateTime _propertiesRefresh = DateTime.UtcNow; - private volatile object _dailyStatsLock = new object(); - private volatile object _dailyPNLLock = new object(); + private DateTime _propertiesRefresh = DateTime.UtcNow; + private volatile object _dailyPNLLock = new object(); + private volatile object _dailyTCVLock = new object(); private volatile object _monthlyStatsLock = new object(); private volatile object _statsLock = new object(); private volatile object _buyLock = new object(); @@ -221,7 +223,11 @@ namespace Core.Main.DataObjects FundingWeek = statsDataJson["totalFundingWeek"], FundingThisMonth = statsDataJson["totalFundingThisMonth"], FundingLastMonth = statsDataJson["totalFundingLastMonth"], - FundingTotal = statsDataJson["totalFunding"] + FundingTotal = statsDataJson["totalFunding"], + TotalFundingPerc = statsDataJson["totalFundingPerc"], + TotalFundingPercYesterday = statsDataJson["totalFundingPercYesterday"], + TotalFundingPercWeek = statsDataJson["totalFundingPercWeekPerc"], + TotalFundingPercToday = statsDataJson["totalFundingPercTodayPerc"] }; } public List DailyPNL @@ -299,6 +305,83 @@ namespace Core.Main.DataObjects Order = dailyPNLDataJson["order"], }; } + + + public List DailyTCV + { + get + { + if (_dailyTCV == null || DateTime.UtcNow > _dailyTCVRefresh) + { + lock (_dailyTCVLock) + { + if (_dailyTCV == null || DateTime.UtcNow > _dailyTCVRefresh) + { + using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats")) + using (var reader = new StreamReader(stream)) + using (var jsonReader = new JsonTextReader(reader)) + { + JObject basicSection = null; + JObject extraSection = null; + + while (jsonReader.Read()) + { + if (jsonReader.TokenType == JsonToken.PropertyName) + { + if ((string)jsonReader.Value == "basic") + { + jsonReader.Read(); // Move to the value of the "basic" property + basicSection = JObject.Load(jsonReader); + } + else if ((string)jsonReader.Value == "extra") + { + jsonReader.Read(); // Move to the value of the "extra" property + extraSection = JObject.Load(jsonReader); + } + } + + if (basicSection != null && extraSection != null) + { + break; + } + } + + if (basicSection != null) // && + //((_totalProfit == null || + //!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value())) || + //(_totalSales == null || + //!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value())))) + { + //_totalProfit = basicSection["totalProfit"].Value(); + //_totalSales = basicSection["totalSales"].Value(); + + if (extraSection != null) + { + JArray dailyTCVSection = (JArray)extraSection["dailyTCVStats"]; + _dailyTCV = dailyTCVSection.Select(j => BuildDailyTCVData(j as JObject)).ToList(); + _dailyTCVRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1); + } + } + } + } + } + } + return _dailyTCV; + } + } + public int GetTotalTCVDays() + { + return DailyTCV?.Count ?? 0; + } + private DailyTCVData BuildDailyTCVData(dynamic dailyTCVDataJson) + { + return new DailyTCVData() + { + Date = dailyTCVDataJson["date"], + TCV = dailyTCVDataJson["TCV"], + Order = dailyTCVDataJson["order"], + }; + } public List MonthlyStats { get @@ -375,6 +458,7 @@ namespace Core.Main.DataObjects TotalSales = monthlyStatsDataJson["totalSales"], TotalProfitCurrency = monthlyStatsDataJson["totalProfitCurrency"], AvgGrowth = monthlyStatsDataJson["avgGrowth"], + Order = monthlyStatsDataJson["order"], }; } public List SellLog diff --git a/Monitor/Pages/SalesAnalyzer.cshtml b/Monitor/Pages/SalesAnalyzer.cshtml index 00b47c5..6b5d34f 100644 --- a/Monitor/Pages/SalesAnalyzer.cshtml +++ b/Monitor/Pages/SalesAnalyzer.cshtml @@ -19,14 +19,11 @@ @{ - string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")); - if (Model.totalCurrentValue > 100) - { - totalCurrentValueString = Math.Round(Model.totalCurrentValue, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")); - } + double totalCurrentValue = double.Parse(Model.PTData.Misc.TotalCurrentValue); + string totalCurrentValueString = Model.PTData.Misc.TotalCurrentValue; } - Total Current Value:   @totalCurrentValueString @Model.Summary.MainMarket - Starting Value:   @Model.MiscData.StartBalance   @Model.Summary.MainMarket + Total Current Value:   @totalCurrentValueString @Model.Summary.MainMarket + Starting Value:   @Model.MiscData.StartBalance   @Model.Summary.MainMarket @@ -34,16 +31,33 @@ -
-
-
-

Cumulative PNL

-
- +
+
+
+

Cumulative Profits + @if (!Model.CumulativeProfitChartDataJSON.Equals("")) { +
+ +
+ } else { +

Unable to load graph, no sales data found.

+ } +

+
+ +
+
+

Daily TCV + @if (!Model.TCVChartDataJSON.Equals("")) { +
+ +
+ } else { +

Unable to load graph, no sales data found.

+ }

-
@if (Model.PTData.SellLog.Count == 0) {
@@ -60,10 +74,11 @@
@{ int totalDays = Model.PTData.GetTotalDays(); + double startBalance = Model.MiscData.StartBalance; double totalSales = Model.PTData.Stats.TotalSales; double totalProfit = Model.PTData.Stats.TotalProfit; double totalFundingFees = Model.PTData.Stats.FundingTotal; - double totalPercentGain = Model.PTData.Stats.TotalProfitPerc; + double totalPercentGain = ((totalProfit + totalFundingFees) / startBalance) * 100; double totalProfitFiat = @Math.Round((totalProfit + totalFundingFees) * Model.PTData.Misc.FiatConversionRate, 0); double avgDailySales = @Math.Round(totalSales/totalDays, 1); double avgDailyGain = totalPercentGain / totalDays; @@ -76,9 +91,8 @@ double avgMonthlyProfit = totalProfit / totalMonths; double avgMonthlyGain = totalPercentGain / totalMonths; double avgMonthlyFunding = totalFundingFees / totalMonths; - string percentGainText = totalPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%"; } -

Sales Analysis

(@startDate - @endDate) +

Sales Analysis

     (@startDate - @endDate) @@ -101,12 +115,6 @@ - - - - - - @if(Model.PropertiesData.IsLeverageExchange) { @@ -123,6 +131,12 @@ + + + + + +
@totalProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) @Math.Round(totalProfit / totalDays, 8).ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) @avgMonthlyProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))
% Gain@Html.Raw(percentGainText)@avgDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@avgMonthlyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
@Html.Raw(Math.Round(totalProfitFiat / totalDays, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US"))) @Html.Raw(Math.Round(totalProfitFiat / totalMonths, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))
% Gain@totalPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@avgDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@avgMonthlyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
@@ -131,46 +145,52 @@
@{ - double currentTotalBalance = Model.totalCurrentValue; - double estimatedBalance1Month = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 30.0), 8); - double estimatedBalance3Months = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 90.0), 8); - double estimatedBalance6Months = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 180.0), 8); - double estimatedBalance1Year = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 365.0), 8); + double estimatedBalance1Week = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 7.0), 8); + double estimatedBalance1Month = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 30.0), 8); + double estimatedBalance3Months = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 90.0), 8); + double estimatedBalance6Months = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 180.0), 8); + double estimatedBalance1Year = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 365.0), 8); } -

Balance Prediction

+

TCV Prediction

- + - + + + + + + + - + - + - + - + - + - + - +
Est. BalanceEst. TCV Est. @Model.PTData.Properties.Currency Value Est. Gain
1 month1 Week@estimatedBalance1Week.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))@Html.Raw(Math.Round(estimatedBalance1Week * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))@Math.Round((estimatedBalance1Week - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
1 Month @estimatedBalance1Month.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) @Html.Raw(Math.Round(estimatedBalance1Month * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))@Math.Round((estimatedBalance1Month - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@Math.Round((estimatedBalance1Month - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
3 months3 Months @estimatedBalance3Months.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) @Html.Raw(Math.Round(estimatedBalance3Months * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))@Math.Round((estimatedBalance3Months - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@Math.Round((estimatedBalance3Months - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
6 months6 Months @estimatedBalance6Months.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) @Html.Raw(Math.Round(estimatedBalance6Months * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))@Math.Round((estimatedBalance6Months - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@Math.Round((estimatedBalance6Months - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
1 year1 Year @estimatedBalance1Year.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) @Html.Raw(Math.Round(estimatedBalance1Year * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))@Math.Round((estimatedBalance1Year - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%@Math.Round((estimatedBalance1Year - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
@@ -180,20 +200,27 @@
-
+
+

Daily Sales
- +

-
-
- -
+
+

Daily Profit + @if (!Model.ProfitChartDataJSON.Equals("")) { +
+ +
+ } else { +

Unable to load graph, no sales data found.

+ }

-
+
+
@@ -375,7 +402,7 @@ nv.utils.windowResize(lineChart.update); return lineChart; }); - +@* nv.addGraph(function () { var lineChart = nv.models.lineChart(); var height = 300; @@ -402,7 +429,7 @@ d3.select('.balance-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart); nv.utils.windowResize(lineChart.update); return lineChart; - }); + }); *@ $("#salesList").on("show.bs.modal", function (e) { $(this).find(".modal-content").html(''); @@ -412,7 +439,146 @@ }); }); })(jQuery); - - + + + + + + } diff --git a/Monitor/Pages/SalesAnalyzer.cshtml.cs b/Monitor/Pages/SalesAnalyzer.cshtml.cs index 58151ee..89cb5da 100644 --- a/Monitor/Pages/SalesAnalyzer.cshtml.cs +++ b/Monitor/Pages/SalesAnalyzer.cshtml.cs @@ -15,9 +15,14 @@ namespace Monitor.Pages public PropertiesData PropertiesData { get; set; } public StatsData StatsData { get; set; } public List DailyPNL { get; set; } + public List DailyTCV { get; set; } + public int ProfitDays { get; set; } + public int TCVDays { get; set; } public List MonthlyStats { get; set; } public string TradesChartDataJSON = ""; + public string CumulativeProfitChartDataJSON = ""; + public string TCVChartDataJSON = ""; public string ProfitChartDataJSON = ""; public string BalanceChartDataJSON = ""; public IEnumerable> TopMarkets = null; @@ -42,6 +47,7 @@ namespace Monitor.Pages StatsData = this.PTData.Stats; MonthlyStats = this.PTData.MonthlyStats; DailyPNL = this.PTData.DailyPNL; + DailyTCV = this.PTData.DailyTCV; //List monthlyStatsData = this.PTData.MonthlyStats; //List dailyPNLData = this.PTData.DailyPNL; @@ -53,9 +59,198 @@ namespace Monitor.Pages BuildTopMarkets(); BuildSalesChartData(); - BuildTCV(); + BuildProfitChartData(); + BuildCumulativeProfitChartData(); + BuildTCVChartData(); //MonthlyAverages(monthlyStatsData, PTData.Stats.FundingTotal); } + private void BuildTCVChartData() + { + List TCVPerDayList = new List(); + + if (PTData.DailyTCV.Count > 0) + { + // Get timezone offset + TimeSpan offset; + bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); + string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); + + if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) + { + offset = TimeSpan.Zero; // If offset is invalid, set it to zero + } + + DateTime endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date; + + // Parse dates once and adjust them to the local timezone + Dictionary dailyTCVByDate = PTData.DailyTCV + .Select(data => { + DateTime dateUtc = DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture); + DateTime dateLocal = dateUtc.Add(isNegative ? -offset : offset); + return new { Date = dateLocal.Date, Data = data }; + }) + .ToDictionary( + item => item.Date, + item => item.Data + ); + + DateTime earliestDataDate = dailyTCVByDate.Keys.Min(); + DateTime startDate = earliestDataDate; + + // Calculate the total days of data available + TCVDays = (endDate - startDate).Days; + + for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) + { + // Use the dictionary to find the Data for the date + if (dailyTCVByDate.TryGetValue(date, out DailyTCVData dailyTCV)) + { + double TCV = dailyTCV.TCV; + + // Add the data point to the list + TCVPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = TCV }); + } + } + // Convert the list to a JSON string using Newtonsoft.Json + TCVChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { + new { + key = "TCV in " + PTData.Misc.Market, + color = Constants.ChartLineColors[1], + values = TCVPerDayList + } + }); + } + } + + private void BuildCumulativeProfitChartData() + { + List profitPerDayList = new List(); + + if (PTData.DailyPNL.Count > 0) + { + // Get timezone offset + TimeSpan offset; + bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); + string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); + + if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) + { + offset = TimeSpan.Zero; // If offset is invalid, set it to zero + } + + DateTime endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date; + + // Parse dates once and adjust them to the local timezone + Dictionary dailyPNLByDate = PTData.DailyPNL + .Select(data => { + DateTime dateUtc = DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture); + DateTime dateLocal = dateUtc.Add(isNegative ? -offset : offset); + return new { Date = dateLocal.Date, Data = data }; + }) + .ToDictionary( + item => item.Date, + item => item.Data + ); + + DateTime earliestDataDate = dailyPNLByDate.Keys.Min(); + DateTime startDate = earliestDataDate; + + // Calculate the total days of data available + ProfitDays = (endDate - startDate).Days; + + double previousDayCumulativeProfit = 0; + for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) + { + // Use the dictionary to find the DailyPNLData for the date + if (dailyPNLByDate.TryGetValue(date, out DailyPNLData dailyPNL)) + { + // Use the CumulativeProfitCurrency directly + double profitFiat = dailyPNL.CumulativeProfitCurrency; + + // Add the data point to the list + profitPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = profitFiat }); + + previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency; + } + } + // Convert the list to a JSON string using Newtonsoft.Json + CumulativeProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { + new { + key = "Profit in " + PTData.Misc.Market, + color = Constants.ChartLineColors[1], + values = profitPerDayList + } + }); + } + } + private void BuildProfitChartData() + { + List profitPerDayList = new List(); + + if (PTData.DailyPNL.Count > 0) + { + // Get timezone offset + TimeSpan offset; + bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); + string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); + + if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) + { + offset = TimeSpan.Zero; // If offset is invalid, set it to zero + } + + DateTime endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date; + + // Parse dates once and adjust them to the local timezone + Dictionary dailyPNLByDate = PTData.DailyPNL + .Select(data => { + DateTime dateUtc = DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture); + DateTime dateLocal = dateUtc.Add(isNegative ? -offset : offset); + return new { Date = dateLocal.Date, Data = data }; + }) + .ToDictionary( + item => item.Date, + item => item.Data + ); + + DateTime earliestDataDate = dailyPNLByDate.Keys.Min(); + DateTime startDate = earliestDataDate; + + // Calculate the total days of data available + ProfitDays = (endDate - startDate).Days; + + double previousDayCumulativeProfit = 0; + bool isFirstDay = true; + for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) + { + // Use the dictionary to find the DailyPNLData for the date + if (dailyPNLByDate.TryGetValue(date, out DailyPNLData dailyPNL)) + { + if (isFirstDay) + { + isFirstDay = false; + } + else + { + // Calculate the profit for the current day + double profitFiat = Math.Round(dailyPNL.CumulativeProfitCurrency - previousDayCumulativeProfit, 2); + + // Add the data point to the list + profitPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = profitFiat }); + } + previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency; + } + } + // Convert the list to a JSON string using Newtonsoft.Json + ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { + new { + key = "Profit in " + PTData.Misc.Market, + color = Constants.ChartLineColors[1], + values = profitPerDayList + } + }); + } + } public (double totalMonths, DateTime startDate, DateTime endDate) MonthlyAverages(List monthlyStats, List dailyPNL) { @@ -186,19 +381,5 @@ namespace Monitor.Pages } } } - private void BuildTCV() - { - double AvailableBalance = PTData.GetCurrentBalance(); - foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog) - { - double leverage = dcaLogEntry.Leverage; - if (leverage == 0) - { - leverage = 1; - } - totalCurrentValue = totalCurrentValue + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) / leverage); - } - totalCurrentValue = totalCurrentValue + AvailableBalance; - } } } diff --git a/Monitor/Pages/_get/DashboardBottom.cshtml b/Monitor/Pages/_get/DashboardBottom.cshtml index 66ee7fa..2e5fd8e 100644 --- a/Monitor/Pages/_get/DashboardBottom.cshtml +++ b/Monitor/Pages/_get/DashboardBottom.cshtml @@ -11,7 +11,7 @@
-
+

Market Trend History

@if (!Model.TrendChartDataJSON.Equals("")) {
@@ -24,7 +24,7 @@
-
+
@{ string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")); @@ -127,44 +127,42 @@

Sales Overviewmore

@{ + double avgGrowthThisMonth = Model.PTData.MonthlyStats.FirstOrDefault(data => data.Order == 1)?.AvgGrowth ?? 0.0; + double avgGrowthLastMonth = Model.PTData.MonthlyStats.FirstOrDefault(data => data.Order == 2)?.AvgGrowth ?? 0.0; - var overviewStats = Model.StatsData; // todaysStats is a new variable + //var startingBalance = Model.MiscData.StartBalance; + var totalCurrentValue = Model.totalCurrentValue; + var overviewStats = Model.StatsData; var todaysSales = overviewStats.SalesToday; var todaysProfit = overviewStats.ProfitToday; var todaysFunding = overviewStats.FundingToday; - var todaysPercentGain = overviewStats.ProfitPercToday; - //var todaysFundingGain = todaysPercentGain * ((todaysProfit - todaysFunding) / todaysProfit); + var todaysPercentGain = overviewStats.ProfitPercToday + Model.PTData.Stats.TotalFundingPercToday; var yesterdaysSales = overviewStats.SalesYesterday; var yesterdaysProfit = overviewStats.ProfitYesterday; var yesterdaysFunding = overviewStats.FundingYesterday; - var yesterdaysPercentGain = overviewStats.ProfitPercYesterday; - //var yesterdaysFundingGain = yesterdaysPercentGain * ((yesterdaysProfit + yesterdaysFunding) / yesterdaysProfit); + var yesterdaysPercentGain = overviewStats.ProfitPercYesterday + Model.PTData.Stats.TotalFundingPercYesterday; var last7DaysSales = overviewStats.SalesWeek; var last7DaysProfit = overviewStats.ProfitWeek; var last7DaysFunding = overviewStats.FundingWeek; - var last7DaysPercentGain = overviewStats.ProfitPercWeek; - //var last7DaysFundingGain = last7DaysPercentGain * ((last7DaysProfit + last7DaysFunding) / last7DaysProfit); + var last7DaysPercentGain = overviewStats.ProfitPercWeek + Model.PTData.Stats.TotalFundingPercWeek; var thisMonthSales = overviewStats.SalesThisMonth; var thisMonthProfit = overviewStats.ProfitThisMonth; var thisMonthFunding = overviewStats.FundingThisMonth; - var thisMonthPercentGain = overviewStats.ProfitPercThisMonth; - //var thisMonthFundingGain = thisMonthPercentGain * ((thisMonthProfit + thisMonthFunding) / thisMonthProfit); + var thisMonthPercentGain = avgGrowthThisMonth; var lastMonthSales = overviewStats.SalesLastMonth; var lastMonthProfit = overviewStats.ProfitLastMonth; var lastMonthFunding = overviewStats.FundingLastMonth; - var lastMonthPercentGain = overviewStats.ProfitPercLastMonth; - //var lastMonthFundingGain = lastMonthPercentGain * ((lastMonthProfit + lastMonthFunding) / lastMonthProfit); + var lastMonthPercentGain = avgGrowthLastMonth; var totalSales = overviewStats.TotalSales; var totalProfit = overviewStats.TotalProfit; var totalFunding = overviewStats.FundingTotal; - var totalProfitPercent = overviewStats.TotalProfitPerc; - //var totalFundingGain = totalProfitPercent * ((totalProfit + totalFunding) / totalProfit); + var totalPercentGain = overviewStats.TotalProfitPerc + Model.PTData.Stats.TotalFundingPerc; double todaysProfitFiat = Math.Round((todaysProfit + todaysFunding) * Model.PTData.Misc.FiatConversionRate, 2); double yesterdaysProfitFiat = Math.Round((yesterdaysProfit + yesterdaysFunding) * Model.PTData.Misc.FiatConversionRate, 2); @@ -182,12 +180,12 @@ Sales Profit @Model.PTData.Misc.Market - Gain @if (futuresFunding) { - Funding + Funding @Model.PTData.Misc.Market } @Model.PTData.Properties.Currency + Gain @@ -195,67 +193,67 @@ Today @overviewStats.SalesToday @todaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - @todaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% @if (futuresFunding) { @todaysFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) } @Html.Raw(todaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))) + @todaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% Yesterday @yesterdaysSales @yesterdaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - @yesterdaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% @if (futuresFunding) { @yesterdaysFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - } + } @Html.Raw(yesterdaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))) + @yesterdaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% Last 7 Days @last7DaysSales @last7DaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - @last7DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% @if (futuresFunding) { @last7DaysFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) } @Html.Raw(last7DaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))) + @last7DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% This Month @thisMonthSales @thisMonthProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - @thisMonthPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% @if (futuresFunding) { @thisMonthFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) } @Html.Raw(thisMonthProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))) + @thisMonthPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% Last Month @lastMonthSales @lastMonthProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - @lastMonthPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% @if (futuresFunding) { @lastMonthFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) } @Html.Raw(lastMonthProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))) + @lastMonthPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% Total @totalSales @totalProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) - @totalProfitPercent.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% @if (futuresFunding) { @totalFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")) } @Html.Raw(totalProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))) + @totalPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% diff --git a/Monitor/Pages/_get/DashboardBottom.cshtml.cs b/Monitor/Pages/_get/DashboardBottom.cshtml.cs index d74916d..970e0bd 100644 --- a/Monitor/Pages/_get/DashboardBottom.cshtml.cs +++ b/Monitor/Pages/_get/DashboardBottom.cshtml.cs @@ -42,7 +42,9 @@ namespace Monitor.Pages StatsData = this.PTData.Stats; PropertiesData = this.PTData.Properties; MiscData = this.PTData.Misc; + List monthlyStatsData = this.PTData.MonthlyStats; List dailyPNLData = this.PTData.DailyPNL; + // Cleanup temp files FileHelper.CleanupFilesMinutes(PTMagicMonitorBasePath + "wwwroot" + System.IO.Path.DirectorySeparatorChar + "assets" + System.IO.Path.DirectorySeparatorChar + "tmp" + System.IO.Path.DirectorySeparatorChar, 5); @@ -65,161 +67,162 @@ namespace Monitor.Pages BuildAssetDistributionData(); BuildProfitChartData(); } + private void BuildMarketTrendChartData() -{ - List trendChartData = new List(); - if (MarketTrends.Count > 0) { - - int mtIndex = 0; - foreach (MarketTrend mt in MarketTrends) + List trendChartData = new List(); + if (MarketTrends.Count > 0) { - if (mt.DisplayGraph) + + int mtIndex = 0; + foreach (MarketTrend mt in MarketTrends) { - string lineColor = mtIndex < Constants.ChartLineColors.Length - ? Constants.ChartLineColors[mtIndex] - : Constants.ChartLineColors[mtIndex - 20]; - - if (Summary.MarketTrendChanges.ContainsKey(mt.Name)) + if (mt.DisplayGraph) { - List marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name]; + string lineColor = mtIndex < Constants.ChartLineColors.Length + ? Constants.ChartLineColors[mtIndex] + : Constants.ChartLineColors[mtIndex - 20]; - if (marketTrendChangeSummaries.Count > 0) + if (Summary.MarketTrendChanges.ContainsKey(mt.Name)) { - List trendValues = new List(); + List marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name]; - // Sort marketTrendChangeSummaries by TrendDateTime - marketTrendChangeSummaries = marketTrendChangeSummaries.OrderBy(m => m.TrendDateTime).ToList(); - - // Get trend ticks for chart - TimeSpan offset; - bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); - string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); - - if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) + if (marketTrendChangeSummaries.Count > 0) { - offset = TimeSpan.Zero; // If offset is invalid, set it to zero - } + List trendValues = new List(); - DateTime currentDateTime = DateTime.UtcNow; - DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours); - DateTime endDateTime = currentDateTime; + // Sort marketTrendChangeSummaries by TrendDateTime + marketTrendChangeSummaries = marketTrendChangeSummaries.OrderBy(m => m.TrendDateTime).ToList(); - // Ensure startDateTime doesn't exceed the available data - DateTime earliestTrendDateTime = marketTrendChangeSummaries.Min(mtc => mtc.TrendDateTime); - startDateTime = startDateTime > earliestTrendDateTime ? startDateTime : earliestTrendDateTime; - DataHours = (currentDateTime - earliestTrendDateTime).TotalHours; + // Get trend ticks for chart + TimeSpan offset; + bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); + string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); - // Cache the result of SplitCamelCase(mt.Name) - string splitCamelCaseName = SystemHelper.SplitCamelCase(mt.Name); - - for (DateTime tickTime = startDateTime; tickTime <= endDateTime; tickTime = tickTime.AddMinutes(PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes)) - { - // Use binary search to find the range of items that match the condition - int index = marketTrendChangeSummaries.BinarySearch(new MarketTrendChange { TrendDateTime = tickTime }, Comparer.Create((x, y) => x.TrendDateTime.CompareTo(y.TrendDateTime))); - if (index < 0) index = ~index; - if (index < marketTrendChangeSummaries.Count) + if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) { - MarketTrendChange mtc = marketTrendChangeSummaries[index]; - if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0; - - // Adjust tickTime to the desired timezone before converting to string - DateTime adjustedTickTime = tickTime.Add(isNegative ? -offset : offset); - trendValues.Add("{ x: new Date('" + adjustedTickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}"); + offset = TimeSpan.Zero; // If offset is invalid, set it to zero } + + DateTime currentDateTime = DateTime.UtcNow; + DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours); + DateTime endDateTime = currentDateTime; + + // Ensure startDateTime doesn't exceed the available data + DateTime earliestTrendDateTime = marketTrendChangeSummaries.Min(mtc => mtc.TrendDateTime); + startDateTime = startDateTime > earliestTrendDateTime ? startDateTime : earliestTrendDateTime; + DataHours = (currentDateTime - earliestTrendDateTime).TotalHours; + + // Cache the result of SplitCamelCase(mt.Name) + string splitCamelCaseName = SystemHelper.SplitCamelCase(mt.Name); + + for (DateTime tickTime = startDateTime; tickTime <= endDateTime; tickTime = tickTime.AddMinutes(PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes)) + { + // Use binary search to find the range of items that match the condition + int index = marketTrendChangeSummaries.BinarySearch(new MarketTrendChange { TrendDateTime = tickTime }, Comparer.Create((x, y) => x.TrendDateTime.CompareTo(y.TrendDateTime))); + if (index < 0) index = ~index; + if (index < marketTrendChangeSummaries.Count) + { + MarketTrendChange mtc = marketTrendChangeSummaries[index]; + if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0; + + // Adjust tickTime to the desired timezone before converting to string + DateTime adjustedTickTime = tickTime.Add(isNegative ? -offset : offset); + trendValues.Add("{ x: new Date('" + adjustedTickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}"); + } + } + + // Add most recent tick + MarketTrendChange latestMtc = marketTrendChangeSummaries.Last(); + if (Double.IsInfinity(latestMtc.TrendChange)) latestMtc.TrendChange = 0; + + // Adjust latestMtc.TrendDateTime to the desired timezone before converting to string + DateTime adjustedLatestTrendDateTime = latestMtc.TrendDateTime.Add(isNegative ? -offset : offset); + trendValues.Add("{ x: new Date('" + adjustedLatestTrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + latestMtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}"); + + // Use cached splitCamelCaseName + trendChartData.Add("{ key: '" + splitCamelCaseName + "', color: '" + lineColor + "', values: [" + string.Join(",\n", trendValues) + "] }"); + mtIndex++; } - - // Add most recent tick - MarketTrendChange latestMtc = marketTrendChangeSummaries.Last(); - if (Double.IsInfinity(latestMtc.TrendChange)) latestMtc.TrendChange = 0; - - // Adjust latestMtc.TrendDateTime to the desired timezone before converting to string - DateTime adjustedLatestTrendDateTime = latestMtc.TrendDateTime.Add(isNegative ? -offset : offset); - trendValues.Add("{ x: new Date('" + adjustedLatestTrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + latestMtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}"); - - // Use cached splitCamelCaseName - trendChartData.Add("{ key: '" + splitCamelCaseName + "', color: '" + lineColor + "', values: [" + string.Join(",\n", trendValues) + "] }"); - mtIndex++; } } } } + TrendChartDataJSON = "[" + string.Join(",", trendChartData) + "]"; } - TrendChartDataJSON = "[" + string.Join(",", trendChartData) + "]"; -} private void BuildProfitChartData() -{ - List profitPerDayList = new List(); - - if (PTData.DailyPNL.Count > 0) { - // Get timezone offset - TimeSpan offset; - bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); - string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); + List profitPerDayList = new List(); - if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) + if (PTData.DailyPNL.Count > 0) { - offset = TimeSpan.Zero; // If offset is invalid, set it to zero - } + // Get timezone offset + TimeSpan offset; + bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-"); + string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-'); - DateTime endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date; - - // Parse dates once and adjust them to the local timezone - Dictionary dailyPNLByDate = PTData.DailyPNL - .Select(data => { - DateTime dateUtc = DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture); - DateTime dateLocal = dateUtc.Add(isNegative ? -offset : offset); - return new { Date = dateLocal.Date, Data = data }; - }) - .ToDictionary( - item => item.Date, - item => item.Data - ); - - DateTime earliestDataDate = dailyPNLByDate.Keys.Min(); - DateTime startDate = endDate.AddDays(-PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays - 1); // Fetch data for timeframe + 1 days - if (startDate < earliestDataDate) - { - startDate = earliestDataDate; - } - - // Calculate the total days of data available - ProfitDays = (endDate - startDate).Days; - - double previousDayCumulativeProfit = 0; - bool isFirstDay = true; - for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) - { - // Use the dictionary to find the DailyPNLData for the date - if (dailyPNLByDate.TryGetValue(date, out DailyPNLData dailyPNL)) + if (!TimeSpan.TryParse(offsetWithoutSign, out offset)) { - if (isFirstDay) - { - isFirstDay = false; - } - else - { - // Calculate the profit for the current day - double profitFiat = Math.Round(dailyPNL.CumulativeProfitCurrency - previousDayCumulativeProfit, 2); + offset = TimeSpan.Zero; // If offset is invalid, set it to zero + } - // Add the data point to the list - profitPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = profitFiat }); + DateTime endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date; + + // Parse dates once and adjust them to the local timezone + Dictionary dailyPNLByDate = PTData.DailyPNL + .Select(data => { + DateTime dateUtc = DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture); + DateTime dateLocal = dateUtc.Add(isNegative ? -offset : offset); + return new { Date = dateLocal.Date, Data = data }; + }) + .ToDictionary( + item => item.Date, + item => item.Data + ); + + DateTime earliestDataDate = dailyPNLByDate.Keys.Min(); + DateTime startDate = endDate.AddDays(-PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays - 1); // Fetch data for timeframe + 1 days + if (startDate < earliestDataDate) + { + startDate = earliestDataDate; + } + + // Calculate the total days of data available + ProfitDays = (endDate - startDate).Days; + + double previousDayCumulativeProfit = 0; + bool isFirstDay = true; + for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) + { + // Use the dictionary to find the DailyPNLData for the date + if (dailyPNLByDate.TryGetValue(date, out DailyPNLData dailyPNL)) + { + if (isFirstDay) + { + isFirstDay = false; + } + else + { + // Calculate the profit for the current day + double profitFiat = Math.Round(dailyPNL.CumulativeProfitCurrency - previousDayCumulativeProfit, 2); + + // Add the data point to the list + profitPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = profitFiat }); + } + previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency; } - previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency; } + // Convert the list to a JSON string using Newtonsoft.Json + ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { + new { + key = "Profit in " + PTData.Misc.Market, + color = Constants.ChartLineColors[1], + values = profitPerDayList + } + }); } - // Convert the list to a JSON string using Newtonsoft.Json - ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { - new { - key = "Profit in " + PTData.Misc.Market, - color = Constants.ChartLineColors[1], - values = profitPerDayList - } - }); } -} private void BuildAssetDistributionData() {