Merge pull request #337 from HojouFotytu/develop
2.7.1 update - Removal of Sales Log duplication - Various cosmetic changes Details: https://github.com/PTMagicians/PTMagic/pull/337
This commit is contained in:
commit
820c676955
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace Core.Main.DataObjects.PTMagicData
|
||||
{
|
||||
#region Settings Objects
|
||||
public class GeneralSettingsWrapper
|
||||
{
|
||||
public GeneralSettings GeneralSettings { get; set; }
|
||||
|
@ -21,7 +19,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public SecureSettings SecureSettings { get; set; }
|
||||
}
|
||||
|
||||
#region GeneralSettings
|
||||
|
||||
public class GeneralSettings
|
||||
{
|
||||
public Application Application { get; set; }
|
||||
|
@ -43,12 +41,10 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public string ProfitTrailerDefaultSettingName { get; set; } = "default";
|
||||
public int FloodProtectionMinutes { get; set; } = 15;
|
||||
public string Exchange { get; set; }
|
||||
public double StartBalance { get; set; } = 0;
|
||||
public string InstanceName { get; set; } = "PT Magic";
|
||||
public string TimezoneOffset { get; set; } = "+0:00";
|
||||
public string MainFiatCurrency { get; set; } = "USD";
|
||||
public string CoinMarketCapAPIKey { get; set; }
|
||||
public string FreeCurrencyConverterAPIKey { get; set; }
|
||||
//public string FreeCurrencyConverterAPIKey { get; set; }
|
||||
}
|
||||
|
||||
public class Monitor
|
||||
|
@ -61,9 +57,11 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public string AnalyzerChart { get; set; } = "";
|
||||
public int GraphIntervalMinutes { get; set; } = 60;
|
||||
public int GraphMaxTimeframeHours { get; set; } = 24;
|
||||
public int ProfitsMaxTimeframeDays { get; set; } = 60;
|
||||
public int RefreshSeconds { get; set; } = 30;
|
||||
public int BagAnalyzerRefreshSeconds { get; set; } = 5;
|
||||
public int BuyAnalyzerRefreshSeconds { get; set; } = 5;
|
||||
//public int MaxSalesRecords { get; set; } = 99999;
|
||||
public int MaxTopMarkets { get; set; } = 20;
|
||||
public int MaxDailySummaries { get; set; } = 10;
|
||||
public int MaxMonthlySummaries { get; set; } = 10;
|
||||
|
@ -105,9 +103,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public Int64 ChatId { get; set; }
|
||||
public bool SilentMode { get; set; } = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AnalyzerSettings
|
||||
public class AnalyzerSettings
|
||||
{
|
||||
public MarketAnalyzer MarketAnalyzer { get; set; }
|
||||
|
@ -130,6 +126,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
|
||||
[DefaultValue("Market")]
|
||||
public string TrendCurrency { get; set; } = "Market";
|
||||
public string SplitCamelCaseName { get; set; }
|
||||
|
||||
[DefaultValue(0)]
|
||||
public int MaxMarkets { get; set; } = 0;
|
||||
|
@ -243,18 +240,12 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
[DefaultValue(0)]
|
||||
public int HoursSinceTriggered { get; set; } = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SecureSettings
|
||||
public class SecureSettings
|
||||
{
|
||||
public string MonitorPassword { get; set; } = "";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Market Analyzer Objects
|
||||
public class Market
|
||||
{
|
||||
public int Position;
|
||||
|
@ -290,9 +281,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public DateTime FirstSeen = Constants.confMinDate;
|
||||
public DateTime LastSeen = Constants.confMaxDate;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Summary Objects
|
||||
|
||||
public class Summary
|
||||
{
|
||||
public string Version { get; set; } = "";
|
||||
|
@ -323,14 +312,26 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public string SellStrategy { get; set; } = "";
|
||||
public string MainMarket { get; set; } = "";
|
||||
public double MainMarketPrice { get; set; } = 0;
|
||||
public string MainFiatCurrency { get; set; } = "USD";
|
||||
public double MainFiatCurrencyExchangeRate { get; set; } = 1;
|
||||
private PropertiesData _propertiesData = new PropertiesData();
|
||||
public string MainFiatCurrency => _propertiesData.Currency;
|
||||
private MiscData _miscData = new MiscData();
|
||||
public double MainFiatCurrencyExchangeRate => _miscData.FiatConversionRate;
|
||||
public List<StrategySummary> BuyStrategies { get; set; } = new List<StrategySummary>();
|
||||
public List<StrategySummary> SellStrategies { get; set; } = new List<StrategySummary>();
|
||||
public List<StrategySummary> DCABuyStrategies { get; set; } = new List<StrategySummary>();
|
||||
public List<StrategySummary> DCASellStrategies { get; set; } = new List<StrategySummary>();
|
||||
}
|
||||
|
||||
public class PropertiesData
|
||||
{
|
||||
public string Currency { get; set; } = "";
|
||||
public bool Shorting { get; set; } = false;
|
||||
public bool Margin { get; set; } = false;
|
||||
public string UpTime { get; set; } = "";
|
||||
public int Port { get; set; } = 0;
|
||||
public bool IsLeverageExchange { get; set; } = false;
|
||||
public string BaseUrl { get; set; } = "";
|
||||
}
|
||||
|
||||
public class StrategySummary
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
|
@ -363,22 +364,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public List<StrategySummary> DCABuyStrategies { get; set; } = new List<StrategySummary>();
|
||||
public List<StrategySummary> DCASellStrategies { get; set; } = new List<StrategySummary>();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties Objects
|
||||
public class Properties
|
||||
{
|
||||
public string Currency { get; set; } = "";
|
||||
public bool Shorting { get; set; } = false;
|
||||
public bool Margin { get; set; } = false;
|
||||
public string UpTime { get; set; } = "";
|
||||
public int Port { get; set; } = 0;
|
||||
public bool IsLeverageExchange { get; set; } = false;
|
||||
public string BaseUrl { get; set; } = "";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Transaction Objects
|
||||
|
||||
public class Transaction
|
||||
{
|
||||
public string GUID { get; set; } = "";
|
||||
|
@ -396,9 +382,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
return result.DateTime;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SingleMarketSettingSummary Objects
|
||||
|
||||
public class SingleMarketSettingSummary
|
||||
{
|
||||
public string Market { get; set; } = "";
|
||||
|
@ -414,24 +398,93 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public double LastPrice { get; set; } = 0;
|
||||
public double Last24hVolume { get; set; } = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// public class SellLogData
|
||||
// {
|
||||
// public double SoldAmount { get; set; }
|
||||
// public DateTime SoldDate { get; set; }
|
||||
// public int BoughtTimes { get; set; }
|
||||
// public string Market { get; set; }
|
||||
// public double ProfitPercent { get; set; }
|
||||
// public double Profit { get; set; }
|
||||
// public double AverageBuyPrice { get; set; }
|
||||
// public double TotalCost { get; set; }
|
||||
// public double SoldPrice { get; set; }
|
||||
// public double SoldValue { get; set; }
|
||||
// public double TotalSales { get; set; }
|
||||
// }
|
||||
|
||||
#region Profit Trailer JSON Objects
|
||||
|
||||
public class SellLogData
|
||||
public class StatsData
|
||||
{
|
||||
public double SoldAmount { get; set; }
|
||||
public DateTime SoldDate { get; set; }
|
||||
public int BoughtTimes { get; set; }
|
||||
public string Market { get; set; }
|
||||
public double ProfitPercent { get; set; }
|
||||
public double Profit { get; set; }
|
||||
public double AverageBuyPrice { get; set; }
|
||||
public double TotalCost { get; set; }
|
||||
public double SoldPrice { get; set; }
|
||||
public double SoldValue { get; set; }
|
||||
public double SalesToday { get; set; }
|
||||
public double ProfitToday { get; set; }
|
||||
public double ProfitPercToday { get; set; }
|
||||
public double SalesYesterday { get; set; }
|
||||
public double ProfitYesterday { get; set; }
|
||||
public double ProfitPercYesterday { get; set; }
|
||||
public double SalesWeek { get; set; }
|
||||
public double ProfitWeek { get; set; }
|
||||
public double ProfitPercWeek { get; set; }
|
||||
public double SalesThisMonth { get; set; }
|
||||
public double ProfitThisMonth { get; set; }
|
||||
public double ProfitPercThisMonth { get; set; }
|
||||
public double SalesLastMonth { get; set; }
|
||||
public double ProfitLastMonth { get; set; }
|
||||
public double ProfitPercLastMonth { get; set; }
|
||||
public double TotalProfit { get; set; }
|
||||
public double TotalSales { get; set; }
|
||||
public double TotalProfitPerc { get; set; }
|
||||
public double FundingToday { get; set; }
|
||||
public double FundingYesterday { get; set; }
|
||||
public double FundingWeek { get; set; }
|
||||
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
|
||||
{
|
||||
public string Date { get; set; }
|
||||
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
|
||||
{
|
||||
public string Month { get; set; }
|
||||
public double TotalProfitCurrency { get; set; }
|
||||
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 DailyStatsData
|
||||
{
|
||||
public string Date { get; set; }
|
||||
public int TotalSales { get; set; }
|
||||
public int TotalBuys { get; set; }
|
||||
public double TotalProfit { get; set; }
|
||||
public double AvgProfit { get; set; }
|
||||
|
||||
public double AvgGrowth { get; set; }
|
||||
}
|
||||
public class PTStrategy
|
||||
{
|
||||
public string type { get; set; }
|
||||
|
@ -507,16 +560,17 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public List<Strategy> BuyStrategies { get; set; } = new List<Strategy>();
|
||||
}
|
||||
|
||||
public class SummaryData
|
||||
{
|
||||
public class MiscData
|
||||
{
|
||||
public double Balance { get; set; }
|
||||
public double StartBalance { get; set; }
|
||||
public double FiatConversionRate { get; set; }
|
||||
public double PairsValue { get; set; }
|
||||
public double DCAValue { get; set; }
|
||||
public double PendingValue { get; set; }
|
||||
public double DustValue { get; set; }
|
||||
public string Market { get; set; }
|
||||
public string TotalCurrentValue { get; set; }
|
||||
public string TimeZoneOffset { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -14,12 +14,11 @@ namespace Core.Main
|
|||
{
|
||||
public class PTMagic
|
||||
{
|
||||
|
||||
public PTMagic(LogHelper log)
|
||||
{
|
||||
this.Log = log;
|
||||
}
|
||||
|
||||
|
||||
#region Properties
|
||||
private LogHelper _log;
|
||||
private PTMagicConfiguration _systemConfiguration;
|
||||
|
@ -84,7 +83,10 @@ namespace Core.Main
|
|||
_systemConfiguration = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class IsAnalzyerRunning
|
||||
{
|
||||
private string _isAnalyzerRunning;
|
||||
}
|
||||
public System.Timers.Timer Timer
|
||||
{
|
||||
get
|
||||
|
@ -720,15 +722,6 @@ namespace Core.Main
|
|||
this.Log.DoLogInfo("No CoinMarketCap API KEY specified! That's ok, but you can't use CoinMarketCap in your settings.analyzer.json");
|
||||
}
|
||||
|
||||
// Check for CurrencyConverterApi Key
|
||||
if (!this.PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey.Equals(""))
|
||||
{
|
||||
this.Log.DoLogInfo("FreeCurrencyConverterApi KEY found");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Log.DoLogInfo("No FreeCurrencyConverterApi KEY specified. That's ok! But you can only use USD; apply for a key at: https://freecurrencyrates.com/en");
|
||||
}
|
||||
}
|
||||
catch (System.NullReferenceException)
|
||||
{
|
||||
|
@ -871,9 +864,6 @@ namespace Core.Main
|
|||
// Check for latest GitHub version
|
||||
this.CheckLatestGitHubVersion(this.LastRuntimeSummary.Version);
|
||||
|
||||
// Get latest main fiat currency exchange rate
|
||||
this.GetMainFiatCurrencyDetails();
|
||||
|
||||
// Load current PT files
|
||||
this.LoadCurrentProfitTrailerProperties();
|
||||
|
||||
|
@ -1127,35 +1117,6 @@ namespace Core.Main
|
|||
}
|
||||
}
|
||||
|
||||
private void GetMainFiatCurrencyDetails()
|
||||
{
|
||||
this.LastRuntimeSummary.MainFiatCurrency = this.LastMainFiatCurrency;
|
||||
this.LastRuntimeSummary.MainFiatCurrencyExchangeRate = this.LastMainFiatCurrencyExchangeRate;
|
||||
|
||||
if (this.LastFiatCurrencyCheck < DateTime.UtcNow.AddHours(-12) && !this.PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency.Equals("USD", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
this.LastRuntimeSummary.MainFiatCurrency = this.PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency;
|
||||
this.LastRuntimeSummary.MainFiatCurrencyExchangeRate = BaseAnalyzer.GetMainFiatCurrencyRate(this.PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency, this.PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey, this.Log);
|
||||
this.LastMainFiatCurrency = this.LastRuntimeSummary.MainFiatCurrency;
|
||||
this.LastMainFiatCurrencyExchangeRate = this.LastRuntimeSummary.MainFiatCurrencyExchangeRate;
|
||||
|
||||
this.LastFiatCurrencyCheck = DateTime.UtcNow;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
// Fallback to USD in case something went wrong
|
||||
this.Log.DoLogError("Fixer.io exchange rate check error: " + ex.Message);
|
||||
this.LastRuntimeSummary.MainFiatCurrency = "USD";
|
||||
this.LastRuntimeSummary.MainFiatCurrencyExchangeRate = 1;
|
||||
this.LastMainFiatCurrency = "USD";
|
||||
this.LastMainFiatCurrencyExchangeRate = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get current PT properties
|
||||
private void LoadCurrentProfitTrailerProperties()
|
||||
{
|
||||
|
|
|
@ -437,7 +437,7 @@ namespace Core.ProfitTrailer
|
|||
}
|
||||
else
|
||||
{
|
||||
strategyText += "<span class=\"label label-warning\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">FORM</span> ";
|
||||
strategyText += "";
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -64,13 +64,16 @@
|
|||
|
||||
var loadDashboardBottom = function () {
|
||||
//destroy all d3 svg graph to avoid memory leak
|
||||
$(".nvtooltip").remove();
|
||||
$("svg > *").remove();
|
||||
$("svg").remove();
|
||||
nv.charts = {};
|
||||
nv.graphs = [];
|
||||
nv.logs = {};
|
||||
nv.tooltip = {};
|
||||
setTimeout(function()
|
||||
{
|
||||
$(".nvtooltip").remove();
|
||||
$("svg > *").remove();
|
||||
$("svg").remove();
|
||||
nv.charts = {};
|
||||
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.
|
||||
if (intervalDashboardBottom != null)
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<p><input type="checkbox" name="cbRememberMe"/> <label for="cbRememberMe">Stay logged in</label></p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Monitor.Pages
|
|||
{
|
||||
HttpContext.Session.SetString("LoggedIn" + PTMagicConfiguration.GeneralSettings.Monitor.Port.ToString(), DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"));
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.IsPasswordProtected = true;
|
||||
PTMagicConfiguration.WriteGeneralSettings();
|
||||
//PTMagicConfiguration.WriteGeneralSettings();
|
||||
if (cbRememberMe != null)
|
||||
{
|
||||
if (cbRememberMe.Equals("on", StringComparison.InvariantCultureIgnoreCase))
|
||||
|
|
|
@ -155,14 +155,14 @@ else
|
|||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trend Averages at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b></h4>
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange </b><i class="fa fa-info-circle text-muted" style="font-size x-small" 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 at @Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes intervals, in general settings."></i></h4>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-right">Markets</th>
|
||||
<th class="text-right">Timeframe</th>
|
||||
<th class="text-right">Threshold %</th>
|
||||
<th class="text-right">Threshold <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are excluded from the trend average."></i></th>
|
||||
<th class="text-right">Change</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -190,9 +190,9 @@ else
|
|||
}
|
||||
else
|
||||
{
|
||||
<td class="text-right">@marketTrend.TrendThreshold</td>
|
||||
<td class="text-right">@marketTrend.TrendThreshold %</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@trendChangeOutput%</td>
|
||||
<td class="text-right text-autocolor bold-text" >@trendChangeOutput%</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using Core.Main;
|
||||
using Core.Helper;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Monitor.Pages
|
||||
{
|
||||
|
@ -11,6 +12,7 @@ namespace Monitor.Pages
|
|||
{
|
||||
public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
|
||||
public string TrendChartDataJSON = "";
|
||||
public double DataHours { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
|
@ -28,77 +30,85 @@ namespace Monitor.Pages
|
|||
|
||||
private void BuildMarketTrendChartData()
|
||||
{
|
||||
if (MarketTrends.Count > 0)
|
||||
{
|
||||
TrendChartDataJSON = "[";
|
||||
int mtIndex = 0;
|
||||
foreach (MarketTrend mt in MarketTrends)
|
||||
List<string> trendChartData = new List<string>();
|
||||
if (MarketTrends.Count > 0)
|
||||
{
|
||||
if (mt.DisplayGraph)
|
||||
{
|
||||
string lineColor = "";
|
||||
if (mtIndex < Constants.ChartLineColors.Length)
|
||||
|
||||
int mtIndex = 0;
|
||||
foreach (MarketTrend mt in MarketTrends)
|
||||
{
|
||||
lineColor = Constants.ChartLineColors[mtIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
lineColor = Constants.ChartLineColors[mtIndex - 20];
|
||||
}
|
||||
|
||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||
{
|
||||
List<MarketTrendChange> marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name];
|
||||
|
||||
if (marketTrendChangeSummaries.Count > 0)
|
||||
{
|
||||
if (!TrendChartDataJSON.Equals("[")) TrendChartDataJSON += ",";
|
||||
|
||||
TrendChartDataJSON += "{";
|
||||
TrendChartDataJSON += "key: '" + SystemHelper.SplitCamelCase(mt.Name) + "',";
|
||||
TrendChartDataJSON += "color: '" + lineColor + "',";
|
||||
TrendChartDataJSON += "values: [";
|
||||
|
||||
// Get trend ticks for chart
|
||||
DateTime currentDateTime = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, DateTime.UtcNow.Hour, 0, 0);
|
||||
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
||||
DateTime endDateTime = currentDateTime;
|
||||
int trendChartTicks = 0;
|
||||
for (DateTime tickTime = startDateTime; tickTime <= endDateTime; tickTime = tickTime.AddMinutes(PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes))
|
||||
if (mt.DisplayGraph)
|
||||
{
|
||||
List<MarketTrendChange> tickRange = marketTrendChangeSummaries.FindAll(m => m.TrendDateTime >= tickTime).OrderBy(m => m.TrendDateTime).ToList();
|
||||
if (tickRange.Count > 0)
|
||||
{
|
||||
MarketTrendChange mtc = tickRange.First();
|
||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
||||
string lineColor = mtIndex < Constants.ChartLineColors.Length
|
||||
? Constants.ChartLineColors[mtIndex]
|
||||
: Constants.ChartLineColors[mtIndex - 20];
|
||||
|
||||
TrendChartDataJSON += "{ x: new Date('" + tickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
trendChartTicks++;
|
||||
}
|
||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||
{
|
||||
List<MarketTrendChange> marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name];
|
||||
|
||||
if (marketTrendChangeSummaries.Count > 0)
|
||||
{
|
||||
List<string> trendValues = new List<string>();
|
||||
|
||||
// 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))
|
||||
{
|
||||
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<MarketTrendChange>.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
|
||||
List<MarketTrendChange> latestTickRange = marketTrendChangeSummaries.OrderByDescending(m => m.TrendDateTime).ToList();
|
||||
if (latestTickRange.Count > 0)
|
||||
{
|
||||
MarketTrendChange mtc = latestTickRange.First();
|
||||
if (trendChartTicks > 0) TrendChartDataJSON += ",\n";
|
||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
||||
|
||||
TrendChartDataJSON += "{ x: new Date('" + mtc.TrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
}
|
||||
|
||||
TrendChartDataJSON += "]";
|
||||
TrendChartDataJSON += "}";
|
||||
|
||||
mtIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TrendChartDataJSON += "]";
|
||||
}
|
||||
TrendChartDataJSON = "[" + string.Join(",", trendChartData) + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@page
|
||||
@model SalesAnalyzer
|
||||
@using System.Globalization
|
||||
@{
|
||||
ViewData["Title"] = "";
|
||||
}
|
||||
|
@ -19,14 +20,11 @@
|
|||
<thead>
|
||||
<tr>
|
||||
@{
|
||||
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;
|
||||
}
|
||||
<th class="m-t-0 header-title text-left">Total Account Value: <text class="text-autocolor"> @totalCurrentValueString @Model.Summary.MainMarket </text> <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is based on your sales history, entries on the Transactions page and any currently held positions."></i></small></th>
|
||||
<th class="text-right">Starting Value: <text class="text-autocolor"> @Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance @Model.Summary.MainMarket </text> <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is the starting value found in your settings file"></i></small></th>
|
||||
<th class="m-t-0 header-title text-left">Total Current Value: <text class="text-autocolor"> @totalCurrentValueString @Model.Summary.MainMarket </text> <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is based on the Total Current Value reported by Profit Trailer."></i></small></th>
|
||||
<th class="text-right">Starting Value: <text class="text-autocolor"> @Model.MiscData.StartBalance @Model.Summary.MainMarket </text> <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is the starting value set in your PT account settings."></i></small></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
@ -34,78 +32,129 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title text-center">Cumulative Profits <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This value is based on your sales history"></i></small></h4>
|
||||
<div class="balance-chart">
|
||||
<svg style="height:350px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Model.PTData.SellLog.Count == 0) {
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">No Sales!</h4>
|
||||
<div class="col-md-6">
|
||||
<div class="card-box px-2" style="height:320px;">
|
||||
<h4 class="m-t-0 header-title"><b>Cumulative Profits</b>
|
||||
@if (!Model.CumulativeProfitChartDataJSON.Equals("")) {
|
||||
<div class="cumulative-profit-chart">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
</div>
|
||||
} else {
|
||||
<p>Unable to load graph, no sales data found.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Sorry, but your Profit Trailer did not sell anything so far. Please wait for the bot to have at least one sale and you will start seeing data in here.</p>
|
||||
<div class="col-md-6">
|
||||
<div class="card-box px-2" style="height:320px;">
|
||||
<h4 class="m-t-0 header-title"><b>Daily TCV</b>
|
||||
@if (!Model.TCVChartDataJSON.Equals("")) {
|
||||
<div class="TCV-chart">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
</div>
|
||||
} else {
|
||||
<p>Unable to load graph, no sales data found.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} else {
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card-box px-3" style="height:340px;">
|
||||
@{
|
||||
var days = Math.Min(Model.DailyStats.Count, 30);
|
||||
}
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Daily Buys/Sales (@days Days) </b>
|
||||
<div class="sales-chart">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card-box px-3" style="height:340px;">
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Daily Profit (All Time) </b>
|
||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||
<div class="profit-chart">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
</div>
|
||||
} else {
|
||||
<p>Unable to load graph, no sales data found.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Sales Analysis</h4>
|
||||
@{
|
||||
double totalProfit = 0;
|
||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
||||
double totalProfitFiat = Math.Round(totalProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double percentGain = Math.Round(totalProfit / Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance * 100, 2);
|
||||
double avgDailyGain = Model.DailyGains.Values.Average(dg => dg);
|
||||
double avgMonthlyGain = Model.MonthlyGains.Values.Average(dg => dg);
|
||||
string percentGainText = percentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
if (Model.PTData.TransactionData.Transactions.Count > 0) {
|
||||
percentGainText = "<i class=\"fa fa-info-circle text-muted\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"You have added at least one manual transaction, so the total gain percentage cannot be calculated.\"></i>";
|
||||
}
|
||||
}
|
||||
int totalDays = Model.PTData.DailyPNL.Count;
|
||||
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 = ((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;
|
||||
|
||||
var MonthlyAveragesResult = Model.MonthlyAverages(Model.PTData.MonthlyStats, Model.PTData.DailyPNL);
|
||||
string startDate = MonthlyAveragesResult.startDate.ToString("d");
|
||||
string endDate = MonthlyAveragesResult.endDate.ToString("d");
|
||||
double totalMonths = Math.Round(MonthlyAveragesResult.totalMonths, 1);
|
||||
double avgMonthlySales = @Math.Round(totalSales / totalMonths, 1);
|
||||
double avgMonthlyProfit = totalProfit / totalMonths;
|
||||
double avgMonthlyGain = totalPercentGain / totalMonths;
|
||||
double avgMonthlyFunding = totalFundingFees / totalMonths;
|
||||
}
|
||||
<h4 class="m-t-0 header-title" style="display: inline;">Averages</h4> <span style="font-size: x-small"> (@startDate - @endDate)</span>
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-right">Total</th>
|
||||
<th class="text-right">AVG/Day</th>
|
||||
<th class="text-right">AVG/Month</th>
|
||||
<th class="text-right">AVG/Day</span></th>
|
||||
<th class="text-right">AVG/Month</span> <small><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top"
|
||||
title="Months are based on the size of the calendar months. Weighted to compensate for partial months."></i></small></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Sales</th>
|
||||
<td class="text-right">@Model.PTData.SellLog.Count</td>
|
||||
<td class="text-right">@Math.Round((double)Model.PTData.SellLog.Count / (double)Model.PTData.SellLog.GroupBy(d => d.SoldDate.Date).ToList().Count, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right">@Math.Round((double)Model.PTData.SellLog.Count / (double)Model.PTData.SellLog.GroupBy(d => d.SoldDate.Date.ToString("yyyy-MM")).ToList().Count, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right">@totalSales</td>
|
||||
<td class="text-right">@avgDailySales</td>
|
||||
<td class="text-right">@avgMonthlySales</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Profit</th>
|
||||
<th>@Model.PTData.Misc.Market</th>
|
||||
<td class="text-right text-autocolor">@totalProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round(totalProfit / (double)Model.PTData.SellLog.GroupBy(d => d.SoldDate.Date).ToList().Count, 8).ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round(totalProfit / (double)Model.PTData.SellLog.GroupBy(d => d.SoldDate.Date.ToString("yyyy-MM")).ToList().Count, 8).ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round(totalProfit / totalDays, 8).ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@avgMonthlyProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
@if(Model.PropertiesData.IsLeverageExchange)
|
||||
{
|
||||
<tr>
|
||||
<th>Funding</th>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(totalFundingFees,8).ToString("#0.00000000", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(totalFundingFees / totalDays,8).ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(totalFundingFees / totalMonths,8).ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th>@Model.PTData.Properties.Currency</th>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(totalProfitFiat,0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(totalProfitFiat / totalDays, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(totalProfitFiat / totalMonths, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Profit USD</th>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + totalProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + Math.Round(totalProfitFiat / (double)Model.PTData.SellLog.GroupBy(d => d.SoldDate.Date).ToList().Count, 8).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + Math.Round(totalProfitFiat / (double)Model.PTData.SellLog.GroupBy(d => d.SoldDate.Date.ToString("yyyy-MM")).ToList().Count, 8).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>% Gain</th>
|
||||
<td class="text-right text-autocolor">@Html.Raw(percentGainText)</td>
|
||||
<td class="text-right text-autocolor">@avgDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td class="text-right text-autocolor">@avgMonthlyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<th>Gain</th>
|
||||
<td class="text-right text-autocolor">@totalPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
<td class="text-right text-autocolor">@avgDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
<td class="text-right text-autocolor">@avgMonthlyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -115,46 +164,52 @@
|
|||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
@{
|
||||
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);
|
||||
}
|
||||
<h4 class="m-t-0 header-title">Balance Prediction <small><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The balance prediction is based on your daily average gain of @avgDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% and your current approximate balance of @currentTotalBalance.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))"></i></small></h4>
|
||||
<h4 class="m-t-0 header-title">TCV Prediction <small><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The balance prediction is based on your daily average gain of @avgDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))% and your current TCV of @totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))"></i></small></h4>
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-right"></th>
|
||||
<th class="text-right">Est. Balance</th>
|
||||
<th class="text-right">Est. @Model.Summary.MainFiatCurrency Value</th>
|
||||
<th class="text-right">Est. Gain</th>
|
||||
<th class="text-right">@Model.PTData.Misc.Market</th>
|
||||
<th class="text-right">@Model.PTData.Properties.Currency</th>
|
||||
<th class="text-right">Gain</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>1 month</th>
|
||||
<th>1 Week</th>
|
||||
<td class="text-right text-autocolor">@estimatedBalance1Week.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(estimatedBalance1Week * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance1Week - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1 Month</th>
|
||||
<td class="text-right text-autocolor">@estimatedBalance1Month.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + Math.Round(estimatedBalance1Month * Model.Summary.MainMarketPrice, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance1Month - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(estimatedBalance1Month * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance1Month - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>3 months</th>
|
||||
<th>3 Months</th>
|
||||
<td class="text-right text-autocolor">@estimatedBalance3Months.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + Math.Round(estimatedBalance3Months * Model.Summary.MainMarketPrice, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance3Months - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(estimatedBalance3Months * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance3Months - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>6 months</th>
|
||||
<th>6 Months</th>
|
||||
<td class="text-right text-autocolor">@estimatedBalance6Months.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + Math.Round(estimatedBalance6Months * Model.Summary.MainMarketPrice, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance6Months - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(estimatedBalance6Months * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance6Months - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1 year</th>
|
||||
<th>1 Year</th>
|
||||
<td class="text-right text-autocolor">@estimatedBalance1Year.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + Math.Round(estimatedBalance1Year * Model.Summary.MainMarketPrice, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance1Year - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Math.Round(estimatedBalance1Year * Model.MiscData.FiatConversionRate, 0).ToString("#,#0", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round((estimatedBalance1Year - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -162,53 +217,47 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<div class="trades-chart">
|
||||
<svg style="height:220px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<div class="profit-chart">
|
||||
<svg style="height:220px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Last @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDailySummaries days</h4>
|
||||
@{
|
||||
var maxDays = Math.Min(Model.DailyStats.Count, Math.Min(Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDailySummaries, 30));
|
||||
}
|
||||
<h4 class="m-t-0 header-title">Last @maxDays Days</h4>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Day</th>
|
||||
<th class="text-right">Buys</th>
|
||||
<th class="text-right">Sales</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainMarket</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainFiatCurrency</th>
|
||||
<th class="text-right">% Gain</th>
|
||||
<th class="text-right">Profit @Model.PTData.Properties.Currency</th>
|
||||
<th class="text-right">Gain</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (DateTime salesDate = Model.DateTimeNow.DateTime.Date; salesDate >= Model.DateTimeNow.DateTime.AddDays(-Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDailySummaries) && salesDate >= Model.MinSellLogDate; salesDate = salesDate.AddDays(-1)) {
|
||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> salesDateSales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date == salesDate);
|
||||
double salesDateProfit = 0;
|
||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
||||
double salesDateProfitFiat = Math.Round(salesDateProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double salesDateStartBalance = Model.PTData.GetSnapshotBalance(salesDate);
|
||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
||||
@{
|
||||
for (int i = 0; i < maxDays; i++)
|
||||
{
|
||||
DateTime salesDate = DateTime.ParseExact(Model.PTData.DailyStats[i].Date, "d-M-yyyy", CultureInfo.InvariantCulture);
|
||||
var buys = Model.PTData.DailyStats[i].TotalBuys;
|
||||
var sales = Model.PTData.DailyStats[i].TotalSales;
|
||||
var profit = Model.PTData.DailyStats[i].TotalProfit;
|
||||
var avgProfit = Model.PTData.DailyStats[i].AvgProfit;
|
||||
var profitFiat = Math.Round(profit * Model.PTData.Misc.FiatConversionRate, 0);
|
||||
|
||||
<tr>
|
||||
<td><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)_get/SalesList/?d=@salesDate.ToString("yyyy-MM-dd")" data-remote="false" data-toggle="modal" data-target="#salesList">@salesDate.ToShortDateString()</a></td>
|
||||
<td class="text-right">@salesDateSales.Count</td>
|
||||
<td class="text-right text-autocolor">@salesDateProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + salesDateProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@salesDateGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td>@salesDate.ToString("yyyy-MM-dd")</td>
|
||||
<td class="text-right text-autocolor"">@buys</td>
|
||||
<td class="text-right text-autocolor"">@sales</td>
|
||||
<td class="text-right text-autocolor">@profit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Math.Round(profitFiat,0).ToString("#,#0", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@avgProfit.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -217,110 +266,83 @@
|
|||
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Last @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries months</h4>
|
||||
|
||||
@{
|
||||
var maxMonths = Math.Min(Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries, Model.MonthlyStats.Count);
|
||||
}
|
||||
<h4 class="m-t-0 header-title">Last @maxMonths months</h4>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Month</th>
|
||||
<th class="text-right">Sales</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainMarket</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainFiatCurrency</th>
|
||||
<th class="text-right">% Gain</th>
|
||||
<th class="text-right">AVG %/Day</th>
|
||||
<th class="text-right">Profit @Model.PTData.Properties.Currency</th>
|
||||
<th class="text-right">Growth</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
DateTime minSellLogMonthDate = new DateTime(Model.MinSellLogDate.Year, Model.MinSellLogDate.Month, 1).Date;
|
||||
DateTime salesMonthStartDate = new DateTime(Model.DateTimeNow.DateTime.Year, Model.DateTimeNow.DateTime.Month, 1).Date;
|
||||
}
|
||||
@for (DateTime salesMonthDate = salesMonthStartDate.Date; salesMonthDate >= Model.DateTimeNow.DateTime.AddMonths(-Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries) && salesMonthDate >= minSellLogMonthDate; salesMonthDate = salesMonthDate.AddMonths(-1)) {
|
||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> salesMonthSales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date.Month == salesMonthDate.Month && sl.SoldDate.Date.Year == salesMonthDate.Year);
|
||||
double salesDateProfit = 0;
|
||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
||||
double salesDateProfitFiat = Math.Round(salesDateProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double salesDateStartBalance = Model.PTData.GetSnapshotBalance(salesMonthDate);
|
||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
||||
double salesDateAVGDailyGain = 0;
|
||||
double monthDailyProfit = 0;
|
||||
int days = 0;
|
||||
for (int d = 1; d <= DateTime.DaysInMonth(salesMonthDate.Year, salesMonthDate.Month); d++) {
|
||||
DateTime monthDay = salesMonthDate.AddDays(-salesMonthDate.Day + d);
|
||||
if (monthDay <= Model.DateTimeNow) {
|
||||
days++;
|
||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> monthDaySales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date == monthDay.Date);
|
||||
double monthDayProfit = 0;
|
||||
monthDayProfit = monthDaySales.Sum(sl => sl.Profit);
|
||||
double monthDayStartBalance = Model.PTData.GetSnapshotBalance(monthDay);
|
||||
monthDailyProfit += Math.Round(monthDayProfit / monthDayStartBalance * 100, 2);
|
||||
}
|
||||
for (int i = 0; i < maxMonths; i++)
|
||||
{
|
||||
DateTime monthDate = DateTime.ParseExact(Model.PTData.MonthlyStats[i].Month, "M-yyyy", CultureInfo.InvariantCulture);
|
||||
string monthName = monthDate.ToString("MMMM", CultureInfo.InvariantCulture);
|
||||
var sales = Model.PTData.MonthlyStats[i].TotalSales;
|
||||
var profit = Model.PTData.MonthlyStats[i].TotalProfitCurrency;
|
||||
var profitFiat = Math.Round(profit * Model.PTData.Misc.FiatConversionRate, 0);
|
||||
var growth = Math.Round(Model.PTData.MonthlyStats[i].AvgGrowth,2);
|
||||
<tr>
|
||||
<td>@monthName</td>
|
||||
<td class="text-right text-autocolor">@sales</td>
|
||||
<td class="text-right text-autocolor">@profit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@profitFiat</td>
|
||||
<td class="text-right text-autocolor">@growth %</td>
|
||||
</tr>
|
||||
}
|
||||
salesDateAVGDailyGain = Math.Round(monthDailyProfit / days, 2);
|
||||
<tr>
|
||||
<td><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)_get/SalesList/?m=@salesMonthDate.ToString("yyyy-MM")" data-remote="false" data-toggle="modal" data-target="#salesList">@salesMonthDate.ToString("MMMM", new System.Globalization.CultureInfo("en-US"))</a></td>
|
||||
<td class="text-right text-autocolor">@salesMonthSales.Count</td>
|
||||
<td class="text-right text-autocolor">@salesDateProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + salesDateProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@salesDateGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td class="text-right text-autocolor">@salesDateAVGDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
@* <div class="col-md-6"> *@
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title"><b>Top @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets Sales Market Analysis</b></h4>
|
||||
<h4 class="m-t-0 header-title"><b>Top @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets Sales Markets</b></h4>
|
||||
<table class="tablesaw table m-b-0" data-tablesaw-sortable data-tablesaw-sortable-switch>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" data-tablesaw-priority="persist" data-tablesaw-sortable-col data-tablesaw-sortable-default-col>Rank</th>
|
||||
<th scope="col" data-tablesaw-sortable-col>Market</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Profit @Model.PTData.Misc.Market</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Sales</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Profit @Model.Summary.MainMarket</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Profit @Model.Summary.MainFiatCurrency</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Profit @Model.Summary.MainFiatCurrency/Trade</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Profit %/Trade</th>
|
||||
<th scope="col" class="text-right" data-tablesaw-sortable-col>Avg/Trade</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
var topMarkets = Model.PTData.SellLog.GroupBy(m => m.Market).Select(mg => mg.Sum(m => m.Profit));
|
||||
int marketRank = 0;
|
||||
}
|
||||
@foreach (KeyValuePair<string, double> 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);
|
||||
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);
|
||||
<tr>
|
||||
<td>@marketRank</td>
|
||||
<td><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform, Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, marketData.Key, Model.Summary.MainMarket)" target="_blank">@marketData.Key</a></td>
|
||||
<td class="text-right">@trades</td>
|
||||
<td class="text-right text-autocolor-saw">@marketData.Value.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor-saw">@profitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) @Model.Summary.MainFiatCurrency</td>
|
||||
<td class="text-right text-autocolor-saw">@profitFiatPerTrade.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) @Model.Summary.MainFiatCurrency</td>
|
||||
<td class="text-right text-autocolor-saw">@Model.PTData.SellLog.FindAll(m => m.Market == marketData.Key).Average(p => p.ProfitPercent).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
<td>@rank</td>
|
||||
<td><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform, Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, coin, Model.PTData.Misc.Market)" target="_blank">@coin</a></td>
|
||||
<td class="text-right text-autocolor-saw">@profit</td>
|
||||
<td class="text-right">@sales</td>
|
||||
<td class="text-right text-autocolor-saw">@avg </td>
|
||||
</tr>
|
||||
rank++;
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@* </div> *@
|
||||
|
||||
<div id="salesList" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true" style="display: none;">
|
||||
<div class="modal-dialog modal-full">
|
||||
<div class="modal-content">
|
||||
<i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
|
@ -343,60 +365,198 @@
|
|||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/datatables/buttons.print.min.js"></script>
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/datatables/buttons.colVis.min.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
nv.addGraph(function () {
|
||||
var lineChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
/**/
|
||||
var chartData = @Html.Raw(Model.TradesChartDataJSON);
|
||||
/**/
|
||||
lineChart.useInteractiveGuideline(true);
|
||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
||||
lineChart.yAxis.axisLabel('Daily Sales').tickFormat(d3.format(','));
|
||||
d3.select('.trades-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
||||
nv.utils.windowResize(lineChart.update);
|
||||
return lineChart;
|
||||
});
|
||||
$('[role="tooltip"]').remove();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
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;
|
||||
});
|
||||
var salesChart; // Keep a reference to the chart
|
||||
var salesData; // Keep a reference to the data
|
||||
|
||||
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;
|
||||
});
|
||||
@if (!Model.SalesChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
salesChart = nv.models.multiBarChart();
|
||||
var height = 300;
|
||||
salesChart.groupSpacing(0.5);
|
||||
salesChart.showControls(false);
|
||||
//salesChart.useInteractiveGuideline(true);
|
||||
salesChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
salesChart.yAxis.axisLabel('').tickFormat(d3.format(',.2f'));
|
||||
|
||||
$("#salesList").on("show.bs.modal", function (e) {
|
||||
$(this).find(".modal-content").html('<i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>');
|
||||
var link = $(e.relatedTarget);
|
||||
$(this).find(".modal-content").load(link.attr("href"), function () {
|
||||
$('.text-autocolor').autocolor(false);
|
||||
salesData = @Html.Raw(Model.SalesChartDataJSON);
|
||||
|
||||
d3.select('.sales-chart svg')
|
||||
.datum(salesData)
|
||||
.transition().duration(0)
|
||||
.call(salesChart);
|
||||
|
||||
// Add mouseleave, and mousemove event listeners to hide tooltip
|
||||
d3.select('.sales-chart').on('mouseleave', function() {
|
||||
d3.select('.nvtooltip').style('opacity', 0);
|
||||
});
|
||||
|
||||
d3.select('body').on('mousemove', function() {
|
||||
var chartBounds = d3.select('.sales-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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(salesChart.update);
|
||||
return salesChart;
|
||||
});
|
||||
});
|
||||
</text>
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
$('[role="tooltip"]').remove();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
var cumulativeProfitChart; // Keep a reference to the chart
|
||||
var cumulativeProfitData; // Keep a reference to the data
|
||||
|
||||
@if (!Model.CumulativeProfitChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
cumulativeProfitChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
cumulativeProfitChart.useInteractiveGuideline(true);
|
||||
cumulativeProfitChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
cumulativeProfitChart.yAxis.axisLabel('').tickFormat(d3.format(',.2f'));
|
||||
|
||||
cumulativeProfitData = @Html.Raw(Model.CumulativeProfitChartDataJSON);
|
||||
|
||||
d3.select('.cumulative-profit-chart svg')
|
||||
.datum(cumulativeProfitData)
|
||||
.transition().duration(0)
|
||||
.call(cumulativeProfitChart);
|
||||
|
||||
// Add mouseleave, and mousemove event listeners to hide tooltip
|
||||
d3.select('.cumulative-profit-chart').on('mouseleave', function() {
|
||||
d3.select('.nvtooltip').style('opacity', 0);
|
||||
});
|
||||
|
||||
d3.select('body').on('mousemove', function() {
|
||||
var chartBounds = d3.select('.cumulative-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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(cumulativeProfitChart.update);
|
||||
return cumulativeProfitChart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
$('[role="tooltip"]').remove();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
var TCVChart; // Keep a reference to the chart
|
||||
var TCVData; // Keep a reference to the data
|
||||
|
||||
@if (!Model.TCVChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
TCVChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
TCVChart.useInteractiveGuideline(true);
|
||||
TCVChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
TCVChart.yAxis.axisLabel('').tickFormat(d3.format(',.2f'));
|
||||
|
||||
TCVData = @Html.Raw(Model.TCVChartDataJSON);
|
||||
|
||||
d3.select('.TCV-chart svg')
|
||||
.datum(TCVData)
|
||||
.transition().duration(0)
|
||||
.call(TCVChart);
|
||||
|
||||
// Add mouseleave, and mousemove event listeners to hide tooltip
|
||||
d3.select('.TCV-chart').on('mouseleave', function() {
|
||||
d3.select('.nvtooltip').style('opacity', 0);
|
||||
});
|
||||
|
||||
d3.select('body').on('mousemove', function() {
|
||||
var chartBounds = d3.select('.TCV-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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(TCVChart.update);
|
||||
return TCVChart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
$('[role="tooltip"]').remove();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
var profitChart; // Keep a reference to the chart
|
||||
var profitData; // Keep a reference to the data
|
||||
|
||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
profitChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
profitChart.useInteractiveGuideline(true);
|
||||
profitChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
profitChart.yAxis.axisLabel('').tickFormat(d3.format(',.2f'));
|
||||
|
||||
profitData = @Html.Raw(Model.ProfitChartDataJSON);
|
||||
|
||||
d3.select('.profit-chart svg')
|
||||
.datum(profitData)
|
||||
.transition().duration(0)
|
||||
.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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(profitChart.update);
|
||||
return profitChart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
}
|
||||
|
|
|
@ -1,146 +1,352 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Core.Main;
|
||||
using Core.Helper;
|
||||
using System.Globalization;
|
||||
using Core.Main.DataObjects;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
|
||||
|
||||
namespace Monitor.Pages
|
||||
{
|
||||
public class SalesAnalyzer : _Internal.BasePageModelSecure
|
||||
{
|
||||
{
|
||||
public ProfitTrailerData PTData = null;
|
||||
public MiscData MiscData { get; set; }
|
||||
public PropertiesData PropertiesData { get; set; }
|
||||
public StatsData StatsData { get; set; }
|
||||
public List<DailyPNLData> DailyPNL { get; set; }
|
||||
public List<DailyTCVData> DailyTCV { get; set; }
|
||||
public List<ProfitablePairsData> ProfitablePairs { get; set; }
|
||||
public List<DailyStatsData> DailyStats { get; set; }
|
||||
public int ProfitDays { get; set; }
|
||||
public int TCVDays { get; set; }
|
||||
public int SalesDays { get; set; }
|
||||
public List<MonthlyStatsData> MonthlyStats { get; set; }
|
||||
|
||||
public string TradesChartDataJSON = "";
|
||||
public string CumulativeProfitChartDataJSON = "";
|
||||
public string TCVChartDataJSON = "";
|
||||
public string ProfitChartDataJSON = "";
|
||||
public string BalanceChartDataJSON = "";
|
||||
public string SalesChartDataJSON = "";
|
||||
public IEnumerable<KeyValuePair<string, double>> TopMarkets = null;
|
||||
public DateTime MinSellLogDate = Constants.confMinDate;
|
||||
public Dictionary<DateTime, double> DailyGains = new Dictionary<DateTime, double>();
|
||||
public Dictionary<DateTime, double> MonthlyGains = new Dictionary<DateTime, double>();
|
||||
//public DateTime MinSellLogDate = Constants.confMinDate;
|
||||
public DateTimeOffset DateTimeNow = Constants.confMinDate;
|
||||
public double totalCurrentValue = 0;
|
||||
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
BindData();
|
||||
BuildTCV();
|
||||
}
|
||||
|
||||
private void BindData()
|
||||
{
|
||||
PTData = this.PtDataObject;
|
||||
|
||||
MiscData = this.PTData.Misc;
|
||||
PropertiesData = this.PTData.Properties;
|
||||
StatsData = this.PTData.Stats;
|
||||
MonthlyStats = this.PTData.MonthlyStats;
|
||||
DailyPNL = this.PTData.DailyPNL;
|
||||
DailyTCV = this.PTData.DailyTCV;
|
||||
ProfitablePairs = this.PTData.ProfitablePairs;
|
||||
DailyStats = this.PTData.DailyStats;
|
||||
|
||||
// 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();
|
||||
}
|
||||
private void BuildTopMarkets()
|
||||
|
||||
private void BuildTCVChartData()
|
||||
{
|
||||
var markets = PTData.SellLog.GroupBy(m => m.Market);
|
||||
Dictionary<string, double> topMarketsDic = new Dictionary<string, double>();
|
||||
foreach (var market in markets)
|
||||
{
|
||||
double totalProfit = 0;
|
||||
totalProfit = PTData.SellLog.FindAll(m => m.Market == market.Key).Sum(m => m.Profit);
|
||||
topMarketsDic.Add(market.Key, totalProfit);
|
||||
}
|
||||
TopMarkets = new SortedDictionary<string, double>(topMarketsDic).OrderByDescending(m => m.Value).Take(PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets);
|
||||
List<object> TCVPerDayList = new List<object>();
|
||||
|
||||
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<DateTime, DailyTCVData> 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<object> profitPerDayList = new List<object>();
|
||||
|
||||
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<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 = 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<object> profitPerDayList = new List<object>();
|
||||
|
||||
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<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 = 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<MonthlyStatsData> monthlyStats, List<DailyPNLData> dailyPNL)
|
||||
{
|
||||
double totalMonths = 0;
|
||||
// Get the exact start and end dates of sales data
|
||||
DateTime startDate = dailyPNL.Min(d => DateTime.ParseExact(d.Date, "d-M-yyyy", CultureInfo.InvariantCulture));
|
||||
DateTime endDate = dailyPNL.Max(d => DateTime.ParseExact(d.Date, "d-M-yyyy", CultureInfo.InvariantCulture));
|
||||
|
||||
int daysInFirstMonth = DateTime.DaysInMonth(startDate.Year, startDate.Month) - startDate.Day + 1;
|
||||
int daysInLastMonth = endDate.Day;
|
||||
//Console.WriteLine("Start Date: {0}, End Date: {1}, Days in first month: {2}, Days in last month: {3}", startDate, endDate, daysInFirstMonth, daysInLastMonth);
|
||||
|
||||
for (int i = 0; i < monthlyStats.Count; i++)
|
||||
{
|
||||
var monthStat = monthlyStats[i];
|
||||
double weight;
|
||||
|
||||
// Parse the Month property into a DateTime object
|
||||
DateTime monthDate = DateTime.ParseExact(monthStat.Month, "M-yyyy", CultureInfo.InvariantCulture);
|
||||
|
||||
// If it's the first or last month in the dataset, calculate the weight based on the number of days
|
||||
if (i == 0)
|
||||
{
|
||||
// Calculate weight based on the number of days in the dataset for the first month
|
||||
weight = daysInFirstMonth / 30.0;
|
||||
}
|
||||
else if (i == monthlyStats.Count - 1)
|
||||
{
|
||||
// Calculate weight based on the number of days in the dataset for the last month
|
||||
weight = (daysInLastMonth / 30.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, assume it's a full month
|
||||
weight = 1;
|
||||
}
|
||||
totalMonths += weight;
|
||||
}
|
||||
return (totalMonths, startDate, endDate);
|
||||
}
|
||||
|
||||
|
||||
private void BuildSalesChartData()
|
||||
{
|
||||
if (PTData.SellLog.Count > 0)
|
||||
{
|
||||
MinSellLogDate = PTData.SellLog.OrderBy(sl => sl.SoldDate).First().SoldDate.Date;
|
||||
DateTime graphStartDate = DateTimeNow.DateTime.Date.AddDays(-1850);
|
||||
if (MinSellLogDate > graphStartDate) graphStartDate = MinSellLogDate;
|
||||
List<object> salesPerDayList = new List<object>();
|
||||
List<object> buysPerDayList = new List<object>(); // New list for daily buys
|
||||
|
||||
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 (PTData.DailyStats.Count > 0)
|
||||
{
|
||||
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 = "[";
|
||||
TradesChartDataJSON += "{";
|
||||
TradesChartDataJSON += "key: 'Sales',";
|
||||
TradesChartDataJSON += "color: '" + Constants.ChartLineColors[0] + "',";
|
||||
TradesChartDataJSON += "values: [" + tradesPerDayJSON + "]";
|
||||
TradesChartDataJSON += "}";
|
||||
TradesChartDataJSON += "]";
|
||||
// Get timezone offset
|
||||
TimeSpan offset;
|
||||
bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-");
|
||||
string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-');
|
||||
|
||||
ProfitChartDataJSON = "[";
|
||||
ProfitChartDataJSON += "{";
|
||||
ProfitChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',";
|
||||
ProfitChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',";
|
||||
ProfitChartDataJSON += "values: [" + profitPerDayJSON + "]";
|
||||
ProfitChartDataJSON += "}";
|
||||
ProfitChartDataJSON += "]";
|
||||
if (!TimeSpan.TryParse(offsetWithoutSign, out offset))
|
||||
{
|
||||
offset = TimeSpan.Zero; // If offset is invalid, set it to zero
|
||||
}
|
||||
|
||||
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<SellLogData> 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 endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date;
|
||||
|
||||
// Parse dates once and adjust them to the local timezone
|
||||
Dictionary<DateTime, DailyStatsData> salesCountByDate = PTData.DailyStats
|
||||
.ToDictionary(
|
||||
data => DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture),
|
||||
data => data
|
||||
);
|
||||
|
||||
DateTime earliestDataDate = salesCountByDate.Keys.Min();
|
||||
DateTime startDate = earliestDataDate;
|
||||
|
||||
// Calculate the total days of data available
|
||||
SalesDays = (endDate - startDate).Days;
|
||||
int counter = 0;
|
||||
for (DateTime date = startDate; date <= endDate && counter < 30; date = date.AddDays(1)) // Check the counter
|
||||
{
|
||||
if (salesCountByDate.TryGetValue(date, out DailyStatsData dailyStatsData))
|
||||
{
|
||||
buysPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = Convert.ToInt32(dailyStatsData.TotalBuys) });
|
||||
salesPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = Convert.ToInt32(dailyStatsData.TotalSales) });
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the lists to a JSON string using Newtonsoft.Json
|
||||
SalesChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] {
|
||||
new { // New JSON object for daily buys
|
||||
key = "Buys",
|
||||
color = Constants.ChartLineColors[19], // Use a different color for buys
|
||||
values = buysPerDayList
|
||||
},
|
||||
new {
|
||||
key = "Sales",
|
||||
color = Constants.ChartLineColors[1],
|
||||
values = salesPerDayList
|
||||
}
|
||||
});
|
||||
}
|
||||
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<Core.Main.DataObjects.PTMagicData.SellLogData> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,19 +124,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
@* <div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Main Fiat Currency <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is the local currency you want PTM to use when showing your sales and account value in fiat."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Application_MainFiatCurrency" value="@Model.PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency">
|
||||
<input type="text" class="form-control" name="Application_MainFiatCurrency" value="@Model.PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency">
|
||||
</div>
|
||||
</div>
|
||||
</div> *@
|
||||
|
||||
<div class="form-group row">
|
||||
@* <div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Starting Balance <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="PTM will use this to calculate total profits to date, and projected profits."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Application_StartBalance" value="@Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance">
|
||||
<input type="text" class="form-control" name="Application_StartBalance" value="@Model.SummaryData.StartBalance">
|
||||
</div>
|
||||
</div>
|
||||
</div> *@
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">CoinMarketCap API Key <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The API Key that will be used to get Coin Data from CoinMarketCap (optional)."></i></label>
|
||||
|
@ -145,12 +145,12 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
@* <div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">FreeCurrencyConverter API Key <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The api key needed for currency conversions for non-USD currency users (optional)."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Application_FreeCurrencyConverterAPIKey" value="@Model.PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey">
|
||||
</div>
|
||||
</div>
|
||||
</div> *@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -196,21 +196,28 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Graph Interval Minutes <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The interval for the monitor market trend graph to draw 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">
|
||||
<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 class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Graph Max Timeframe Hours <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This defines the timeframe that your graph for market trends covers."></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">
|
||||
<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 class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Refresh Seconds <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The refresh interval of your monitor main page."></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">
|
||||
<input type="text" class="form-control" name="Monitor_ProfitsMaxTimeframeDays" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Dashboard Bottom Refresh <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The refresh interval in seconds, of the charts and graphs on then main page."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Monitor_RefreshSeconds" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||
</div>
|
||||
|
@ -240,7 +247,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
@* <div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Max Sales Records<i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The number of sales records PTMagic pulls from Profit Trailer. Changes require a Monitor Restart."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Monitor_MaxSalesRecords" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxSalesRecords.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||
</div>
|
||||
</div> *@
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Max Top Markets <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The amount of top markets being show in your Sales Analyzer."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Monitor_MaxTopMarkets" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||
|
@ -262,7 +276,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-md-4 col-form-label">Max Dashboard Buy Entries <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The amount of entries being shown in your dashboard for possible buys."></i></label>
|
||||
<label class="col-md-4 col-form-label">Max Dashboard Buy Entries <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The amount of possible buys shown in your dashboard. Setting this to 0 completely hides the PBL table."></i></label>
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="Monitor_MaxDashboardBuyEntries" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDashboardBuyEntries.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Core.Main;
|
||||
using Core.Helper;
|
||||
using Core.Main.DataObjects;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
|
||||
|
||||
namespace Monitor.Pages
|
||||
{
|
||||
public class SettingsGeneralModel : _Internal.BasePageModelSecure
|
||||
{
|
||||
public string ValidationMessage = "";
|
||||
public string ValidationMessage = "";
|
||||
public ProfitTrailerData PTData = null;
|
||||
public MiscData MiscData { get; set; }
|
||||
|
||||
private string GetTimezoneOffsetString(TimeZoneInfo tzi)
|
||||
{
|
||||
|
@ -51,6 +54,8 @@ namespace Monitor.Pages
|
|||
public void OnGet()
|
||||
{
|
||||
base.Init();
|
||||
PTData = this.PtDataObject;
|
||||
MiscData = this.PTData.Misc;
|
||||
|
||||
string notification = GetStringParameter("n", "");
|
||||
if (notification.Equals("BackupRestored"))
|
||||
|
@ -68,27 +73,29 @@ namespace Monitor.Pages
|
|||
// Read the new settings
|
||||
PTMagicConfiguration.GeneralSettings.Application.IsEnabled = HttpContext.Request.Form["Application_IsEnabled"].Equals("on");
|
||||
PTMagicConfiguration.GeneralSettings.Application.TestMode = HttpContext.Request.Form["Application_TestMode"].Equals("on");
|
||||
PTMagicConfiguration.GeneralSettings.Application.StartBalance = SystemHelper.TextToDouble(HttpContext.Request.Form["Application_StartBalance"], PTMagicConfiguration.GeneralSettings.Application.StartBalance, "en-US");
|
||||
//PTMagicConfiguration.GeneralSettings.Application.StartBalance = SystemHelper.TextToDouble(HttpContext.Request.Form["Application_StartBalance"], PTMagicConfiguration.GeneralSettings.Application.StartBalance, "en-US");
|
||||
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName = HttpContext.Request.Form["Application_ProfitTrailerDefaultSettingName"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.Exchange = HttpContext.Request.Form["Application_Exchange"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL = HttpContext.Request.Form["Application_ProfitTrailerMonitorURL"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken = HttpContext.Request.Form["Application_ProfitTrailerServerAPIToken"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset = HttpContext.Request.Form["Application_TimezoneOffset"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency = HttpContext.Request.Form["Application_MainFiatCurrency"];
|
||||
//PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency = HttpContext.Request.Form["Application_MainFiatCurrency"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes = SystemHelper.TextToInteger(HttpContext.Request.Form["Application_FloodProtectionMinutes"], PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes);
|
||||
PTMagicConfiguration.GeneralSettings.Application.InstanceName = HttpContext.Request.Form["Application_InstanceName"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.CoinMarketCapAPIKey = HttpContext.Request.Form["Application_CoinMarketCapAPIKey"];
|
||||
PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey = HttpContext.Request.Form["Application_FreeCurrencyConverterAPIKey"];
|
||||
//PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey = HttpContext.Request.Form["Application_FreeCurrencyConverterAPIKey"];
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.IsPasswordProtected = HttpContext.Request.Form["Monitor_IsPasswordProtected"].Equals("on");
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart = HttpContext.Request.Form["Monitor_OpenBrowserOnStart"].Equals("on");
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.AnalyzerChart = HttpContext.Request.Form["Monitor_AnalyzerChart"];
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.Port = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_Port"], PTMagicConfiguration.GeneralSettings.Monitor.Port);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_GraphIntervalMinutes"], PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_GraphMaxTimeframeHours"], PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_ProfitsMaxTimeframeDays"], PTMagicConfiguration.GeneralSettings.Monitor.ProfitsMaxTimeframeDays);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_RefreshSeconds"], PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.BagAnalyzerRefreshSeconds = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_BagAnalyzerRefreshSeconds"], PTMagicConfiguration.GeneralSettings.Monitor.BagAnalyzerRefreshSeconds);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.BuyAnalyzerRefreshSeconds = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_BuyAnalyzerRefreshSeconds"], PTMagicConfiguration.GeneralSettings.Monitor.BuyAnalyzerRefreshSeconds);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform = HttpContext.Request.Form["Monitor_LinkPlatform"];
|
||||
//PTMagicConfiguration.GeneralSettings.Monitor.MaxSalesRecords = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_MaxSalesRecords"], PTMagicConfiguration.GeneralSettings.Monitor.MaxSalesRecords);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_MaxTopMarkets"], PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.MaxDailySummaries = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_MaxDailySummaries"], PTMagicConfiguration.GeneralSettings.Monitor.MaxDailySummaries);
|
||||
PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_MaxMonthlySummaries"], PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries);
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">PTMagic Status <small id="last-refresh" class="pull-right"></small></h4>
|
||||
@{
|
||||
|
@ -67,11 +68,10 @@
|
|||
</div>
|
||||
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Active Settings</h4>
|
||||
<h4 class="m-t-0 header-title">Active Settings <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="If DYNAMIC formulas are used in PT for these settings, the values will not be properly displayed here."></i></h4>
|
||||
@{
|
||||
string maxCostCaption = "Initial";
|
||||
}
|
||||
|
||||
<table class="table table-striped table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
@ -86,8 +86,6 @@
|
|||
}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DCA Level</td>
|
||||
<td class="text-right">@Model.Summary.DCALevels.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td>Min Vol.</td>
|
||||
<td class="text-right">@Model.Summary.MinBuyVolume.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
|
@ -101,124 +99,63 @@
|
|||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Active Buy Strategies</h4>
|
||||
|
||||
<table class="table table-striped table-sm">
|
||||
<tbody>
|
||||
@if (Model.Summary.BuyStrategies.Count == 0) {
|
||||
<tr>
|
||||
<td>Buy Strat.</td>
|
||||
<td class="text-right">@Model.Summary.BuyStrategy</td>
|
||||
<td>Buy Value</td>
|
||||
<td class="text-right">@Model.Summary.BuyValue.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
} else {
|
||||
char buyStrategyIndex = 'A';
|
||||
foreach (Core.Main.DataObjects.PTMagicData.StrategySummary buyStrategy in Model.Summary.BuyStrategies) {
|
||||
<tr>
|
||||
<td>Buy Strat. @buyStrategyIndex</td>
|
||||
<td class="text-right">@buyStrategy.Name</td>
|
||||
<td>Buy Value @buyStrategyIndex</td>
|
||||
<td class="text-right">@buyStrategy.Value.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
buyStrategyIndex++;
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Active Sell Strategies</h4>
|
||||
|
||||
<table class="table table-striped table-sm">
|
||||
<tbody>
|
||||
@if (Model.Summary.SellStrategies.Count == 0) {
|
||||
<tr>
|
||||
<td>Sell Strat.</td>
|
||||
<td class="text-right">@Model.Summary.SellStrategy</td>
|
||||
<td>Sell Value</td>
|
||||
<td class="text-right">@Model.Summary.SellValue.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
} else {
|
||||
char sellStrategyIndex = 'A';
|
||||
foreach (Core.Main.DataObjects.PTMagicData.StrategySummary sellStrategy in Model.Summary.SellStrategies) {
|
||||
<tr>
|
||||
<td>Sell Strat. @sellStrategyIndex</td>
|
||||
<td class="text-right">@sellStrategy.Name</td>
|
||||
<td>Sell Value @sellStrategyIndex</td>
|
||||
<td class="text-right">@sellStrategy.Value.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
sellStrategyIndex++;
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-7">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
|
||||
|
||||
<div id="gsChart24h">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4>
|
||||
|
||||
<div id="gsChart3d">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
|
||||
<div id="gsChart24h">
|
||||
<svg style="height:200px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Global Settings Log</h4>
|
||||
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Time the setting got activated.">Activation Time</th>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Name of the global setting.">Setting</th>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Amount of time the setting is or was active">Active Time</th>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Market trends values from the time the setting got activated.">Market Trends</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (Core.Main.DataObjects.PTMagicData.GlobalSettingSummary gss in Model.Summary.GlobalSettingSummary.OrderByDescending(g => g.SwitchDateTime).Take(Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxSettingsLogEntries)) {
|
||||
TimeSpan offsetTimeSpan = TimeSpan.Parse(Model.PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
|
||||
DateTimeOffset settingActivationTime = gss.SwitchDateTime;
|
||||
settingActivationTime = settingActivationTime.ToOffset(offsetTimeSpan);
|
||||
|
||||
string marketTrendsSummary = "";
|
||||
foreach (string mt in gss.MarketTrendChanges.Keys) {
|
||||
if (!marketTrendsSummary.Equals("")) {
|
||||
marketTrendsSummary += "<br />";
|
||||
}
|
||||
marketTrendsSummary += Core.Helper.SystemHelper.SplitCamelCase(mt) + ": " + gss.MarketTrendChanges[mt].TrendChange.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
}
|
||||
<tr>
|
||||
<td>@settingActivationTime.DateTime.ToShortDateString() @settingActivationTime.DateTime.ToShortTimeString()</td>
|
||||
<td>@Core.Helper.SystemHelper.SplitCamelCase(gss.SettingName)</td>
|
||||
<td>@Core.Helper.SystemHelper.GetProperDurationTime(gss.ActiveSeconds)</td>
|
||||
<td>@Html.Raw(marketTrendsSummary)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4>
|
||||
<div id="gsChart3d">
|
||||
<svg style="height:200px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Global Settings Log</h4>
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Time the setting got activated.">Activation Time</th>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Name of the global setting.">Setting</th>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Amount of time the setting is or was active">Active Time</th>
|
||||
<th data-toggle="tooltip" data-placement="top" title="Market trends values from the time the setting got activated.">Market Trends</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (Core.Main.DataObjects.PTMagicData.GlobalSettingSummary gss in Model.Summary.GlobalSettingSummary.OrderByDescending(g => g.SwitchDateTime).Take(Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxSettingsLogEntries)) {
|
||||
TimeSpan offsetTimeSpan = TimeSpan.Parse(Model.PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
|
||||
DateTimeOffset settingActivationTime = gss.SwitchDateTime;
|
||||
settingActivationTime = settingActivationTime.ToOffset(offsetTimeSpan);
|
||||
|
||||
string marketTrendsSummary = "";
|
||||
foreach (string mt in gss.MarketTrendChanges.Keys) {
|
||||
if (!marketTrendsSummary.Equals("")) {
|
||||
marketTrendsSummary += "<br />";
|
||||
}
|
||||
marketTrendsSummary += Core.Helper.SystemHelper.SplitCamelCase(mt) + ": " + gss.MarketTrendChanges[mt].TrendChange.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
}
|
||||
<tr>
|
||||
<td>@settingActivationTime.DateTime.ToShortDateString() @settingActivationTime.DateTime.ToShortTimeString()</td>
|
||||
<td>@Core.Helper.SystemHelper.SplitCamelCase(gss.SettingName)</td>
|
||||
<td>@Core.Helper.SystemHelper.GetProperDurationTime(gss.ActiveSeconds)</td>
|
||||
<td>@Html.Raw(marketTrendsSummary)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -101,7 +101,6 @@
|
|||
<ul class="submenu">
|
||||
<li><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)SettingsGeneral"><i class="fa fa-power-off"></i> General</a></li>
|
||||
<li><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)SettingsAnalyzer"><i class="fa fa-magic"></i> Analyzer</a></li>
|
||||
<li><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)Transactions"><i class="fa fa-exchange"></i> Transactions</a></li>
|
||||
<li><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)PresetFiles"><i class="fa fa-edit"></i> Presets Files</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -82,9 +82,9 @@
|
|||
double sellTriggerPrice = Model.DCALogData.AverageBuyPrice + (Model.DCALogData.AverageBuyPrice * Model.DCALogData.SellTrigger / 100);
|
||||
|
||||
double averageProfitPercent = 0;
|
||||
if (Model.PTData.SellLog.FindAll(m => m.Market == Model.DCALogData.Market).Count > 0) {
|
||||
@* if (Model.PTData.SellLog.FindAll(m => m.Market == Model.DCALogData.Market).Count > 0) {
|
||||
averageProfitPercent = Model.PTData.SellLog.FindAll(m => m.Market == Model.DCALogData.Market).Average(p => p.ProfitPercent);
|
||||
}
|
||||
} *@
|
||||
|
||||
double investedFiatValue = Math.Round(Model.DCALogData.TotalCost * Model.Summary.MainMarketPrice, 2);
|
||||
double currentValue = Math.Round(Model.DCALogData.Amount * Model.DCALogData.CurrentPrice, 8);
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="card-box px-2" style="height:305px;">
|
||||
<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:340px;">
|
||||
<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" style="font-size x-small" 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 at @Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes intervals, in general settings."></i></h4>
|
||||
@if (!Model.TrendChartDataJSON.Equals("")) {
|
||||
<div class="trend-chart">
|
||||
<svg style="height: 300px;width: 100%;"></svg>
|
||||
|
@ -22,9 +22,11 @@
|
|||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 px-1">
|
||||
<div class="card-box px-3" style="height:305px;">
|
||||
<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-3" style="height:340px;">
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"
|
||||
title="All charts set to refresh every @Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds seconds in your general settings."></div>
|
||||
@{
|
||||
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||
if (Model.totalCurrentValue > 100) {
|
||||
|
@ -34,8 +36,8 @@
|
|||
<div id="AssetDistribution" class="container">
|
||||
<div class="text-center">
|
||||
<small>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Starting balance from PTM settings">Start: <text class="text-autocolor"> @Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance @Model.Summary.MainMarket </text></span>
|
||||
<span data-toggle="tooltip" data-placement="top" title="TCV gain on starting balance">     Gain: <text class="text-autocolor">@Math.Round(((Model.totalCurrentValue - Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance) / Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance) * 100, 2)%</text></span>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Starting balance from PTM settings">Start: <text class="text-autocolor"> @Model.MiscData.StartBalance @Model.Summary.MainMarket </text></span>
|
||||
<span data-toggle="tooltip" data-placement="top" title="TCV gain on starting balance">     Gain: <text class="text-autocolor">@Math.Round(((Model.totalCurrentValue - Model.MiscData.StartBalance) / Model.MiscData.StartBalance) * 100, 2)%</text></span>
|
||||
</small>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
|
@ -49,8 +51,9 @@
|
|||
</div>
|
||||
|
||||
<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="card-box px-2" style="height:305px;">
|
||||
@*<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:340px;">
|
||||
<h4 class="m-t-0 m-b-20 header-title" style="display: inline;">Daily Profit <i class="fa fa-info-circle text-muted" style="font-size x-small" 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("")) {
|
||||
<div class="profit-chart">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
|
@ -61,144 +64,213 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 px-1">
|
||||
<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>
|
||||
<br>
|
||||
<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>
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="card-box px-3">
|
||||
@* <div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeco;nds * 1000)" data-color="#aaa,#414d59"></div>
|
||||
<br> *@
|
||||
<h4 class="m-t-0 m-b-20 header-title">Live Trends
|
||||
<i class="fa fa-info-circle text-muted" style="font-size small" data-toggle="tooltip" data-placement="top" title="Set to refresh every @Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds seconds in general settings."></i>
|
||||
<small class="pull-right" style="font-size: x-small"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">ANALYZER</a></small>
|
||||
</h4>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-right">Markets</th>
|
||||
<th class="text-right">Timeframe</th>
|
||||
<th class="text-right" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are excluded from the trend average.">Threshold %</th>
|
||||
<th class="text-right">Threshold <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are excluded from the trend average."></i>
|
||||
</th>
|
||||
<th class="text-right">Change</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var marketTrend in Model.MarketTrends.OrderBy(mt => mt.TrendMinutes)) {
|
||||
if (Model.Summary.MarketTrendChanges.ContainsKey(marketTrend.Name)) {
|
||||
double trendChange = Model.Summary.MarketTrendChanges[marketTrend.Name].OrderByDescending(mtc => mtc.TrendDateTime).First().TrendChange;
|
||||
string trendChangeOutput = trendChange.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
if (Model.Summary.MarketTrendChanges.ContainsKey(marketTrend.Name)) {
|
||||
double trendChange = Model.Summary.MarketTrendChanges[marketTrend.Name].Last().TrendChange;
|
||||
string trendChangeOutput = trendChange.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
|
||||
int marketCount = marketTrend.MaxMarkets;
|
||||
string marketCountString = marketCount.ToString();
|
||||
int marketCount = marketTrend.MaxMarkets;
|
||||
string marketCountString = marketCount.ToString();
|
||||
|
||||
if (marketCount == 0) {
|
||||
marketCountString = "All";
|
||||
} else if (marketCount > Model.Summary.MarketSummary.Keys.Count && marketTrend.Platform.Equals("Exchange", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
marketCountString = Model.Summary.MarketSummary.Keys.Count.ToString();
|
||||
if (marketCount == 0) {
|
||||
marketCountString = "All";
|
||||
} else if (marketCount > Model.Summary.MarketSummary.Keys.Count && marketTrend.Platform.Equals("Exchange", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
marketCountString = Model.Summary.MarketSummary.Keys.Count.ToString();
|
||||
}
|
||||
|
||||
// Cache the result of SplitCamelCase(marketTrend.Name)
|
||||
string splitCamelCaseName = Core.Helper.SystemHelper.SplitCamelCase(marketTrend.Name);
|
||||
|
||||
<tr>
|
||||
<td>@splitCamelCaseName</td> <!-- Use the cached value here -->
|
||||
<td class="text-right">@marketCountString</td>
|
||||
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td>
|
||||
@if (marketTrend.TrendThreshold == 0)
|
||||
{
|
||||
<td class="text-right">--</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td class="text-right">@marketTrend.TrendThreshold %</td>
|
||||
}
|
||||
<td class="text-right text-autocolor" style="font-weight:bold;">@trendChangeOutput %</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<td>@Core.Helper.SystemHelper.SplitCamelCase(marketTrend.Name)</td>
|
||||
<td class="text-right">@marketCountString</td>
|
||||
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td>
|
||||
@if (marketTrend.TrendThreshold == 0)
|
||||
{
|
||||
<td class="text-right">--</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td class="text-right">@marketTrend.TrendThreshold</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@trendChangeOutput%</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 px-1">
|
||||
<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>
|
||||
<br>
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Sales Overview</b><small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)SalesAnalyzer">more</a></small></h4>
|
||||
<div class="col-md-7 px-1">
|
||||
<div class="card-box px-3">
|
||||
<h4 class="m-t-0 m-b-20 header-title">Sales Overview
|
||||
<i class="fa fa-info-circle text-muted" style="font-size x-small" data-toggle="tooltip" data-placement="top" title="All data acquired via Profit Trailer API."></i>
|
||||
<small class="pull-right" style="font-size: small"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)SalesAnalyzer">ANALYZER</a></small>
|
||||
</h4>
|
||||
@{
|
||||
|
||||
double totalProfit = 0;
|
||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
||||
double totalProfitFiat = Math.Round(totalProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double percentGain = Math.Round(totalProfit / Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance * 100, 2);
|
||||
string percentGainText = percentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
if (Model.PTData.TransactionData.Transactions.Count > 0)
|
||||
{
|
||||
percentGainText = "<i class=\"fa fa-info-circle text-muted\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"You have added at least one manual transaction, so the total gain percentage cannot be calculated.\"></i>";
|
||||
}
|
||||
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;
|
||||
|
||||
double todaysProfit = 0;
|
||||
todaysProfit = Model.PTData.SellLogToday.Sum(s => s.Profit);
|
||||
double todaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime);
|
||||
double todaysProfitFiat = Math.Round(todaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double todaysPercentGain = Math.Round(todaysProfit / todaysStartBalance * 100, 2);
|
||||
//var startingBalance = Model.MiscData.StartBalance;
|
||||
var totalCurrentValue = Model.totalCurrentValue;
|
||||
var overviewStats = Model.StatsData;
|
||||
|
||||
double yesterdaysProfit = 0;
|
||||
yesterdaysProfit = Model.PTData.SellLogYesterday.Sum(s => s.Profit);
|
||||
double yesterdaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-1));
|
||||
double yesterdaysProfitFiat = Math.Round(yesterdaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double yesterdaysPercentGain = Math.Round(yesterdaysProfit / yesterdaysStartBalance * 100, 2);
|
||||
var todaysSales = overviewStats.SalesToday;
|
||||
var todaysProfit = overviewStats.ProfitToday;
|
||||
var todaysFunding = overviewStats.FundingToday;
|
||||
var todaysPercentGain = overviewStats.ProfitPercToday + Model.PTData.Stats.TotalFundingPercToday;
|
||||
|
||||
var yesterdaysSales = overviewStats.SalesYesterday;
|
||||
var yesterdaysProfit = overviewStats.ProfitYesterday;
|
||||
var yesterdaysFunding = overviewStats.FundingYesterday;
|
||||
var yesterdaysPercentGain = overviewStats.ProfitPercYesterday + Model.PTData.Stats.TotalFundingPercYesterday;
|
||||
|
||||
double last7DaysProfit = 0;
|
||||
last7DaysProfit = Model.PTData.SellLogLast7Days.Sum(s => s.Profit);
|
||||
double last7DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-7));
|
||||
double last7DaysProfitFiat = Math.Round(last7DaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double last7DaysPercentGain = Math.Round(last7DaysProfit / last7DaysStartBalance * 100, 2);
|
||||
var last7DaysSales = overviewStats.SalesWeek;
|
||||
var last7DaysProfit = overviewStats.ProfitWeek;
|
||||
var last7DaysFunding = overviewStats.FundingWeek;
|
||||
var last7DaysPercentGain = overviewStats.ProfitPercWeek + Model.PTData.Stats.TotalFundingPercWeek;
|
||||
|
||||
var thisMonthSales = overviewStats.SalesThisMonth;
|
||||
var thisMonthProfit = overviewStats.ProfitThisMonth;
|
||||
var thisMonthFunding = overviewStats.FundingThisMonth;
|
||||
var thisMonthPercentGain = avgGrowthThisMonth;
|
||||
|
||||
var lastMonthSales = overviewStats.SalesLastMonth;
|
||||
var lastMonthProfit = overviewStats.ProfitLastMonth;
|
||||
var lastMonthFunding = overviewStats.FundingLastMonth;
|
||||
var lastMonthPercentGain = avgGrowthLastMonth;
|
||||
|
||||
var totalSales = overviewStats.TotalSales;
|
||||
var totalProfit = overviewStats.TotalProfit;
|
||||
var totalFunding = overviewStats.FundingTotal;
|
||||
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);
|
||||
double last7DaysProfitFiat = Math.Round((last7DaysProfit + last7DaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||
double thisMonthProfitFiat = Math.Round((thisMonthProfit + thisMonthFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||
double lastMonthProfitFiat = Math.Round((lastMonthProfit + lastMonthFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||
double totalProfitFiat = Math.Round((totalProfit + totalFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||
|
||||
bool futuresFunding = Model.PropertiesData.IsLeverageExchange;
|
||||
|
||||
double last30DaysProfit = 0;
|
||||
last30DaysProfit = Model.PTData.SellLogLast30Days.Sum(s => s.Profit);
|
||||
double last30DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-30));
|
||||
double last30DaysProfitFiat = Math.Round(last30DaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double last30DaysPercentGain = Math.Round(last30DaysProfit / last30DaysStartBalance * 100, 2);
|
||||
}
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-right">Sales</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainMarket</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainFiatCurrency</th>
|
||||
<th class="text-right">Profit @Model.PTData.Misc.Market</th>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<th class="text-right">Funding</th>
|
||||
}
|
||||
<th class="text-right">@Model.PTData.Properties.Currency</th>
|
||||
<th class="text-right">Gain</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Today</th>
|
||||
<td class="text-right">@Model.PTData.SellLogToday.Count</td>
|
||||
<td class="text-right">@overviewStats.SalesToday</td>
|
||||
<td class="text-right text-autocolor">@todaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + todaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@todaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<td class="text-right text-autocolor">@todaysFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@Html.Raw(todaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@todaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Yesterday</th>
|
||||
<td class="text-right">@Model.PTData.SellLogYesterday.Count</td>
|
||||
<td class="text-right">@yesterdaysSales</td>
|
||||
<td class="text-right text-autocolor">@yesterdaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + yesterdaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@yesterdaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<td class="text-right text-autocolor">@yesterdaysFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@Html.Raw(yesterdaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@yesterdaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Last 7 Days</th>
|
||||
<td class="text-right">@Model.PTData.SellLogLast7Days.Count</td>
|
||||
<th>7 Days</th>
|
||||
<td class="text-right">@last7DaysSales</td>
|
||||
<td class="text-right text-autocolor">@last7DaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + last7DaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@last7DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<td class="text-right text-autocolor">@last7DaysFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@Html.Raw(last7DaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@last7DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Last 30 Days</th>
|
||||
<td class="text-right">@Model.PTData.SellLogLast30Days.Count</td>
|
||||
<td class="text-right text-autocolor">@last30DaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + last30DaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@last30DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
@{
|
||||
var timeParts = @Model.MiscData.TimeZoneOffset.Split(':');
|
||||
var timeZoneOffsetHours = int.Parse(timeParts[0]);
|
||||
var timeZoneOffset = TimeSpan.FromHours(timeZoneOffsetHours);
|
||||
var timeZoneInfo = TimeZoneInfo.CreateCustomTimeZone("Custom", timeZoneOffset, "Custom", "Custom");
|
||||
var currentDateTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, timeZoneInfo);
|
||||
var currentMonthName = currentDateTime.ToString("MMMM");
|
||||
}
|
||||
<th>@currentMonthName</th>
|
||||
<td class="text-right">@thisMonthSales</td>
|
||||
<td class="text-right text-autocolor">@thisMonthProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<td class="text-right text-autocolor">@thisMonthFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@Html.Raw(thisMonthProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@thisMonthPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@{
|
||||
var previousMonthDateTime = currentDateTime.AddMonths(-1);
|
||||
var previousMonthName = previousMonthDateTime.ToString("MMMM");
|
||||
}
|
||||
<th>@previousMonthName</th>
|
||||
<td class="text-right">@lastMonthSales</td>
|
||||
<td class="text-right text-autocolor">@lastMonthProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<td class="text-right text-autocolor">@lastMonthFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@Html.Raw(lastMonthProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@lastMonthPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total</th>
|
||||
<td class="text-right">@Model.PTData.SellLog.Count</td>
|
||||
<td class="text-right">@totalSales</td>
|
||||
<td class="text-right text-autocolor">@totalProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + totalProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@Html.Raw(percentGainText)</td>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
<td class="text-right text-autocolor">@totalFunding.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
}
|
||||
<td class="text-right text-autocolor">@Html.Raw(totalProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td class="text-right text-autocolor">@totalPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -210,74 +282,176 @@
|
|||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/nvd3/nv.d3.min.js"></script>
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/tablesaw/js/tablesaw.js"></script>
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/tablesaw/js/tablesaw-init.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$(".cdev").circlos();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
$(document).ready(function () {
|
||||
$(".cdev").circlos();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
var assetDistributionChart; // Keep a reference to the chart
|
||||
var assetDistributionData; // Keep a reference to the data
|
||||
|
||||
@if (!Model.AssetDistributionData.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function() {
|
||||
assetDistributionChart = nv.models.pieChart()
|
||||
.x(function(d) { return d.label })
|
||||
.y(function(d) { return d.value })
|
||||
.showLabels(true)
|
||||
.labelThreshold(.1)
|
||||
.labelType("percent")
|
||||
.donut(true)
|
||||
.donutRatio(0.3);
|
||||
|
||||
assetDistributionData = @Html.Raw(Model.AssetDistributionData);
|
||||
|
||||
@if (!Model.AssetDistributionData.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function() {
|
||||
var chart = nv.models.pieChart()
|
||||
.x(function(d) { return d.label })
|
||||
.y(function(d) { return d.value })
|
||||
.showLabels(true) //Display pie labels
|
||||
.labelThreshold(.1) //Configure the minimum slice size for labels to show up
|
||||
.labelType("percent") //Configure what type of data to show in the label. Can be "key", "value" or "percent"
|
||||
.donut(true) //Turn on Donut mode. Makes pie chart look tasty!
|
||||
.donutRatio(0.3) //Configure how big you want the donut hole size to be.
|
||||
;
|
||||
d3.select("#AssetDistribution svg")
|
||||
.datum(@Html.Raw(Model.AssetDistributionData))
|
||||
.transition().duration(350)
|
||||
.call(chart);
|
||||
return chart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
});
|
||||
.datum(assetDistributionData)
|
||||
.transition().duration(0)
|
||||
.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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(assetDistributionChart.update);
|
||||
return assetDistributionChart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
$('[role="tooltip"]').remove();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
@if (!Model.Summary.CurrentGlobalSetting.SettingName.Equals(Model.LastGlobalSetting)) {
|
||||
<text>
|
||||
$.Notification.notify('success', 'top left', '@Core.Helper.SystemHelper.SplitCamelCase(Model.Summary.CurrentGlobalSetting.SettingName) now active!', 'PTMagic switched Profit Trailer settings to "@Core.Helper.SystemHelper.SplitCamelCase(Model.Summary.CurrentGlobalSetting.SettingName)".');
|
||||
</text>
|
||||
}
|
||||
var trendChart; // Keep a reference to the chart
|
||||
var trendData; // Keep a reference to the data
|
||||
|
||||
@if (!Model.TrendChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
var lineChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
var chartData = @Html.Raw(Model.TrendChartDataJSON);
|
||||
lineChart.useInteractiveGuideline(true);
|
||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%H:%M')(new Date(d)); });
|
||||
lineChart.yAxis.axisLabel('Trend %').tickFormat(d3.format(',.2f'));
|
||||
d3.select('.trend-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
||||
//nv.utils.windowResize(lineChart.update); v1.3.0 => Removed this line to prevent memory leak
|
||||
return lineChart;
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
trendChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
trendChart.useInteractiveGuideline(true);
|
||||
trendChart.xAxis.tickFormat(function (d) { return d3.time.format('%H:%M')(new Date(d)); });
|
||||
trendChart.yAxis.axisLabel('Trend %').tickFormat(d3.format(',.2f'));
|
||||
|
||||
trendData = @Html.Raw(Model.TrendChartDataJSON);
|
||||
|
||||
d3.select('.trend-chart svg')
|
||||
.datum(trendData)
|
||||
.transition().duration(0)
|
||||
.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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(trendChart.update);
|
||||
return trendChart;
|
||||
});
|
||||
</text>
|
||||
</text>
|
||||
}
|
||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
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); v1.3.0 => Removed this line to prevent memory leak
|
||||
return lineChart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
})(jQuery);
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
$('[role="tooltip"]').remove();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
var profitChart; // Keep a reference to the chart
|
||||
var profitData; // Keep a reference to the data
|
||||
|
||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
profitChart = nv.models.lineChart();
|
||||
var height = 300;
|
||||
profitChart.useInteractiveGuideline(true);
|
||||
profitChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
profitChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
|
||||
|
||||
profitData = @Html.Raw(Model.ProfitChartDataJSON);
|
||||
|
||||
d3.select('.profit-chart svg')
|
||||
.datum(profitData)
|
||||
.transition().duration(0)
|
||||
.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);
|
||||
}
|
||||
});
|
||||
nv.utils.windowResize(profitChart.update);
|
||||
return profitChart;
|
||||
});
|
||||
</text>
|
||||
}
|
||||
})(jQuery);
|
||||
</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>
|
||||
|
|
|
@ -6,14 +6,20 @@ using Core.Main;
|
|||
using Core.Helper;
|
||||
using Core.Main.DataObjects;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
using Core.MarketAnalyzer;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Monitor.Pages
|
||||
{
|
||||
public class DashboardBottomModel : _Internal.BasePageModelSecureAJAX
|
||||
{
|
||||
public ProfitTrailerData PTData = null;
|
||||
public StatsData StatsData { get; set; }
|
||||
public PropertiesData PropertiesData { get; set; }
|
||||
public MiscData MiscData { get; set; }
|
||||
public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
|
||||
public double DataHours { get; set; }
|
||||
public int ProfitDays { get; set; }
|
||||
public string TrendChartDataJSON = "";
|
||||
public string ProfitChartDataJSON = "";
|
||||
public string LastGlobalSetting = "Default";
|
||||
|
@ -26,12 +32,18 @@ namespace Monitor.Pages
|
|||
base.Init();
|
||||
|
||||
BindData();
|
||||
BuildAssetDistributionData();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void BindData()
|
||||
{
|
||||
PTData = this.PtDataObject;
|
||||
StatsData = this.PTData.Stats;
|
||||
PropertiesData = this.PTData.Properties;
|
||||
MiscData = this.PTData.Misc;
|
||||
List<MonthlyStatsData> monthlyStatsData = this.PTData.MonthlyStats;
|
||||
List<DailyPNLData> 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);
|
||||
|
@ -51,113 +63,166 @@ namespace Monitor.Pages
|
|||
MarketTrends = PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.OrderBy(mt => mt.TrendMinutes).ThenByDescending(mt => mt.Platform).ToList();
|
||||
|
||||
BuildMarketTrendChartData();
|
||||
BuildAssetDistributionData();
|
||||
BuildProfitChartData();
|
||||
}
|
||||
|
||||
private void BuildMarketTrendChartData()
|
||||
{
|
||||
if (MarketTrends.Count > 0)
|
||||
{
|
||||
TrendChartDataJSON = "[";
|
||||
int mtIndex = 0;
|
||||
foreach (MarketTrend mt in MarketTrends)
|
||||
List<string> trendChartData = new List<string>();
|
||||
if (MarketTrends.Count > 0)
|
||||
{
|
||||
if (mt.DisplayGraph)
|
||||
{
|
||||
string lineColor = "";
|
||||
if (mtIndex < Constants.ChartLineColors.Length)
|
||||
|
||||
int mtIndex = 0;
|
||||
foreach (MarketTrend mt in MarketTrends)
|
||||
{
|
||||
lineColor = Constants.ChartLineColors[mtIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
lineColor = Constants.ChartLineColors[mtIndex - 20];
|
||||
}
|
||||
|
||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||
{
|
||||
List<MarketTrendChange> marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name];
|
||||
|
||||
if (marketTrendChangeSummaries.Count > 0)
|
||||
{
|
||||
if (!TrendChartDataJSON.Equals("[")) TrendChartDataJSON += ",";
|
||||
|
||||
TrendChartDataJSON += "{";
|
||||
TrendChartDataJSON += "key: '" + SystemHelper.SplitCamelCase(mt.Name) + "',";
|
||||
TrendChartDataJSON += "color: '" + lineColor + "',";
|
||||
TrendChartDataJSON += "values: [";
|
||||
|
||||
// Get trend ticks for chart
|
||||
DateTime currentDateTime = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, DateTime.UtcNow.Hour, 0, 0);
|
||||
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
||||
DateTime endDateTime = currentDateTime;
|
||||
int trendChartTicks = 0;
|
||||
for (DateTime tickTime = startDateTime; tickTime <= endDateTime; tickTime = tickTime.AddMinutes(PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes))
|
||||
if (mt.DisplayGraph)
|
||||
{
|
||||
List<MarketTrendChange> tickRange = marketTrendChangeSummaries.FindAll(m => m.TrendDateTime >= tickTime).OrderBy(m => m.TrendDateTime).ToList();
|
||||
if (tickRange.Count > 0)
|
||||
{
|
||||
MarketTrendChange mtc = tickRange.First();
|
||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
||||
string lineColor = mtIndex < Constants.ChartLineColors.Length
|
||||
? Constants.ChartLineColors[mtIndex]
|
||||
: Constants.ChartLineColors[mtIndex - 20];
|
||||
|
||||
TrendChartDataJSON += "{ x: new Date('" + tickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
trendChartTicks++;
|
||||
}
|
||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||
{
|
||||
List<MarketTrendChange> marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name];
|
||||
|
||||
if (marketTrendChangeSummaries.Count > 0)
|
||||
{
|
||||
List<string> trendValues = new List<string>();
|
||||
|
||||
// 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))
|
||||
{
|
||||
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<MarketTrendChange>.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
|
||||
List<MarketTrendChange> latestTickRange = marketTrendChangeSummaries.OrderByDescending(m => m.TrendDateTime).ToList();
|
||||
if (latestTickRange.Count > 0)
|
||||
{
|
||||
MarketTrendChange mtc = latestTickRange.First();
|
||||
if (trendChartTicks > 0) TrendChartDataJSON += ",\n";
|
||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
||||
TrendChartDataJSON += "{ x: new Date('" + mtc.TrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
}
|
||||
TrendChartDataJSON += "]";
|
||||
TrendChartDataJSON += "}";
|
||||
mtIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TrendChartDataJSON += "]";
|
||||
}
|
||||
TrendChartDataJSON = "[" + string.Join(",", trendChartData) + "]";
|
||||
}
|
||||
|
||||
private void BuildProfitChartData()
|
||||
{
|
||||
int tradeDayIndex = 0;
|
||||
string profitPerDayJSON = "";
|
||||
|
||||
if (PTData.SellLog.Count > 0)
|
||||
{
|
||||
DateTime minSellLogDate = PTData.SellLog.OrderBy(sl => sl.SoldDate).First().SoldDate.Date;
|
||||
DateTime graphStartDate = DateTime.UtcNow.Date.AddDays(-30);
|
||||
if (minSellLogDate > graphStartDate)
|
||||
List<object> profitPerDayList = new List<object>();
|
||||
|
||||
if (PTData.DailyPNL.Count > 0)
|
||||
{
|
||||
graphStartDate = minSellLogDate;
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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
|
||||
}
|
||||
});
|
||||
}
|
||||
for (DateTime salesDate = graphStartDate; salesDate <= DateTime.UtcNow.Date; salesDate = salesDate.AddDays(1))
|
||||
{
|
||||
if (tradeDayIndex > 0)
|
||||
{
|
||||
profitPerDayJSON += ",\n";
|
||||
}
|
||||
int trades = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate).Count;
|
||||
double profit = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate).Sum(t => t.Profit);
|
||||
double profitFiat = Math.Round(profit * Summary.MainMarketPrice, 2);
|
||||
profitPerDayJSON += "{x: new Date('" + salesDate.ToString("yyyy-MM-dd") + "'), y: " + profitFiat.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
tradeDayIndex++;
|
||||
}
|
||||
ProfitChartDataJSON = "[";
|
||||
ProfitChartDataJSON += "{";
|
||||
ProfitChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',";
|
||||
ProfitChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',";
|
||||
ProfitChartDataJSON += "values: [" + profitPerDayJSON + "]";
|
||||
ProfitChartDataJSON += "}";
|
||||
ProfitChartDataJSON += "]";
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildAssetDistributionData()
|
||||
{
|
||||
// the per PT-Eelroy, the PT API doesn't provide these values when using leverage, so they are calculated here to cover either case.
|
||||
|
@ -171,7 +236,6 @@ namespace Monitor.Pages
|
|||
foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog)
|
||||
{
|
||||
string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive);
|
||||
|
||||
// Aggregate totals
|
||||
double leverage = dcaLogEntry.Leverage;
|
||||
if (leverage == 0)
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
@page
|
||||
@model SalesListModel
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-0">Showing @Model.SellLog.Count sales for @Model.SalesTimeframe</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table id="sales-list" class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Sold Time</th>
|
||||
<th>Market</th>
|
||||
<th class="text-right">Avg. Bought Price</th>
|
||||
<th class="text-right">DCA</th>
|
||||
<th class="text-right">Sold Price</th>
|
||||
<th class="text-right">Sold Amount</th>
|
||||
<th class="text-right">Bought Cost</th>
|
||||
<th class="text-right">Sold Value</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainMarket</th>
|
||||
<th class="text-right">Profit @Model.Summary.MainFiatCurrency</th>
|
||||
<th class="text-right">Profit %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (Core.Main.DataObjects.PTMagicData.SellLogData sellLogEntry in Model.SellLog) {
|
||||
double profitFiat = Math.Round(sellLogEntry.Profit * Model.Summary.MainMarketPrice, 2);
|
||||
<tr>
|
||||
<td>@sellLogEntry.SoldDate.ToShortDateString() @sellLogEntry.SoldDate.ToLongTimeString()</td>
|
||||
<td><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, sellLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@sellLogEntry.Market</a></td>
|
||||
<td class="text-right">@sellLogEntry.AverageBuyPrice.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right">
|
||||
@if (sellLogEntry.BoughtTimes > 0) {
|
||||
@sellLogEntry.BoughtTimes;
|
||||
}
|
||||
</td>
|
||||
<td class="text-right">@sellLogEntry.SoldPrice.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right">@sellLogEntry.SoldAmount.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right">@sellLogEntry.TotalCost.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right">@sellLogEntry.SoldValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@sellLogEntry.Profit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@profitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
<td class="text-right text-autocolor">@sellLogEntry.ProfitPercent.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
//Buttons examples
|
||||
var table = $('#sales-list').DataTable({
|
||||
lengthChange: false,
|
||||
searching: false,
|
||||
paging: false,
|
||||
info: false,
|
||||
ordering: false,
|
||||
buttons: ['copy', 'excel', 'pdf']
|
||||
});
|
||||
|
||||
table.buttons().container()
|
||||
.appendTo('#sales-list_wrapper .col-md-6:eq(0)');
|
||||
|
||||
$('.btn-trend-relation').click(function () {
|
||||
var relation = $(this).data('trend-relation');
|
||||
|
||||
$('.btn-trend-relation').addClass('btn-custom');
|
||||
$(this).removeClass('btn-custom');
|
||||
|
||||
if (relation == 'absolute') {
|
||||
$('#trends-absolute').removeClass('hidden');
|
||||
$('#trends-relative').addClass('hidden');
|
||||
|
||||
} else {
|
||||
$('#trends-absolute').addClass('hidden');
|
||||
$('#trends-relative').removeClass('hidden');
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
|
@ -1,49 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Core.Main;
|
||||
using Core.Helper;
|
||||
using Core.Main.DataObjects;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
using Core.MarketAnalyzer;
|
||||
|
||||
namespace Monitor.Pages {
|
||||
public class SalesListModel : _Internal.BasePageModelSecure {
|
||||
public ProfitTrailerData PTData = null;
|
||||
private string salesDateString = "";
|
||||
private string salesMonthString = "";
|
||||
|
||||
public string SalesTimeframe = "";
|
||||
public DateTime SalesDate = Constants.confMinDate;
|
||||
public List<SellLogData> SellLog = new List<SellLogData>();
|
||||
|
||||
public void OnGet() {
|
||||
// Initialize Config
|
||||
base.Init();
|
||||
|
||||
BindData();
|
||||
}
|
||||
|
||||
private void BindData() {
|
||||
salesDateString = GetStringParameter("d", "");
|
||||
salesMonthString = GetStringParameter("m", "");
|
||||
|
||||
PTData = this.PtDataObject;
|
||||
|
||||
if (!salesDateString.Equals("")) {
|
||||
SalesDate = SystemHelper.TextToDateTime(salesDateString, Constants.confMinDate);
|
||||
if (SalesDate != Constants.confMinDate) {
|
||||
SalesTimeframe = SalesDate.ToShortDateString();
|
||||
SellLog = PTData.SellLog.FindAll(sl => sl.SoldDate.Date == SalesDate.Date).OrderByDescending(sl => sl.SoldDate).ToList();
|
||||
}
|
||||
} else if (!salesMonthString.Equals("")) {
|
||||
SalesDate = SystemHelper.TextToDateTime(salesMonthString + "-01", Constants.confMinDate);
|
||||
if (SalesDate != Constants.confMinDate) {
|
||||
SalesTimeframe = SalesDate.ToString("MMMM yyyy", new System.Globalization.CultureInfo("en-US"));
|
||||
SellLog = PTData.SellLog.FindAll(sl => sl.SoldDate.Date.Month == SalesDate.Month && sl.SoldDate.Date.Year == SalesDate.Year).OrderByDescending(sl => sl.SoldDate).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace Monitor
|
|||
services.AddDistributedMemoryCache();
|
||||
services.AddSession(options =>
|
||||
{
|
||||
options.IdleTimeout = TimeSpan.FromSeconds(900);
|
||||
options.IdleTimeout = TimeSpan.FromSeconds(1800);
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString();
|
||||
});
|
||||
|
|
|
@ -639,7 +639,7 @@ a.text-dark:hover {
|
|||
}
|
||||
|
||||
.bg-success {
|
||||
background-color: #81c868 !important;
|
||||
background-color: #296a12 !important;
|
||||
}
|
||||
|
||||
.bg-info {
|
||||
|
@ -647,11 +647,11 @@ a.text-dark:hover {
|
|||
}
|
||||
|
||||
.bg-warning {
|
||||
background-color: #ffbd4a !important;
|
||||
background-color: #563a09 !important;
|
||||
}
|
||||
|
||||
.bg-danger {
|
||||
background-color: #f05050 !important;
|
||||
background-color: #6e0e0e !important;
|
||||
}
|
||||
|
||||
.bg-muted {
|
||||
|
@ -759,7 +759,7 @@ a.text-dark:hover {
|
|||
}
|
||||
|
||||
.label-success {
|
||||
background-color: #81c868;
|
||||
background-color: #3b5e2f;
|
||||
}
|
||||
|
||||
.label-info {
|
||||
|
@ -767,11 +767,11 @@ a.text-dark:hover {
|
|||
}
|
||||
|
||||
.label-warning {
|
||||
background-color: #ffbd4a;
|
||||
background-color: #847f0a;
|
||||
}
|
||||
|
||||
.label-danger {
|
||||
background-color: #f05050;
|
||||
background-color: #601f1f;
|
||||
}
|
||||
|
||||
.label-purple {
|
||||
|
@ -829,7 +829,7 @@ a.text-dark:hover {
|
|||
}
|
||||
|
||||
.badge-success {
|
||||
background-color: #81c868;
|
||||
background-color: #307516;
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
|
@ -837,11 +837,11 @@ a.text-dark:hover {
|
|||
}
|
||||
|
||||
.badge-warning {
|
||||
background-color: #ffbd4a;
|
||||
background-color: #6f5019;
|
||||
}
|
||||
|
||||
.badge-danger {
|
||||
background-color: #f05050;
|
||||
background-color: #6a1414;
|
||||
}
|
||||
|
||||
.badge-purple {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{DC985FA9-87CC-4C60-A587-E646E74A1A4A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Monitor", "Monitor\Monitor.csproj", "{D967C466-E4BF-40A9-84FD-698079FAD3D5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PTMagic", "PTMagic\PTMagic.csproj", "{D81F5541-438E-42C7-B6E7-B859875B18A8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC985FA9-87CC-4C60-A587-E646E74A1A4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC985FA9-87CC-4C60-A587-E646E74A1A4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC985FA9-87CC-4C60-A587-E646E74A1A4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC985FA9-87CC-4C60-A587-E646E74A1A4A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D967C466-E4BF-40A9-84FD-698079FAD3D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D967C466-E4BF-40A9-84FD-698079FAD3D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D967C466-E4BF-40A9-84FD-698079FAD3D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D967C466-E4BF-40A9-84FD-698079FAD3D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D81F5541-438E-42C7-B6E7-B859875B18A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D81F5541-438E-42C7-B6E7-B859875B18A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D81F5541-438E-42C7-B6E7-B859875B18A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D81F5541-438E-42C7-B6E7-B859875B18A8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3646F7E-91F6-4D66-9B1B-2B74317580A4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -6,7 +6,7 @@ using Core.Helper;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
||||
[assembly: AssemblyVersion("2.6.1")]
|
||||
[assembly: AssemblyVersion("2.7.1")]
|
||||
[assembly: AssemblyProduct("PT Magic")]
|
||||
|
||||
namespace PTMagic
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
"ProfitTrailerMonitorURLXtra": "", // URLs for additional bots you want PTM to update (optional - comma separated list)
|
||||
"ProfitTrailerDefaultSettingName": "default", // Your Profit Trailer default setting name (needed to change your settings)
|
||||
"Exchange": "Bittrex", // The exchange your are running Profit Trailer on
|
||||
"StartBalance": 0, // The balance you had in your wallet when you started working with Profit Trailer
|
||||
"TimezoneOffset": "+0:00", // Your timezone offset from UTC time
|
||||
"MainFiatCurrency": "USD", // Your main fiat currency that will be used in the monitor
|
||||
"FloodProtectionMinutes": 0, // If a price trend is just zig-zagging around its trigger, you may want to protect your settings from getting switched back and forth every minute
|
||||
"InstanceName": "PT Magic", // The name of the instance of this bot. This will be used in your monitor and your Telegram messages. In case you are running more than one bot, you may set different names to separate them
|
||||
"CoinMarketCapAPIKey": "", //CoinMarketCap Api
|
||||
"FreeCurrencyConverterAPIKey": "" // If "MainFiatCurrency" above is anything other than USD, you must obtain an API key from https://free.currencyconverterapi.com/free-api-key
|
||||
//"FreeCurrencyConverterAPIKey": "" // If "MainFiatCurrency" above is anything other than USD, you must obtain an API key from https://free.currencyconverterapi.com/free-api-key
|
||||
},
|
||||
"Monitor": {
|
||||
"IsPasswordProtected": true, // Defines if your monitor will be asking to setup a password on its first start
|
||||
|
@ -24,8 +21,9 @@
|
|||
"Port": 8080, // The port you want to run your monitor on
|
||||
"RootUrl": "/", // The root Url of your monitor
|
||||
"AnalyzerChart": "", // By default the chart on the Market Analyzer page will use your default currency against USD. You can change that here. (eg., BTCEUR)
|
||||
"GraphIntervalMinutes": 60, // The interval for the monitor market trend graph to draw points
|
||||
"GraphMaxTimeframeHours": 24, // This will enable you to define the timeframe that your graph for market trends covers
|
||||
"GraphIntervalMinutes": 60, // The interval for the monitor market trend graph to draw points in minutes
|
||||
"GraphMaxTimeframeHours": 24, // This will enable you to define the timeframe that your graph for market trends covers in hours
|
||||
"ProfitsMaxTimeframeDays": 30, // This will enable you to define the timeframe for your dashboard profits graph in days
|
||||
"RefreshSeconds": 30, // The refresh interval of your monitor main page
|
||||
"LinkPlatform": "TradingView", // The platform to which the pair name will link if you click on it
|
||||
"MaxTopMarkets": 20, // The amount of top markets being shown in your Sales Analyzer
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
"ProfitTrailerMonitorURLXtra": "", // URLs for additional bots you want PTM to update (optional - comma separated list)
|
||||
"ProfitTrailerDefaultSettingName": "default", // Your Profit Trailer default setting name (needed to change your settings)
|
||||
"Exchange": "Bittrex", // The exchange your are running Profit Trailer on
|
||||
"StartBalance": 0, // The balance you had in your wallet when you started working with Profit Trailer
|
||||
"TimezoneOffset": "+0:00", // Your timezone offset from UTC time
|
||||
"MainFiatCurrency": "USD", // Your main fiat currency that will be used in the monitor
|
||||
"FloodProtectionMinutes": 0, // If a price trend is just zig-zagging around its trigger, you may want to protect your settings from getting switched back and forth every minute
|
||||
"FloodProtectionMinutes": 0, // If a price trend is just zig-zagging around its trigger, you may want to protect your settings from getting switched back and forth every minute
|
||||
"InstanceName": "PT Magic", // The name of the instance of this bot. This will be used in your monitor and your Telegram messages. In case you are running more than one bot, you may set different names to separate them
|
||||
"CoinMarketCapAPIKey": "", //CoinMarketCap Api
|
||||
"FreeCurrencyConverterAPIKey": "" // If "MainFiatCurrency" above is anything other than USD, you must obtain an API key from https://free.currencyconverterapi.com/free-api-key
|
||||
},
|
||||
"Monitor": {
|
||||
"IsPasswordProtected": true, // Defines if your monitor will be asking to setup a password on its first start
|
||||
|
@ -24,8 +21,9 @@
|
|||
"Port": 8080, // The port you want to run your monitor on
|
||||
"RootUrl": "/", // The root Url of your monitor
|
||||
"AnalyzerChart": "", // By default the chart on the Market Analyzer page will use your default currency against USD. You can change that here. (eg., BTCEUR)
|
||||
"GraphIntervalMinutes": 60, // The interval for the monitor market trend graph to draw points
|
||||
"GraphMaxTimeframeHours": 24, // This will enable you to define the timeframe that your graph for market trends covers
|
||||
"GraphIntervalMinutes": 60, // The interval for the monitor market trend graph to draw points in minutes
|
||||
"GraphMaxTimeframeHours": 24, // This will enable you to define the timeframe that your graph for market trends covers in hours
|
||||
"ProfitsMaxTimeframeDays": 30, // This will enable you to define the timeframe for your dashboard profits graph in days
|
||||
"RefreshSeconds": 30, // The refresh interval of your monitor main page
|
||||
"LinkPlatform": "TradingView", // The platform to which the pair name will link if you click on it
|
||||
"MaxTopMarkets": 20, // The amount of top markets being shown in your Sales Analyzer
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
- This version of PT Magic only works with Profit Trailer v2.4.x and above
|
||||
|
||||
### .Net
|
||||
- PTMagic requires .Net Core Runtime 3.1 on the host operating system (download: https://dotnet.microsoft.com/download)
|
||||
- PTMagic requires .Net Core Runtime 7 on the host operating system (download: https://dotnet.microsoft.com/download)
|
||||
|
||||
### Settings
|
||||
- **If you are updating from any version of PTMagic prior to 2.4.1,** check the default settings included with this release for any new lines that might need to be added to your settings.general.json file.
|
||||
|
|
Loading…
Reference in New Issue