More Dashboard bottom optimizations

This commit is contained in:
HojouFotytu 2024-01-14 04:10:44 +09:00
parent 16fada1443
commit 08554da6ee
5 changed files with 290 additions and 165 deletions

View File

@ -33,11 +33,6 @@
$("#baglist-refresh-icon").html('<i class="fa fa-circle-o-notch fa-spin fa-fw" data-toggle="tooltip" data-placement="top" title="Loading fresh data..."></i>'); $("#baglist-refresh-icon").html('<i class="fa fa-circle-o-notch fa-spin fa-fw" data-toggle="tooltip" data-placement="top" title="Loading fresh data..."></i>');
$("#buylist-refresh-icon").html('<i class="fa fa-circle-o-notch fa-spin fa-fw" data-toggle="tooltip" data-placement="top" title="Loading fresh data..."></i>'); $("#buylist-refresh-icon").html('<i class="fa fa-circle-o-notch fa-spin fa-fw" data-toggle="tooltip" data-placement="top" title="Loading fresh data..."></i>');
// Add the page refresh code here
setTimeout(function(){
location.reload();
}, 60 * 60 * 1000); // 60 minutes
// Clear exisitng interval to stop multiple attempts to load at the same time. // Clear exisitng interval to stop multiple attempts to load at the same time.
if (intervalDashboardTop != null) if (intervalDashboardTop != null)
{ {
@ -69,13 +64,16 @@
var loadDashboardBottom = function () { var loadDashboardBottom = function () {
//destroy all d3 svg graph to avoid memory leak //destroy all d3 svg graph to avoid memory leak
//$(".nvtooltip").remove(); setTimeout(function()
//$("svg > *").remove(); {
//$("svg").remove(); $(".nvtooltip").remove();
//nv.charts = {}; $("svg > *").remove();
//nv.graphs = []; $("svg").remove();
//nv.logs = {}; nv.charts = {};
//nv.tooltip = {}; nv.graphs = [];
nv.logs = {};
nv.tooltip = {};
}, 10 * intervalDashboardBottom * 1000); // 10 times intervalDashboardBottom in milliseconds
// Clear exisitng interval to stop multiple attempts to load at the same time. // Clear exisitng interval to stop multiple attempts to load at the same time.
if (intervalDashboardBottom != null) if (intervalDashboardBottom != null)

View File

@ -196,21 +196,21 @@
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-md-4 col-form-label">Market Trend Graph Interval Minutes <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The time interval for the market trend graph between points."></i></label> <label class="col-md-4 col-form-label">Market Trend Graph Interval Minutes <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The time interval for the market trend graph (Dashboard and Sales Analyzer) between data points. Very small intervals on large timeframe graphs can significantly impact performance."></i></label>
<div class="col-md-8"> <div class="col-md-8">
<input type="text" class="form-control" name="Monitor_GraphIntervalMinutes" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes.ToString(new System.Globalization.CultureInfo("en-US"))"> <input type="text" class="form-control" name="Monitor_GraphIntervalMinutes" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes.ToString(new System.Globalization.CultureInfo("en-US"))">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-md-4 col-form-label">Market Trend Graph Max Timeframe <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This defines the total timeframe for the market trends graph in hours."></i></label> <label class="col-md-4 col-form-label">Market Trend Graph Max Timeframe <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This defines the total timeframe for the market trends graph (Dashboard and Sales Analyzer) in hours. Large timeframe graphs can significantly impact performance."></i></label>
<div class="col-md-8"> <div class="col-md-8">
<input type="text" class="form-control" name="Monitor_GraphMaxTimeframeHours" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours.ToString(new System.Globalization.CultureInfo("en-US"))"> <input type="text" class="form-control" name="Monitor_GraphMaxTimeframeHours" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours.ToString(new System.Globalization.CultureInfo("en-US"))">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-md-4 col-form-label">Daily Profit Graph Max Timeframe <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This defines the total timeframe for the daily profits graph on the dashboard in days."></i></label> <label class="col-md-4 col-form-label">Daily Profit Graph Max Timeframe <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This defines the total timeframe for the daily profits graph on the dashboard in days. Large timeframes can significantly impact performance."></i></label>
<div class="col-md-8"> <div class="col-md-8">
<input type="text" class="form-control" name="Monitor_ProfitsMaxTimeframeDays" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays.ToString(new System.Globalization.CultureInfo("en-US"))"> <input type="text" class="form-control" name="Monitor_ProfitsMaxTimeframeDays" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays.ToString(new System.Globalization.CultureInfo("en-US"))">
</div> </div>

View File

@ -10,7 +10,8 @@
} }
<div class="row"> <div class="row">
<div class="col-md-5">
<div class="col-md-6">
<div class="card-box"> <div class="card-box">
<h4 class="m-t-0 header-title">PTMagic Status <small id="last-refresh" class="pull-right"></small></h4> <h4 class="m-t-0 header-title">PTMagic Status <small id="last-refresh" class="pull-right"></small></h4>
@{ @{
@ -71,7 +72,6 @@
@{ @{
string maxCostCaption = "Initial"; string maxCostCaption = "Initial";
} }
<table class="table table-striped table-sm"> <table class="table table-striped table-sm">
<tbody> <tbody>
<tr> <tr>
@ -99,35 +99,32 @@
</table> </table>
</div> </div>
</div>
<div class="col-md-7">
<div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="card-box"> <div class="card-box">
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4> <h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
<div id="gsChart24h"> <div id="gsChart24h">
<svg style="height:300px;width:100%"></svg> <svg style="height:200px;width:100%"></svg>
</div> </div>
</div> </div>
</div>
<div class="col-md-6">
<div class="card-box"> <div class="card-box">
<h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4> <h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4>
<div id="gsChart3d"> <div id="gsChart3d">
<svg style="height:300px;width:100%"></svg> <svg style="height:200px;width:100%"></svg>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="card-box"> <div class="card-box">
<h4 class="m-t-0 header-title">Global Settings Log</h4> <h4 class="m-t-0 header-title">Global Settings Log</h4>
<table class="table table-striped table-sm"> <table class="table table-striped table-sm">
<thead> <thead>
<tr> <tr>
@ -160,9 +157,6 @@
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</div>
@section Scripts { @section Scripts {

View File

@ -11,8 +11,8 @@
<div class="row"> <div class="row">
<div class="col-md-5 px-1"> <div class="col-md-5 px-1">
<div class="card-box px-2" style="height:305px;"> <div class="card-box px-2" style="height:320px;">
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div> <h4 class="m-t-0 m-b-20 header-title" style="display: inline;"><b>Market Trend History </b><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="@Math.Round(Model.DataHours, 1) hours of data available. Currently set to show @Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours hours in general settings."></i></h4>
@if (!Model.TrendChartDataJSON.Equals("")) { @if (!Model.TrendChartDataJSON.Equals("")) {
<div class="trend-chart"> <div class="trend-chart">
<svg style="height: 300px;width: 100%;"></svg> <svg style="height: 300px;width: 100%;"></svg>
@ -22,9 +22,10 @@
} }
</div> </div>
</div> </div>
<div class="col-md-3 px-1"> <div class="col-md-3 px-1">
<div class="card-box px-3" style="height:305px;"> <div class="card-box px-3" style="height:320px;">
@*<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>*@ <div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="You dashboard is set to refresh every @Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds seconds in general settings."></i></div>
@{ @{
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")); string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
if (Model.totalCurrentValue > 100) { if (Model.totalCurrentValue > 100) {
@ -50,7 +51,8 @@
<div class="col-md-4 px-1"> <div class="col-md-4 px-1">
@*<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>*@ @*<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>*@
<div class="card-box px-2" style="height:305px;"> <div class="card-box px-2" style="height:320px;">
<h4 class="m-t-0 m-b-20 header-title" style="display: inline;"><b>Daily Profit </b><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="@Model.ProfitDays days of data available. Currently Set to @Model.PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays days in general settings."></i>
@if (!Model.ProfitChartDataJSON.Equals("")) { @if (!Model.ProfitChartDataJSON.Equals("")) {
<div class="profit-chart"> <div class="profit-chart">
<svg style="height:300px;width:100%"></svg> <svg style="height:300px;width:100%"></svg>
@ -65,8 +67,8 @@
<div class="row"> <div class="row">
<div class="col-md-5 px-1"> <div class="col-md-5 px-1">
<div class="card-box px-2"> <div class="card-box px-2">
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div> @* <div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
<br> <br> *@
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b> <h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b>
<small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4> <small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4>
<table class="table table-sm"> <table class="table table-sm">
@ -293,6 +295,22 @@
.datum(assetDistributionData) .datum(assetDistributionData)
.transition().duration(0) .transition().duration(0)
.call(assetDistributionChart); .call(assetDistributionChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
});
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
}
});
return assetDistributionChart; return assetDistributionChart;
}); });
</text> </text>
@ -325,6 +343,21 @@
.datum(trendData) .datum(trendData)
.transition().duration(0) .transition().duration(0)
.call(trendChart); .call(trendChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
});
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
}
});
return trendChart; return trendChart;
}); });
</text> </text>
@ -348,7 +381,7 @@
profitChart = nv.models.lineChart(); profitChart = nv.models.lineChart();
var height = 300; var height = 300;
profitChart.useInteractiveGuideline(true); profitChart.useInteractiveGuideline(true);
profitChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); }); profitChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
profitChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f')); profitChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
profitData = @Html.Raw(Model.ProfitChartDataJSON); profitData = @Html.Raw(Model.ProfitChartDataJSON);
@ -357,9 +390,54 @@
.datum(profitData) .datum(profitData)
.transition().duration(0) .transition().duration(0)
.call(profitChart); .call(profitChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
});
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
}
});
return profitChart; return profitChart;
}); });
</text> </text>
} }
})(jQuery); })(jQuery);
</script> </script>
<script type="text/javascript">
$(document).ready(function(){
var originalLeave = $.fn.tooltip.Constructor.prototype.leave;
$.fn.tooltip.Constructor.prototype.leave = function(obj){
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type);
var container, timeout;
originalLeave.call(this, obj);
if(obj.currentTarget) {
container = $(obj.currentTarget).siblings('.tooltip');
timeout = self.timeout;
container.one('mouseenter', function(){
//We entered the actual tooltip call off the dogs
clearTimeout(timeout);
//Let's monitor tooltip content instead
container.one('mouseleave', function(){
$.fn.tooltip.Constructor.prototype.leave.call(self, self);
});
});
}
};
$('[data-toggle="tooltip"]').tooltip();
});
</script>

