Summary
This commit is contained in:
parent
08554da6ee
commit
ae15f7440f
|
@ -314,8 +314,8 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public double MainMarketPrice { get; set; } = 0;
|
||||
private PropertiesData _propertiesData = new PropertiesData();
|
||||
public string MainFiatCurrency => _propertiesData.Currency;
|
||||
private SummaryData _summaryData = new SummaryData();
|
||||
public double MainFiatCurrencyExchangeRate => _summaryData.FiatConversionRate;
|
||||
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>();
|
||||
|
@ -447,6 +447,15 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public string Date { get; set; }
|
||||
public double CumulativeProfitCurrency { 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 class PTStrategy
|
||||
|
@ -524,8 +533,9 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public List<Strategy> BuyStrategies { get; set; } = new List<Strategy>();
|
||||
}
|
||||
|
||||
public class SummaryData
|
||||
{ public double Balance { get; set; }
|
||||
public class MiscData
|
||||
{
|
||||
public double Balance { get; set; }
|
||||
public double StartBalance { get; set; }
|
||||
public double FiatConversionRate { get; set; }
|
||||
public double PairsValue { get; set; }
|
||||
|
@ -533,5 +543,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
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; }
|
||||
}
|
||||
}
|
|
@ -15,10 +15,11 @@ namespace Core.Main.DataObjects
|
|||
|
||||
public class ProfitTrailerData
|
||||
{
|
||||
private SummaryData _summary = null;
|
||||
private MiscData _misc = null;
|
||||
private PropertiesData _properties = null;
|
||||
private StatsData _stats = null;
|
||||
private List<DailyPNLData> _dailyPNL = new List<DailyPNLData>();
|
||||
private List<MonthlyStatsData> _monthlyStats = new List<MonthlyStatsData>();
|
||||
private decimal? _totalProfit = null;
|
||||
public decimal? TotalProfit
|
||||
{
|
||||
|
@ -38,20 +39,23 @@ namespace Core.Main.DataObjects
|
|||
private PTMagicConfiguration _systemConfiguration = null;
|
||||
private TransactionData _transactionData = null;
|
||||
private DateTime _dailyPNLRefresh = DateTime.UtcNow;
|
||||
private DateTime _monthlyStatsRefresh = DateTime.UtcNow;
|
||||
private DateTime _statsRefresh = DateTime.UtcNow;
|
||||
private DateTime _buyLogRefresh = DateTime.UtcNow;
|
||||
private DateTime _sellLogRefresh = DateTime.UtcNow;
|
||||
private DateTime _dcaLogRefresh = DateTime.UtcNow;
|
||||
private DateTime _summaryRefresh = DateTime.UtcNow;
|
||||
private DateTime _miscRefresh = DateTime.UtcNow;
|
||||
private DateTime _propertiesRefresh = DateTime.UtcNow;
|
||||
private volatile object _dailyStatsLock = new object();
|
||||
private volatile object _dailyPNLLock = new object();
|
||||
private volatile object _dailyPNLLock = new object();
|
||||
private volatile object _monthlyStatsLock = new object();
|
||||
private volatile object _statsLock = new object();
|
||||
private volatile object _buyLock = new object();
|
||||
private volatile object _sellLock = new object();
|
||||
private volatile object _dcaLock = new object();
|
||||
private volatile object _summaryLock = new object();
|
||||
private volatile object _propertiesLock = new object(); private TimeSpan? _offsetTimeSpan = null;
|
||||
private volatile object _miscLock = new object();
|
||||
private volatile object _propertiesLock = new object();
|
||||
private TimeSpan? _offsetTimeSpan = null;
|
||||
public void DoLog(string message)
|
||||
{
|
||||
// Implement your logging logic here
|
||||
|
@ -87,29 +91,29 @@ namespace Core.Main.DataObjects
|
|||
}
|
||||
}
|
||||
|
||||
public SummaryData Summary
|
||||
public MiscData Misc
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_summary == null || (DateTime.UtcNow > _summaryRefresh))
|
||||
if (_misc == null || (DateTime.UtcNow > _miscRefresh))
|
||||
{
|
||||
lock (_summaryLock)
|
||||
lock (_miscLock)
|
||||
{
|
||||
// Thread double locking
|
||||
if (_summary == null || (DateTime.UtcNow > _summaryRefresh))
|
||||
if (_misc == null || (DateTime.UtcNow > _miscRefresh))
|
||||
{
|
||||
_summary = BuildSummaryData(GetDataFromProfitTrailer("api/v2/data/misc"));
|
||||
_summaryRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
_misc = BuildMiscData(GetDataFromProfitTrailer("api/v2/data/misc"));
|
||||
_miscRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _summary;
|
||||
return _misc;
|
||||
}
|
||||
}
|
||||
private SummaryData BuildSummaryData(dynamic PTData)
|
||||
private MiscData BuildMiscData(dynamic PTData)
|
||||
{
|
||||
return new SummaryData()
|
||||
return new MiscData()
|
||||
{
|
||||
Market = PTData.market,
|
||||
FiatConversionRate = PTData.priceDataFiatConversionRate,
|
||||
|
@ -119,6 +123,8 @@ namespace Core.Main.DataObjects
|
|||
PendingValue = PTData.totalPendingCurrentValue,
|
||||
DustValue = PTData.totalDustCurrentValue,
|
||||
StartBalance = PTData.startBalance,
|
||||
TotalCurrentValue = PTData.totalCurrentValue,
|
||||
TimeZoneOffset = PTData.timeZoneOffset,
|
||||
};
|
||||
}
|
||||
public PropertiesData Properties
|
||||
|
@ -154,27 +160,6 @@ namespace Core.Main.DataObjects
|
|||
BaseUrl = PTProperties.baseUrl
|
||||
};
|
||||
}
|
||||
// public StatsData Stats
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (_stats == null || DateTime.UtcNow > _statsRefresh)
|
||||
// {
|
||||
// lock (_statsLock)
|
||||
// {
|
||||
// if (_stats == null || DateTime.UtcNow > _statsRefresh)
|
||||
// {
|
||||
// dynamic statsDataJson = GetDataFromProfitTrailer("/api/v2/data/stats");
|
||||
// JObject statsDataJObject = statsDataJson as JObject;
|
||||
// JObject basicSection = (JObject)statsDataJObject["basic"];
|
||||
// _stats = BuildStatsData(basicSection);
|
||||
// _statsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return _stats;
|
||||
// }
|
||||
// }
|
||||
|
||||
public StatsData Stats
|
||||
{
|
||||
|
@ -239,37 +224,90 @@ namespace Core.Main.DataObjects
|
|||
FundingTotal = statsDataJson["totalFunding"]
|
||||
};
|
||||
}
|
||||
// public List<DailyPNLData> DailyPNL
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||
// {
|
||||
// lock (_dailyPNLLock)
|
||||
// {
|
||||
// if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||
// {
|
||||
// dynamic dailyPNLDataJson = GetDataFromProfitTrailer("/api/v2/data/stats");
|
||||
// JObject dailyPNLDataJObject = dailyPNLDataJson as JObject;
|
||||
// JArray dailyPNLSection = (JArray)dailyPNLDataJObject["extra"]["dailyPNLStats"];
|
||||
// _dailyPNL = dailyPNLSection.Select(j => BuildDailyPNLData(j as JObject)).ToList();
|
||||
// _dailyPNLRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return _dailyPNL;
|
||||
// }
|
||||
// }
|
||||
|
||||
public List<DailyPNLData> DailyPNL
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||
{
|
||||
lock (_dailyPNLLock)
|
||||
{
|
||||
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||
{
|
||||
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||
using (var reader = new StreamReader(stream))
|
||||
using (var jsonReader = new JsonTextReader(reader))
|
||||
{
|
||||
JObject basicSection = null;
|
||||
JObject extraSection = null;
|
||||
|
||||
while (jsonReader.Read())
|
||||
{
|
||||
if (jsonReader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
if ((string)jsonReader.Value == "basic")
|
||||
{
|
||||
jsonReader.Read(); // Move to the value of the "basic" property
|
||||
basicSection = JObject.Load(jsonReader);
|
||||
}
|
||||
else if ((string)jsonReader.Value == "extra")
|
||||
{
|
||||
jsonReader.Read(); // Move to the value of the "extra" property
|
||||
extraSection = JObject.Load(jsonReader);
|
||||
}
|
||||
}
|
||||
|
||||
if (basicSection != null && extraSection != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (basicSection != null &&
|
||||
((_totalProfit == null ||
|
||||
!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) ||
|
||||
(_totalSales == null ||
|
||||
!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>()))))
|
||||
{
|
||||
_totalProfit = basicSection["totalProfit"].Value<decimal>();
|
||||
_totalSales = basicSection["totalSales"].Value<decimal>();
|
||||
|
||||
if (extraSection != null)
|
||||
{
|
||||
JArray dailyPNLSection = (JArray)extraSection["dailyPNLStats"];
|
||||
_dailyPNL = dailyPNLSection.Select(j => BuildDailyPNLData(j as JObject)).ToList();
|
||||
_dailyPNLRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _dailyPNL;
|
||||
}
|
||||
}
|
||||
public int GetTotalDays()
|
||||
{
|
||||
return DailyPNL?.Count ?? 0;
|
||||
}
|
||||
private DailyPNLData BuildDailyPNLData(dynamic dailyPNLDataJson)
|
||||
{
|
||||
return new DailyPNLData()
|
||||
{
|
||||
Date = dailyPNLDataJson["date"],
|
||||
CumulativeProfitCurrency = dailyPNLDataJson["cumulativeProfitCurrency"],
|
||||
Order = dailyPNLDataJson["order"],
|
||||
};
|
||||
}
|
||||
public List<MonthlyStatsData> MonthlyStats
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||
if (_monthlyStats == null || DateTime.UtcNow > _monthlyStatsRefresh)
|
||||
{
|
||||
lock (_dailyPNLLock)
|
||||
lock (_monthlyStatsLock)
|
||||
{
|
||||
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||
if (_monthlyStats == null || DateTime.UtcNow > _monthlyStatsRefresh)
|
||||
{
|
||||
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||
using (var reader = new StreamReader(stream))
|
||||
|
@ -300,36 +338,43 @@ namespace Core.Main.DataObjects
|
|||
}
|
||||
}
|
||||
|
||||
if (basicSection != null &&
|
||||
((_totalProfit == null ||
|
||||
!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) ||
|
||||
(_totalSales == null ||
|
||||
!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>()))))
|
||||
if (basicSection != null)// &&
|
||||
//((_totalProfit == null ||
|
||||
//!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) ||
|
||||
//(_totalSales == null ||
|
||||
//!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>()))))
|
||||
{
|
||||
_totalProfit = basicSection["totalProfit"].Value<decimal>();
|
||||
_totalSales = basicSection["totalSales"].Value<decimal>();
|
||||
//_totalProfit = basicSection["totalProfit"].Value<decimal>();
|
||||
//_totalSales = basicSection["totalSales"].Value<decimal>();
|
||||
|
||||
if (extraSection != null)
|
||||
{
|
||||
JArray dailyPNLSection = (JArray)extraSection["dailyPNLStats"];
|
||||
_dailyPNL = dailyPNLSection.Select(j => BuildDailyPNLData(j as JObject)).ToList();
|
||||
_dailyPNLRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
JArray monthlyStatsSection = (JArray)extraSection["monthlyStats"];
|
||||
_monthlyStats = monthlyStatsSection.Select(j => BuildMonthlyStatsData(j as JObject)).ToList();
|
||||
_monthlyStatsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _dailyPNL;
|
||||
return _monthlyStats;
|
||||
}
|
||||
}
|
||||
private DailyPNLData BuildDailyPNLData(dynamic dailyPNLDataJson)
|
||||
|
||||
public int GetTotalMonths()
|
||||
{
|
||||
return new DailyPNLData()
|
||||
return MonthlyStats?.Count ?? 0;
|
||||
}
|
||||
|
||||
private MonthlyStatsData BuildMonthlyStatsData(dynamic monthlyStatsDataJson)
|
||||
{
|
||||
return new MonthlyStatsData()
|
||||
{
|
||||
Date = dailyPNLDataJson["date"],
|
||||
CumulativeProfitCurrency = dailyPNLDataJson["cumulativeProfitCurrency"],
|
||||
Order = dailyPNLDataJson["order"],
|
||||
Month = monthlyStatsDataJson["month"],
|
||||
TotalSales = monthlyStatsDataJson["totalSales"],
|
||||
TotalProfitCurrency = monthlyStatsDataJson["totalProfitCurrency"],
|
||||
AvgGrowth = monthlyStatsDataJson["avgGrowth"],
|
||||
};
|
||||
}
|
||||
public List<SellLogData> SellLog
|
||||
|
@ -459,33 +504,33 @@ namespace Core.Main.DataObjects
|
|||
public double GetCurrentBalance()
|
||||
{
|
||||
return
|
||||
(this.Summary.Balance);
|
||||
(this.Misc.Balance);
|
||||
}
|
||||
public double GetPairsBalance()
|
||||
{
|
||||
return
|
||||
(this.Summary.PairsValue);
|
||||
(this.Misc.PairsValue);
|
||||
}
|
||||
public double GetDCABalance()
|
||||
{
|
||||
return
|
||||
(this.Summary.DCAValue);
|
||||
(this.Misc.DCAValue);
|
||||
}
|
||||
public double GetPendingBalance()
|
||||
{
|
||||
return
|
||||
(this.Summary.PendingValue);
|
||||
(this.Misc.PendingValue);
|
||||
}
|
||||
public double GetDustBalance()
|
||||
{
|
||||
return
|
||||
(this.Summary.DustValue);
|
||||
(this.Misc.DustValue);
|
||||
}
|
||||
|
||||
|
||||
public double GetSnapshotBalance(DateTime snapshotDateTime)
|
||||
{
|
||||
double result = _summary.StartBalance;
|
||||
double result = _misc.StartBalance;
|
||||
|
||||
result += this.SellLog.FindAll(sl => sl.SoldDate.Date < snapshotDateTime.Date).Sum(sl => sl.Profit);
|
||||
result += this.TransactionData.Transactions.FindAll(t => t.UTCDateTime < snapshotDateTime).Sum(t => t.Amount);
|
||||
|
|
|
@ -1117,35 +1117,6 @@ namespace Core.Main
|
|||
}
|
||||
}
|
||||
|
||||
//private void GetMainFiatCurrencyDetails()
|
||||
//{
|
||||
//this.LastRuntimeSummary.MainFiatCurrency = this.PropertiesData.Currency;
|
||||
//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()
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
}
|
||||
<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 TCV reported by Profit Trailer."></i></small></th>
|
||||
<th class="text-right">Starting Value: <text class="text-autocolor"> @Model.SummaryData.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="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 found in your settings file"></i></small></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
@ -50,7 +50,6 @@
|
|||
<div class="col-md-12">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">No Sales!</h4>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
|
@ -59,47 +58,49 @@
|
|||
<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.SummaryData.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.GetTotalDays();
|
||||
double totalSales = Model.PTData.Stats.TotalSales;
|
||||
double totalProfit = Model.PTData.Stats.TotalProfit;
|
||||
double totalFundingFees = Model.PTData.Stats.FundingTotal;
|
||||
double totalPercentGain = Model.PTData.Stats.TotalProfitPerc;
|
||||
double 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;
|
||||
string percentGainText = totalPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
}
|
||||
<h4 class="m-t-0 header-title" style="display: inline;">Sales Analysis </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 (@totalDays Days)</th>
|
||||
<th class="text-right">AVG/Month (@totalMonths Months) <small><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top"
|
||||
title="Total months is based on the size of the actual calendar 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>Profit @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>
|
||||
</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>
|
||||
<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>
|
||||
<tr>
|
||||
<th>% Gain</th>
|
||||
|
@ -107,6 +108,21 @@
|
|||
<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>
|
||||
@if(Model.PropertiesData.IsLeverageExchange)
|
||||
{
|
||||
<tr>
|
||||
<th>Funding Fees</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>Profit @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>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -127,7 +143,7 @@
|
|||
<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. @Model.PTData.Properties.Currency Value</th>
|
||||
<th class="text-right">Est. Gain</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -135,25 +151,25 @@
|
|||
<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">@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 - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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">@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 - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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">@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 - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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">@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 - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
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;
|
||||
|
||||
|
@ -12,7 +11,12 @@ namespace Monitor.Pages
|
|||
public class SalesAnalyzer : _Internal.BasePageModelSecure
|
||||
{
|
||||
public ProfitTrailerData PTData = null;
|
||||
public SummaryData SummaryData { get; set; }
|
||||
public MiscData MiscData { get; set; }
|
||||
public PropertiesData PropertiesData { get; set; }
|
||||
public StatsData StatsData { get; set; }
|
||||
public List<DailyPNLData> DailyPNL { get; set; }
|
||||
public List<MonthlyStatsData> MonthlyStats { get; set; }
|
||||
|
||||
public string TradesChartDataJSON = "";
|
||||
public string ProfitChartDataJSON = "";
|
||||
public string BalanceChartDataJSON = "";
|
||||
|
@ -22,17 +26,26 @@ namespace Monitor.Pages
|
|||
public Dictionary<DateTime, double> MonthlyGains = new Dictionary<DateTime, double>();
|
||||
public DateTimeOffset DateTimeNow = Constants.confMinDate;
|
||||
public double totalCurrentValue = 0;
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
BindData();
|
||||
BuildTCV();
|
||||
}
|
||||
|
||||
private void BindData()
|
||||
{
|
||||
PTData = this.PtDataObject;
|
||||
SummaryData = this.PTData.Summary;
|
||||
MiscData = this.PTData.Misc;
|
||||
PropertiesData = this.PTData.Properties;
|
||||
StatsData = this.PTData.Stats;
|
||||
MonthlyStats = this.PTData.MonthlyStats;
|
||||
DailyPNL = this.PTData.DailyPNL;
|
||||
|
||||
//List<MonthlyStatsData> monthlyStatsData = this.PTData.MonthlyStats;
|
||||
//List<DailyPNLData> dailyPNLData = this.PTData.DailyPNL;
|
||||
|
||||
|
||||
// Convert local offset time to UTC
|
||||
TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
|
||||
|
@ -40,6 +53,49 @@ namespace Monitor.Pages
|
|||
|
||||
BuildTopMarkets();
|
||||
BuildSalesChartData();
|
||||
BuildTCV();
|
||||
//MonthlyAverages(monthlyStatsData, PTData.Stats.FundingTotal);
|
||||
}
|
||||
|
||||
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;
|
||||
//Console.WriteLine("Month: {0}, Weight: {1}", monthStat.Month, weight);
|
||||
}
|
||||
return (totalMonths, startDate, endDate);
|
||||
}
|
||||
private void BuildTopMarkets()
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Monitor.Pages
|
|||
{
|
||||
public string ValidationMessage = "";
|
||||
public ProfitTrailerData PTData = null;
|
||||
public SummaryData SummaryData { get; set; }
|
||||
public MiscData MiscData { get; set; }
|
||||
|
||||
private string GetTimezoneOffsetString(TimeZoneInfo tzi)
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ namespace Monitor.Pages
|
|||
{
|
||||
base.Init();
|
||||
PTData = this.PtDataObject;
|
||||
SummaryData = this.PTData.Summary;
|
||||
MiscData = this.PTData.Misc;
|
||||
|
||||
string notification = GetStringParameter("n", "");
|
||||
if (notification.Equals("BackupRestored"))
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<div class="col-md-3 px-1">
|
||||
<div class="card-box px-3" style="height:320px;">
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"><i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="You dashboard is set to refresh every @Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds seconds in general settings."></i></div>
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
||||
@{
|
||||
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||
if (Model.totalCurrentValue > 100) {
|
||||
|
@ -35,8 +35,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.SummaryData.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.SummaryData.StartBalance) / Model.SummaryData.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">
|
||||
|
@ -166,12 +166,12 @@
|
|||
var totalProfitPercent = overviewStats.TotalProfitPerc;
|
||||
//var totalFundingGain = totalProfitPercent * ((totalProfit + totalFunding) / totalProfit);
|
||||
|
||||
double todaysProfitFiat = Math.Round((todaysProfit + todaysFunding) * Model.PTData.Summary.FiatConversionRate, 2);
|
||||
double yesterdaysProfitFiat = Math.Round((yesterdaysProfit + yesterdaysFunding) * Model.PTData.Summary.FiatConversionRate, 2);
|
||||
double last7DaysProfitFiat = Math.Round((last7DaysProfit + last7DaysFunding) * Model.PTData.Summary.FiatConversionRate, 2);
|
||||
double thisMonthProfitFiat = Math.Round((thisMonthProfit + thisMonthFunding) * Model.PTData.Summary.FiatConversionRate, 2);
|
||||
double lastMonthProfitFiat = Math.Round((lastMonthProfit + lastMonthFunding) * Model.PTData.Summary.FiatConversionRate, 2);
|
||||
double totalProfitFiat = Math.Round((totalProfit + totalFunding) * Model.PTData.Summary.FiatConversionRate, 2);
|
||||
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;
|
||||
|
||||
|
@ -181,7 +181,7 @@
|
|||
<tr>
|
||||
<th></th>
|
||||
<th class="text-right">Sales</th>
|
||||
<th class="text-right">Profit @Model.PTData.Summary.Market</th>
|
||||
<th class="text-right">Profit @Model.PTData.Misc.Market</th>
|
||||
<th class="text-right">Gain</th>
|
||||
@if (futuresFunding)
|
||||
{
|
||||
|
|
|
@ -17,8 +17,7 @@ namespace Monitor.Pages
|
|||
public ProfitTrailerData PTData = null;
|
||||
public StatsData StatsData { get; set; }
|
||||
public PropertiesData PropertiesData { get; set; }
|
||||
public SummaryData SummaryData { 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; }
|
||||
|
@ -42,8 +41,7 @@ namespace Monitor.Pages
|
|||
PTData = this.PtDataObject;
|
||||
StatsData = this.PTData.Stats;
|
||||
PropertiesData = this.PTData.Properties;
|
||||
SummaryData = this.PTData.Summary;
|
||||
|
||||
MiscData = this.PTData.Misc;
|
||||
List<DailyPNLData> dailyPNLData = this.PTData.DailyPNL;
|
||||
|
||||
// Cleanup temp files
|
||||
|
@ -215,7 +213,7 @@ namespace Monitor.Pages
|
|||
// Convert the list to a JSON string using Newtonsoft.Json
|
||||
ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] {
|
||||
new {
|
||||
key = "Profit in " + PTData.Properties.Currency,
|
||||
key = "Profit in " + PTData.Misc.Market,
|
||||
color = Constants.ChartLineColors[1],
|
||||
values = profitPerDayList
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue