This commit is contained in:
HojouFotytu 2024-01-15 23:12:46 +09:00
parent 08554da6ee
commit ae15f7440f
8 changed files with 268 additions and 170 deletions

View File

@ -314,8 +314,8 @@ namespace Core.Main.DataObjects.PTMagicData
public double MainMarketPrice { get; set; } = 0; public double MainMarketPrice { get; set; } = 0;
private PropertiesData _propertiesData = new PropertiesData(); private PropertiesData _propertiesData = new PropertiesData();
public string MainFiatCurrency => _propertiesData.Currency; public string MainFiatCurrency => _propertiesData.Currency;
private SummaryData _summaryData = new SummaryData(); private MiscData _miscData = new MiscData();
public double MainFiatCurrencyExchangeRate => _summaryData.FiatConversionRate; public double MainFiatCurrencyExchangeRate => _miscData.FiatConversionRate;
public List<StrategySummary> BuyStrategies { get; set; } = new List<StrategySummary>(); public List<StrategySummary> BuyStrategies { get; set; } = new List<StrategySummary>();
public List<StrategySummary> SellStrategies { 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> DCABuyStrategies { get; set; } = new List<StrategySummary>();
@ -447,6 +447,15 @@ namespace Core.Main.DataObjects.PTMagicData
public string Date { get; set; } public string Date { get; set; }
public double CumulativeProfitCurrency { get; set; } public double CumulativeProfitCurrency { get; set; }
public double Order { 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 public class PTStrategy
@ -524,8 +533,9 @@ namespace Core.Main.DataObjects.PTMagicData
public List<Strategy> BuyStrategies { get; set; } = new List<Strategy>(); public List<Strategy> BuyStrategies { get; set; } = new List<Strategy>();
} }
public class SummaryData public class MiscData
{ public double Balance { get; set; } {
public double Balance { get; set; }
public double StartBalance { get; set; } public double StartBalance { get; set; }
public double FiatConversionRate { get; set; } public double FiatConversionRate { get; set; }
public double PairsValue { get; set; } public double PairsValue { get; set; }
@ -533,5 +543,7 @@ namespace Core.Main.DataObjects.PTMagicData
public double PendingValue { get; set; } public double PendingValue { get; set; }
public double DustValue { get; set; } public double DustValue { get; set; }
public string Market { get; set; } public string Market { get; set; }
public string TotalCurrentValue { get; set; }
public string TimeZoneOffset { get; set; }
} }
} }

View File