View File

@ -8,6 +8,7 @@ using Core.Main.DataObjects;
using Core.Main.DataObjects.PTMagicData; using Core.Main.DataObjects.PTMagicData;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using System.Diagnostics;
namespace Monitor.Pages namespace Monitor.Pages
{ {
@ -19,6 +20,8 @@ namespace Monitor.Pages
public SummaryData SummaryData { get; set; } public SummaryData SummaryData { get; set; }
public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>(); public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
public double DataHours { get; set; }
public int ProfitDays { get; set; }
public string TrendChartDataJSON = ""; public string TrendChartDataJSON = "";
public string ProfitChartDataJSON = ""; public string ProfitChartDataJSON = "";
public string LastGlobalSetting = "Default"; public string LastGlobalSetting = "Default";
@ -32,7 +35,6 @@ namespace Monitor.Pages
BindData(); BindData();
BuildAssetDistributionData();
} }
private void BindData() private void BindData()
@ -62,6 +64,7 @@ namespace Monitor.Pages
MarketTrends = PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.OrderBy(mt => mt.TrendMinutes).ThenByDescending(mt => mt.Platform).ToList(); MarketTrends = PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.OrderBy(mt => mt.TrendMinutes).ThenByDescending(mt => mt.Platform).ToList();
BuildMarketTrendChartData(); BuildMarketTrendChartData();
BuildAssetDistributionData();
BuildProfitChartData(); BuildProfitChartData();
} }
private void BuildMarketTrendChartData() private void BuildMarketTrendChartData()
@ -91,10 +94,24 @@ namespace Monitor.Pages
marketTrendChangeSummaries = marketTrendChangeSummaries.OrderBy(m => m.TrendDateTime).ToList(); marketTrendChangeSummaries = marketTrendChangeSummaries.OrderBy(m => m.TrendDateTime).ToList();
// Get trend ticks for chart // Get trend ticks for chart
DateTime currentDateTime = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, DateTime.UtcNow.Hour, 0, 0); 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 currentDateTime = DateTime.UtcNow;
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours); DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
DateTime endDateTime = currentDateTime; 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) // Cache the result of SplitCamelCase(mt.Name)
string splitCamelCaseName = SystemHelper.SplitCamelCase(mt.Name); string splitCamelCaseName = SystemHelper.SplitCamelCase(mt.Name);
@ -108,14 +125,19 @@ namespace Monitor.Pages
MarketTrendChange mtc = marketTrendChangeSummaries[index]; MarketTrendChange mtc = marketTrendChangeSummaries[index];
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0; if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
trendValues.Add("{ x: new Date('" + tickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}"); // 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 // Add most recent tick
MarketTrendChange latestMtc = marketTrendChangeSummaries.Last(); MarketTrendChange latestMtc = marketTrendChangeSummaries.Last();
if (Double.IsInfinity(latestMtc.TrendChange)) latestMtc.TrendChange = 0; if (Double.IsInfinity(latestMtc.TrendChange)) latestMtc.TrendChange = 0;
trendValues.Add("{ x: new Date('" + latestMtc.TrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + latestMtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}");
// 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 // Use cached splitCamelCaseName
trendChartData.Add("{ key: '" + splitCamelCaseName + "', color: '" + lineColor + "', values: [" + string.Join(",\n", trendValues) + "] }"); trendChartData.Add("{ key: '" + splitCamelCaseName + "', color: '" + lineColor + "', values: [" + string.Join(",\n", trendValues) + "] }");
@ -124,25 +146,56 @@ namespace Monitor.Pages
} }
} }
} }
} }
TrendChartDataJSON = "[" + string.Join(",", trendChartData) + "]"; TrendChartDataJSON = "[" + string.Join(",", trendChartData) + "]";
} }
private void BuildProfitChartData() private void BuildProfitChartData()
{ {
StringBuilder profitPerDayJSON = new StringBuilder(); List<object> profitPerDayList = new List<object>();
if (PTData.DailyPNL.Count > 0) if (PTData.DailyPNL.Count > 0)
{ {
DateTime endDate = DateTime.UtcNow.Date; // 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<DateTime, DailyPNLData> 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 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; double previousDayCumulativeProfit = 0;
bool isFirstDay = true; bool isFirstDay = true;
for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) for (DateTime date = startDate; date <= endDate; date = date.AddDays(1))
{ {
DailyPNLData dailyPNL = PTData.DailyPNL.Find(ds => DateTime.ParseExact(ds.Date, "d-M-yyyy", CultureInfo.InvariantCulture) == date); // Use the dictionary to find the DailyPNLData for the date
if (dailyPNL != null) if (dailyPNLByDate.TryGetValue(date, out DailyPNLData dailyPNL))
{ {
if (isFirstDay) if (isFirstDay)
{ {
@ -153,17 +206,20 @@ namespace Monitor.Pages
// Calculate the profit for the current day // Calculate the profit for the current day
double profitFiat = Math.Round(dailyPNL.CumulativeProfitCurrency - previousDayCumulativeProfit, 2); double profitFiat = Math.Round(dailyPNL.CumulativeProfitCurrency - previousDayCumulativeProfit, 2);
// Add the data point to the JSON string // Add the data point to the list
if (profitPerDayJSON.Length > 0) profitPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = profitFiat });
{
profitPerDayJSON.Append(",\n");
}
profitPerDayJSON.Append("{x: new Date('" + date.ToString("yyyy-MM-dd") + "'), y: " + profitFiat.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}");
} }
previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency; previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency;
} }
} }
ProfitChartDataJSON = "[{key: 'Profit in " + PTData.Properties.Currency + "',color: '" + Constants.ChartLineColors[1] + "',values: [" + profitPerDayJSON.ToString() + "]}]"; // Convert the list to a JSON string using Newtonsoft.Json
ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] {
new {
key = "Profit in " + PTData.Properties.Currency,
color = Constants.ChartLineColors[1],
values = profitPerDayList
}
});
} }
} }
@ -180,7 +236,6 @@ namespace Monitor.Pages
foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog) foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog)
{ {
string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive); string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive);
// Aggregate totals // Aggregate totals
double leverage = dcaLogEntry.Leverage; double leverage = dcaLogEntry.Leverage;
if (leverage == 0) if (leverage == 0)