diff --git a/Core/DataObjects/PTMagicData.cs b/Core/DataObjects/PTMagicData.cs index 0aebdc2..7969a79 100644 --- a/Core/DataObjects/PTMagicData.cs +++ b/Core/DataObjects/PTMagicData.cs @@ -467,7 +467,13 @@ namespace Core.Main.DataObjects.PTMagicData public double TotalSales { get; set; } public double AvgGrowth { get; set; } public double Order { get; set; } - + } + public class ProfitablePairsData + { + public string Coin { get; set; } + public double ProfitCurrency { get; set; } + public int SoldTimes { get; set; } + public double Avg { get; set; } } public class PTStrategy diff --git a/Core/DataObjects/ProfitTrailerData.cs b/Core/DataObjects/ProfitTrailerData.cs index d828a54..212f8d2 100644 --- a/Core/DataObjects/ProfitTrailerData.cs +++ b/Core/DataObjects/ProfitTrailerData.cs @@ -21,6 +21,7 @@ namespace Core.Main.DataObjects private List _dailyPNL = new List(); private List _dailyTCV = new List(); private List _monthlyStats = new List(); + private List _profitablePairs = new List(); private decimal? _totalProfit = null; public decimal? TotalProfit { @@ -48,6 +49,7 @@ namespace Core.Main.DataObjects private DateTime _dcaLogRefresh = DateTime.UtcNow; private DateTime _miscRefresh = DateTime.UtcNow; private DateTime _propertiesRefresh = DateTime.UtcNow; + private DateTime _profitablePairsRefresh = DateTime.UtcNow; private volatile object _dailyPNLLock = new object(); private volatile object _dailyTCVLock = new object(); private volatile object _monthlyStatsLock = new object(); @@ -56,7 +58,8 @@ namespace Core.Main.DataObjects private volatile object _sellLock = new object(); private volatile object _dcaLock = new object(); private volatile object _miscLock = new object(); - private volatile object _propertiesLock = new object(); + private volatile object _propertiesLock = new object(); + private volatile object _profitablePairsLock = new object(); private TimeSpan? _offsetTimeSpan = null; public void DoLog(string message) { @@ -305,6 +308,90 @@ namespace Core.Main.DataObjects Order = dailyPNLDataJson["order"], }; } + public List ProfitablePairs + { + get + { + if (_profitablePairs == null || DateTime.UtcNow > _profitablePairsRefresh) + { + lock (_profitablePairsLock) + { + if (_profitablePairs == null || DateTime.UtcNow > _profitablePairsRefresh) + { + 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) + { + JObject profitablePairsSection = (JObject)extraSection["profitablePairs"]; + _profitablePairs = new List(); + int counter = 0; + foreach (var j in profitablePairsSection) + { + if (counter >= _systemConfiguration.GeneralSettings.Monitor.MaxTopMarkets) + { + break; + } + // Process each JObject in the dictionary + JObject profitablePair = (JObject)j.Value; + _profitablePairs.Add(BuildProfitablePairs(profitablePair)); + counter++; + } + _profitablePairsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1); + } + } + } + } + } + } + return _profitablePairs; + } + } + private ProfitablePairsData BuildProfitablePairs(JObject profitablePairsJson) + { + return new ProfitablePairsData() + { + Coin = profitablePairsJson["coin"].Value(), + ProfitCurrency = profitablePairsJson["profitCurrency"].Value(), + SoldTimes = profitablePairsJson["soldTimes"].Value(), + Avg = profitablePairsJson["avg"].Value(), + }; + } + + + public List DailyTCV @@ -493,7 +580,7 @@ namespace Core.Main.DataObjects this.BuildSellLogData(sellDataPage); pageIndex++; requestedPages++; - Console.WriteLine($"Importing sale: {pageIndex}"); +Console.WriteLine($"Importing sale: {pageIndex}"); } else diff --git a/Monitor/Pages/SalesAnalyzer.cshtml b/Monitor/Pages/SalesAnalyzer.cshtml index 6b5d34f..cc42f5c 100644 --- a/Monitor/Pages/SalesAnalyzer.cshtml +++ b/Monitor/Pages/SalesAnalyzer.cshtml @@ -219,8 +219,49 @@

Unable to load graph, no sales data found.

} + +
+
+
+

Top @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets Sales Markets

+ + + + + + + + + + + + + @{ + int rank = 1; + foreach (var pair in Model.ProfitablePairs) + { + string coin = pair.Coin; + double profit = Math.Round(pair.ProfitCurrency,8); + int sales = pair.SoldTimes; + double avg = Math.Round(pair.Avg,8); + double profitFiat = Math.Round(profit * Model.MiscData.FiatConversionRate, 0); + + + + + + + + + rank++; + } + } + +
RankMarketProfit @Model.PTData.Misc.MarketSalesAvg/TradeProfit @Model.PTData.Properties.Currency
@rank@coin@profit@sales@avg @profitFiat
+
+
@@ -315,55 +356,15 @@
-
-
-
-

Top @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets Sales Market Analysis

- - - - - - - - - - - - - - @{ - var topMarkets = Model.PTData.SellLog.GroupBy(m => m.Market).Select(mg => mg.Sum(m => m.Profit)); - int marketRank = 0; - } - @foreach (KeyValuePair marketData in Model.TopMarkets) { - marketRank++; - int trades = Model.PTData.SellLog.FindAll(m => m.Market == marketData.Key).Count; - double profitFiat = Math.Round(marketData.Value * Model.Summary.MainMarketPrice, 2); - double profitFiatPerTrade = Math.Round(profitFiat / trades, 2); - - - - - - - - - - } - -
RankMarketSalesProfit @Model.Summary.MainMarketProfit @Model.Summary.MainFiatCurrencyProfit @Model.Summary.MainFiatCurrency/TradeProfit %/Trade
@marketRank@marketData.Key@trades@marketData.Value.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))@profitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) @Model.Summary.MainFiatCurrency@profitFiatPerTrade.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) @Model.Summary.MainFiatCurrency@Model.PTData.SellLog.FindAll(m => m.Market == marketData.Key).Average(p => p.ProfitPercent).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%
-
-
-
+ - *@ } @section Scripts { @@ -402,34 +403,6 @@ nv.utils.windowResize(lineChart.update); return lineChart; }); -@* - nv.addGraph(function () { - var lineChart = nv.models.lineChart(); - var height = 300; - /**/ - var chartData = @Html.Raw(Model.ProfitChartDataJSON); - /**/ - lineChart.useInteractiveGuideline(true); - lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); }); - lineChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f')); - d3.select('.profit-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart); - nv.utils.windowResize(lineChart.update); - return lineChart; - }); - - nv.addGraph(function () { - var lineChart = nv.models.lineChart(); - var height = 400; - /**/ - var chartData = @Html.Raw(Model.BalanceChartDataJSON); - /**/ - lineChart.useInteractiveGuideline(true); - lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); }); - lineChart.yAxis.axisLabel('Profit').tickFormat(d3.format(',.2f')); - 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(''); @@ -481,6 +454,7 @@ d3.select('.nvtooltip').style('opacity', 0); } }); + nv.utils.windowResize(cumulativeProfitChart.update); return cumulativeProfitChart; }); @@ -528,6 +502,7 @@ d3.select('.nvtooltip').style('opacity', 0); } }); + nv.utils.windowResize(TCVChart.update); return TCVChart; }); @@ -575,6 +550,7 @@ d3.select('.nvtooltip').style('opacity', 0); } }); + nv.utils.windowResize(profitChart.update); return profitChart; }); diff --git a/Monitor/Pages/SalesAnalyzer.cshtml.cs b/Monitor/Pages/SalesAnalyzer.cshtml.cs index 89cb5da..6c56c89 100644 --- a/Monitor/Pages/SalesAnalyzer.cshtml.cs +++ b/Monitor/Pages/SalesAnalyzer.cshtml.cs @@ -16,6 +16,7 @@ namespace Monitor.Pages public StatsData StatsData { get; set; } public List DailyPNL { get; set; } public List DailyTCV { get; set; } + public List ProfitablePairs { get; set; } public int ProfitDays { get; set; } public int TCVDays { get; set; } public List MonthlyStats { get; set; } @@ -48,21 +49,16 @@ namespace Monitor.Pages MonthlyStats = this.PTData.MonthlyStats; DailyPNL = this.PTData.DailyPNL; DailyTCV = this.PTData.DailyTCV; + ProfitablePairs = this.PTData.ProfitablePairs; - //List monthlyStatsData = this.PTData.MonthlyStats; - //List dailyPNLData = this.PTData.DailyPNL; - - // Convert local offset time to UTC TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); DateTimeNow = DateTimeOffset.UtcNow.ToOffset(offsetTimeSpan); - BuildTopMarkets(); BuildSalesChartData(); BuildProfitChartData(); BuildCumulativeProfitChartData(); BuildTCVChartData(); - //MonthlyAverages(monthlyStatsData, PTData.Stats.FundingTotal); } private void BuildTCVChartData() { @@ -314,25 +310,14 @@ namespace Monitor.Pages int tradeDayIndex = 0; string tradesPerDayJSON = ""; - string profitPerDayJSON = ""; - string balancePerDayJSON = ""; - double balance = 0.0; for (DateTime salesDate = graphStartDate; salesDate <= DateTimeNow.DateTime.Date; salesDate = salesDate.AddDays(1)) { if (tradeDayIndex > 0) { tradesPerDayJSON += ",\n"; - profitPerDayJSON += ",\n"; - balancePerDayJSON += ",\n"; } - double profit = 0; int trades = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate.Date).Count; - profit = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate.Date).Sum(t => t.Profit); - double profitFiat = Math.Round(profit * Summary.MainMarketPrice, 2); - balance += profitFiat; tradesPerDayJSON += "{x: new Date('" + salesDate.Date.ToString("yyyy-MM-dd") + "'), y: " + trades + "}"; - profitPerDayJSON += "{x: new Date('" + salesDate.Date.ToString("yyyy-MM-dd") + "'), y: " + profitFiat.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}"; - balancePerDayJSON += "{x: new Date('" + salesDate.Date.ToString("yyyy-MM-dd") + "'), y: " + balance.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}"; tradeDayIndex++; } TradesChartDataJSON = "["; @@ -343,42 +328,7 @@ namespace Monitor.Pages TradesChartDataJSON += "}"; TradesChartDataJSON += "]"; - ProfitChartDataJSON = "["; - ProfitChartDataJSON += "{"; - ProfitChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',"; - ProfitChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',"; - ProfitChartDataJSON += "values: [" + profitPerDayJSON + "]"; - ProfitChartDataJSON += "}"; - ProfitChartDataJSON += "]"; - - BalanceChartDataJSON = "["; - BalanceChartDataJSON += "{"; - BalanceChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',"; - BalanceChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',"; - BalanceChartDataJSON += "values: [" + balancePerDayJSON + "]"; - BalanceChartDataJSON += "}"; - BalanceChartDataJSON += "]"; - for (DateTime salesDate = DateTimeNow.DateTime.Date; salesDate >= MinSellLogDate; salesDate = salesDate.AddDays(-1)) - { - List salesDateSales = PTData.SellLog.FindAll(sl => sl.SoldDate.Date == salesDate); - double salesDateProfit; - salesDateProfit = salesDateSales.Sum(sl => sl.Profit); - double salesDateStartBalance = PTData.GetSnapshotBalance(salesDate); - double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2); - DailyGains.Add(salesDate, salesDateGain); - } - DateTime minSellLogMonthDate = new DateTime(MinSellLogDate.Year, MinSellLogDate.Month, 1).Date; - DateTime salesMonthStartDate = new DateTime(DateTimeNow.DateTime.Year, DateTimeNow.DateTime.Month, 1).Date; - for (DateTime salesMonthDate = salesMonthStartDate.Date; salesMonthDate >= minSellLogMonthDate; salesMonthDate = salesMonthDate.AddMonths(-1)) - { - List salesMonthSales = PTData.SellLog.FindAll(sl => sl.SoldDate.Date.Month == salesMonthDate.Month && sl.SoldDate.Date.Year == salesMonthDate.Year); - double salesDateProfit; - salesDateProfit = salesMonthSales.Sum(sl => sl.Profit); - double salesDateStartBalance = PTData.GetSnapshotBalance(salesMonthDate); - double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2); - MonthlyGains.Add(salesMonthDate, salesDateGain); - } } } } diff --git a/Monitor/Pages/_get/DashboardBottom.cshtml b/Monitor/Pages/_get/DashboardBottom.cshtml index 2e5fd8e..50531c3 100644 --- a/Monitor/Pages/_get/DashboardBottom.cshtml +++ b/Monitor/Pages/_get/DashboardBottom.cshtml @@ -51,7 +51,7 @@
@*
*@ -
+

Daily Profit @if (!Model.ProfitChartDataJSON.Equals("")) {
@@ -308,7 +308,7 @@ d3.select('.nvtooltip').style('opacity', 0); } }); - + nv.utils.windowResize(assetDistributionChart.update); return assetDistributionChart; }); @@ -355,7 +355,7 @@ d3.select('.nvtooltip').style('opacity', 0); } }); - + nv.utils.windowResize(trendChart.update); return trendChart; }); @@ -403,8 +403,7 @@ d3.select('.nvtooltip').style('opacity', 0); } }); - - + nv.utils.windowResize(profitChart.update); return profitChart; });