@ -15,10 +15,11 @@ namespace Core.Main.DataObjects
public class ProfitTrailerData public class ProfitTrailerData
{ {
private SummaryData _summary = null; private MiscData _misc = null;
private PropertiesData _properties = null; private PropertiesData _properties = null;
private StatsData _stats = null; private StatsData _stats = null;
private List<DailyPNLData> _dailyPNL = new List<DailyPNLData>(); private List<DailyPNLData> _dailyPNL = new List<DailyPNLData>();
private List<MonthlyStatsData> _monthlyStats = new List<MonthlyStatsData>();
private decimal? _totalProfit = null; private decimal? _totalProfit = null;
public decimal? TotalProfit public decimal? TotalProfit
{ {
@ -38,20 +39,23 @@ namespace Core.Main.DataObjects
private PTMagicConfiguration _systemConfiguration = null; private PTMagicConfiguration _systemConfiguration = null;
private TransactionData _transactionData = null; private TransactionData _transactionData = null;
private DateTime _dailyPNLRefresh = DateTime.UtcNow; private DateTime _dailyPNLRefresh = DateTime.UtcNow;
private DateTime _monthlyStatsRefresh = DateTime.UtcNow;
private DateTime _statsRefresh = DateTime.UtcNow; private DateTime _statsRefresh = DateTime.UtcNow;
private DateTime _buyLogRefresh = DateTime.UtcNow; private DateTime _buyLogRefresh = DateTime.UtcNow;
private DateTime _sellLogRefresh = DateTime.UtcNow; private DateTime _sellLogRefresh = DateTime.UtcNow;
private DateTime _dcaLogRefresh = DateTime.UtcNow; private DateTime _dcaLogRefresh = DateTime.UtcNow;
private DateTime _summaryRefresh = DateTime.UtcNow; private DateTime _miscRefresh = DateTime.UtcNow;
private DateTime _propertiesRefresh = DateTime.UtcNow; private DateTime _propertiesRefresh = DateTime.UtcNow;
private volatile object _dailyStatsLock = new object(); 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 _statsLock = new object();
private volatile object _buyLock = new object(); private volatile object _buyLock = new object();
private volatile object _sellLock = new object(); private volatile object _sellLock = new object();
private volatile object _dcaLock = new object(); private volatile object _dcaLock = new object();
private volatile object _summaryLock = new object(); private volatile object _miscLock = new object();
private volatile object _propertiesLock = new object(); private TimeSpan? _offsetTimeSpan = null; private volatile object _propertiesLock = new object();
private TimeSpan? _offsetTimeSpan = null;
public void DoLog(string message) public void DoLog(string message)
{ {
// Implement your logging logic here // Implement your logging logic here
@ -87,29 +91,29 @@ namespace Core.Main.DataObjects
} }
} }
public SummaryData Summary public MiscData Misc
{ {
get get
{ {
if (_summary == null || (DateTime.UtcNow > _summaryRefresh)) if (_misc == null || (DateTime.UtcNow > _miscRefresh))
{ {
lock (_summaryLock) lock (_miscLock)
{ {
// Thread double locking // Thread double locking
if (_summary == null || (DateTime.UtcNow > _summaryRefresh)) if (_misc == null || (DateTime.UtcNow > _miscRefresh))
{ {
_summary = BuildSummaryData(GetDataFromProfitTrailer("api/v2/data/misc")); _misc = BuildMiscData(GetDataFromProfitTrailer("api/v2/data/misc"));
_summaryRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1); _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, Market = PTData.market,
FiatConversionRate = PTData.priceDataFiatConversionRate, FiatConversionRate = PTData.priceDataFiatConversionRate,
@ -119,6 +123,8 @@ namespace Core.Main.DataObjects
PendingValue = PTData.totalPendingCurrentValue, PendingValue = PTData.totalPendingCurrentValue,
DustValue = PTData.totalDustCurrentValue, DustValue = PTData.totalDustCurrentValue,
StartBalance = PTData.startBalance, StartBalance = PTData.startBalance,
TotalCurrentValue = PTData.totalCurrentValue,
TimeZoneOffset = PTData.timeZoneOffset,
}; };
} }
public PropertiesData Properties public PropertiesData Properties
@ -154,27 +160,6 @@ namespace Core.Main.DataObjects
BaseUrl = PTProperties.baseUrl 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 public StatsData Stats
{ {
@ -239,37 +224,90 @@ namespace Core.Main.DataObjects
FundingTotal = statsDataJson["totalFunding"] 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 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 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 stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
using (var reader = new StreamReader(stream)) using (var reader = new StreamReader(stream))
@ -300,36 +338,43 @@ namespace Core.Main.DataObjects
} }
} }
if (basicSection != null && if (basicSection != null)// &&
((_totalProfit == null || //((_totalProfit == null ||
!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) || //!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) ||
(_totalSales == null || //(_totalSales == null ||
!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>())))) //!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>()))))
{ {
_totalProfit = basicSection["totalProfit"].Value<decimal>(); //_totalProfit = basicSection["totalProfit"].Value<decimal>();
_totalSales = basicSection["totalSales"].Value<decimal>(); //_totalSales = basicSection["totalSales"].Value<decimal>();
if (extraSection != null) if (extraSection != null)
{ {
JArray dailyPNLSection = (JArray)extraSection["dailyPNLStats"]; JArray monthlyStatsSection = (JArray)extraSection["monthlyStats"];
_dailyPNL = dailyPNLSection.Select(j => BuildDailyPNLData(j as JObject)).ToList(); _monthlyStats = monthlyStatsSection.Select(j => BuildMonthlyStatsData(j as JObject)).ToList();
_dailyPNLRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1); _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"], Month = monthlyStatsDataJson["month"],
CumulativeProfitCurrency = dailyPNLDataJson["cumulativeProfitCurrency"], TotalSales = monthlyStatsDataJson["totalSales"],
Order = dailyPNLDataJson["order"], TotalProfitCurrency = monthlyStatsDataJson["totalProfitCurrency"],
AvgGrowth = monthlyStatsDataJson["avgGrowth"],
}; };
} }
public List<SellLogData> SellLog public List<SellLogData> SellLog
@ -459,33 +504,33 @@ namespace Core.Main.DataObjects
public double GetCurrentBalance() public double GetCurrentBalance()
{ {
return return
(this.Summary.Balance); (this.Misc.Balance);
} }
public double GetPairsBalance() public double GetPairsBalance()
{ {
return return
(this.Summary.PairsValue); (this.Misc.PairsValue);
} }
public double GetDCABalance() public double GetDCABalance()
{ {
return return
(this.Summary.DCAValue); (this.Misc.DCAValue);
} }
public double GetPendingBalance() public double GetPendingBalance()
{ {
return return
(this.Summary.PendingValue); (this.Misc.PendingValue);
} }
public double GetDustBalance() public double GetDustBalance()
{ {
return return
(this.Summary.DustValue); (this.Misc.DustValue);
} }
public double GetSnapshotBalance(DateTime snapshotDateTime) 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.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); result += this.TransactionData.Transactions.FindAll(t => t.UTCDateTime < snapshotDateTime).Sum(t => t.Amount);

View File

@ -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 // Get current PT properties
private void LoadCurrentProfitTrailerProperties() private void LoadCurrentProfitTrailerProperties()
{ {

View File

@ -26,7 +26,7 @@
} }
} }
<th class="m-t-0 header-title text-left">Total Current Value: &nbsp; <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="m-t-0 header-title text-left">Total Current Value: &nbsp; <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: &nbsp; <text class="text-autocolor"> @Model.SummaryData.StartBalance &nbsp; @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: &nbsp; <text class="text-autocolor"> @Model.MiscData.StartBalance &nbsp; @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> </tr>
</thead> </thead>
</table> </table>
@ -50,7 +50,6 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="card-box"> <div class="card-box">
<h4 class="m-t-0 header-title">No Sales!</h4> <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> <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>
</div> </div>
@ -59,47 +58,49 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="card-box"> <div class="card-box">
<h4 class="m-t-0 header-title">Sales Analysis</h4>
@{ @{
double totalProfit = 0; int totalDays = Model.PTData.GetTotalDays();
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit); double totalSales = Model.PTData.Stats.TotalSales;
double totalProfitFiat = Math.Round(totalProfit * Model.Summary.MainMarketPrice, 2); double totalProfit = Model.PTData.Stats.TotalProfit;
double percentGain = Math.Round(totalProfit / Model.SummaryData.StartBalance * 100, 2); double totalFundingFees = Model.PTData.Stats.FundingTotal;
double avgDailyGain = Model.DailyGains.Values.Average(dg => dg); double totalPercentGain = Model.PTData.Stats.TotalProfitPerc;
double avgMonthlyGain = Model.MonthlyGains.Values.Average(dg => dg); double totalProfitFiat = @Math.Round((totalProfit + totalFundingFees) * Model.PTData.Misc.FiatConversionRate, 0);
string percentGainText = percentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%"; double avgDailySales = @Math.Round(totalSales/totalDays, 1);
if (Model.PTData.TransactionData.Transactions.Count > 0) { double avgDailyGain = totalPercentGain / totalDays;
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>";
}
}
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"> <table class="table table-striped table-sm">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<th class="text-right">Total</th> <th class="text-right">Total</th>
<th class="text-right">AVG/Day</th> <th class="text-right">AVG/Day (@totalDays Days)</th>
<th class="text-right">AVG/Month</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> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<th>Sales</th> <th>Sales</th>
<td class="text-right">@Model.PTData.SellLog.Count</td> <td class="text-right">@totalSales</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">@avgDailySales</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">@avgMonthlySales</td>
</tr> </tr>
<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">@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 / totalDays, 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">@avgMonthlyProfit.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>
</tr> </tr>
<tr> <tr>
<th>% Gain</th> <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">@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> <td class="text-right text-autocolor">@avgMonthlyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
</tr> </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> </tbody>
</table> </table>
</div> </div>
@ -127,7 +143,7 @@
<tr> <tr>
<th class="text-right"></th> <th class="text-right"></th>
<th class="text-right">Est. Balance</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> <th class="text-right">Est. Gain</th>
</tr> </tr>
</thead> </thead>
@ -135,25 +151,25 @@
<tr> <tr>
<th>1 month</th> <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">@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> <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>
<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">@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> <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>
<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">@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> <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>
<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">@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> <td class="text-right text-autocolor">@Math.Round((estimatedBalance1Year - currentTotalBalance) / currentTotalBalance * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
</tr> </tr>
</tbody> </tbody>

View File

@ -1,9 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Core.Main; using Core.Main;
using Core.Helper; using System.Globalization;
using Core.Main.DataObjects; using Core.Main.DataObjects;
using Core.Main.DataObjects.PTMagicData; using Core.Main.DataObjects.PTMagicData;
@ -12,7 +11,12 @@ namespace Monitor.Pages
public class SalesAnalyzer : _Internal.BasePageModelSecure public class SalesAnalyzer : _Internal.BasePageModelSecure
{ {
public ProfitTrailerData PTData = null; 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 TradesChartDataJSON = "";
public string ProfitChartDataJSON = ""; public string ProfitChartDataJSON = "";
public string BalanceChartDataJSON = ""; public string BalanceChartDataJSON = "";
@ -22,17 +26,26 @@ namespace Monitor.Pages
public Dictionary<DateTime, double> MonthlyGains = new Dictionary<DateTime, double>(); public Dictionary<DateTime, double> MonthlyGains = new Dictionary<DateTime, double>();
public DateTimeOffset DateTimeNow = Constants.confMinDate; public DateTimeOffset DateTimeNow = Constants.confMinDate;
public double totalCurrentValue = 0; public double totalCurrentValue = 0;
public void OnGet() public void OnGet()
{ {
base.Init(); base.Init();
BindData(); BindData();
BuildTCV();
} }
private void BindData() private void BindData()
{ {
PTData = this.PtDataObject; 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 // Convert local offset time to UTC
TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", "")); TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
@ -40,6 +53,49 @@ namespace Monitor.Pages
BuildTopMarkets(); BuildTopMarkets();
BuildSalesChartData(); 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() private void BuildTopMarkets()
{ {

View File

@ -13,7 +13,7 @@ namespace Monitor.Pages
{ {
public string ValidationMessage = ""; public string ValidationMessage = "";
public ProfitTrailerData PTData = null; public ProfitTrailerData PTData = null;
public SummaryData SummaryData { get; set; } public MiscData MiscData { get; set; }
private string GetTimezoneOffsetString(TimeZoneInfo tzi) private string GetTimezoneOffsetString(TimeZoneInfo tzi)
{ {
@ -55,7 +55,7 @@ namespace Monitor.Pages
{ {
base.Init(); base.Init();
PTData = this.PtDataObject; PTData = this.PtDataObject;
SummaryData = this.PTData.Summary; MiscData = this.PTData.Misc;
string notification = GetStringParameter("n", ""); string notification = GetStringParameter("n", "");
if (notification.Equals("BackupRestored")) if (notification.Equals("BackupRestored"))

View File

@ -25,7 +25,7 @@
<div class="col-md-3 px-1"> <div class="col-md-3 px-1">
<div class="card-box px-3" style="height:320px;"> <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")); string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
if (Model.totalCurrentValue > 100) { if (Model.totalCurrentValue > 100) {
@ -35,8 +35,8 @@
<div id="AssetDistribution" class="container"> <div id="AssetDistribution" class="container">
<div class="text-center"> <div class="text-center">
<small> <small>
<span data-toggle="tooltip" data-placement="top" title="Starting balance from PTM settings">Start: &nbsp; <text class="text-autocolor"> @Model.SummaryData.StartBalance @Model.Summary.MainMarket </text></span> <span data-toggle="tooltip" data-placement="top" title="Starting balance from PTM settings">Start: &nbsp; <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"> &emsp; &emsp; Gain:&nbsp;<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="TCV gain on starting balance"> &emsp; &emsp; Gain:&nbsp;<text class="text-autocolor">@Math.Round(((Model.totalCurrentValue - Model.MiscData.StartBalance) / Model.MiscData.StartBalance) * 100, 2)%</text></span>
</small> </small>
</div> </div>
<div class="text-center"> <div class="text-center">
@ -166,12 +166,12 @@
var totalProfitPercent = overviewStats.TotalProfitPerc; var totalProfitPercent = overviewStats.TotalProfitPerc;
//var totalFundingGain = totalProfitPercent * ((totalProfit + totalFunding) / totalProfit); //var totalFundingGain = totalProfitPercent * ((totalProfit + totalFunding) / totalProfit);
double todaysProfitFiat = Math.Round((todaysProfit + todaysFunding) * Model.PTData.Summary.FiatConversionRate, 2); double todaysProfitFiat = Math.Round((todaysProfit + todaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
double yesterdaysProfitFiat = Math.Round((yesterdaysProfit + yesterdaysFunding) * Model.PTData.Summary.FiatConversionRate, 2); double yesterdaysProfitFiat = Math.Round((yesterdaysProfit + yesterdaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
double last7DaysProfitFiat = Math.Round((last7DaysProfit + last7DaysFunding) * Model.PTData.Summary.FiatConversionRate, 2); double last7DaysProfitFiat = Math.Round((last7DaysProfit + last7DaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
double thisMonthProfitFiat = Math.Round((thisMonthProfit + thisMonthFunding) * Model.PTData.Summary.FiatConversionRate, 2); double thisMonthProfitFiat = Math.Round((thisMonthProfit + thisMonthFunding) * Model.PTData.Misc.FiatConversionRate, 2);
double lastMonthProfitFiat = Math.Round((lastMonthProfit + lastMonthFunding) * Model.PTData.Summary.FiatConversionRate, 2); double lastMonthProfitFiat = Math.Round((lastMonthProfit + lastMonthFunding) * Model.PTData.Misc.FiatConversionRate, 2);
double totalProfitFiat = Math.Round((totalProfit + totalFunding) * Model.PTData.Summary.FiatConversionRate, 2); double totalProfitFiat = Math.Round((totalProfit + totalFunding) * Model.PTData.Misc.FiatConversionRate, 2);
bool futuresFunding = Model.PropertiesData.IsLeverageExchange; bool futuresFunding = Model.PropertiesData.IsLeverageExchange;
@ -181,7 +181,7 @@
<tr> <tr>
<th></th> <th></th>
<th class="text-right">Sales</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> <th class="text-right">Gain</th>
@if (futuresFunding) @if (futuresFunding)
{ {

View File

@ -17,8 +17,7 @@ namespace Monitor.Pages
public ProfitTrailerData PTData = null; public ProfitTrailerData PTData = null;
public StatsData StatsData { get; set; } public StatsData StatsData { get; set; }
public PropertiesData PropertiesData { 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 List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
public double DataHours { get; set; } public double DataHours { get; set; }
public int ProfitDays { get; set; } public int ProfitDays { get; set; }
@ -42,8 +41,7 @@ namespace Monitor.Pages
PTData = this.PtDataObject; PTData = this.PtDataObject;
StatsData = this.PTData.Stats; StatsData = this.PTData.Stats;
PropertiesData = this.PTData.Properties; PropertiesData = this.PTData.Properties;
SummaryData = this.PTData.Summary; MiscData = this.PTData.Misc;
List<DailyPNLData> dailyPNLData = this.PTData.DailyPNL; List<DailyPNLData> dailyPNLData = this.PTData.DailyPNL;
// Cleanup temp files // Cleanup temp files
@ -215,7 +213,7 @@ namespace Monitor.Pages
// Convert the list to a JSON string using Newtonsoft.Json // Convert the list to a JSON string using Newtonsoft.Json
ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { ProfitChartDataJSON = Newtonsoft.Json.JsonConvert.SerializeObject(new[] {
new { new {
key = "Profit in " + PTData.Properties.Currency, key = "Profit in " + PTData.Misc.Market,
color = Constants.ChartLineColors[1], color = Constants.ChartLineColors[1],
values = profitPerDayList values = profitPerDayList
} }