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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Core.Main.DataObjects.PTMagicData
|
namespace Core.Main.DataObjects.PTMagicData
|
||||||
{
|
{
|
||||||
#region Settings Objects
|
|
||||||
public class GeneralSettingsWrapper
|
public class GeneralSettingsWrapper
|
||||||
{
|
{
|
||||||
public GeneralSettings GeneralSettings { get; set; }
|
public GeneralSettings GeneralSettings { get; set; }
|
||||||
|
@ -21,7 +19,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public SecureSettings SecureSettings { get; set; }
|
public SecureSettings SecureSettings { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#region GeneralSettings
|
|
||||||
public class GeneralSettings
|
public class GeneralSettings
|
||||||
{
|
{
|
||||||
public Application Application { get; set; }
|
public Application Application { get; set; }
|
||||||
|
@ -43,12 +41,10 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public string ProfitTrailerDefaultSettingName { get; set; } = "default";
|
public string ProfitTrailerDefaultSettingName { get; set; } = "default";
|
||||||
public int FloodProtectionMinutes { get; set; } = 15;
|
public int FloodProtectionMinutes { get; set; } = 15;
|
||||||
public string Exchange { get; set; }
|
public string Exchange { get; set; }
|
||||||
public double StartBalance { get; set; } = 0;
|
|
||||||
public string InstanceName { get; set; } = "PT Magic";
|
public string InstanceName { get; set; } = "PT Magic";
|
||||||
public string TimezoneOffset { get; set; } = "+0:00";
|
public string TimezoneOffset { get; set; } = "+0:00";
|
||||||
public string MainFiatCurrency { get; set; } = "USD";
|
|
||||||
public string CoinMarketCapAPIKey { get; set; }
|
public string CoinMarketCapAPIKey { get; set; }
|
||||||
public string FreeCurrencyConverterAPIKey { get; set; }
|
//public string FreeCurrencyConverterAPIKey { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Monitor
|
public class Monitor
|
||||||
|
@ -61,9 +57,11 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public string AnalyzerChart { get; set; } = "";
|
public string AnalyzerChart { get; set; } = "";
|
||||||
public int GraphIntervalMinutes { get; set; } = 60;
|
public int GraphIntervalMinutes { get; set; } = 60;
|
||||||
public int GraphMaxTimeframeHours { get; set; } = 24;
|
public int GraphMaxTimeframeHours { get; set; } = 24;
|
||||||
|
public int ProfitsMaxTimeframeDays { get; set; } = 60;
|
||||||
public int RefreshSeconds { get; set; } = 30;
|
public int RefreshSeconds { get; set; } = 30;
|
||||||
public int BagAnalyzerRefreshSeconds { get; set; } = 5;
|
public int BagAnalyzerRefreshSeconds { get; set; } = 5;
|
||||||
public int BuyAnalyzerRefreshSeconds { get; set; } = 5;
|
public int BuyAnalyzerRefreshSeconds { get; set; } = 5;
|
||||||
|
//public int MaxSalesRecords { get; set; } = 99999;
|
||||||
public int MaxTopMarkets { get; set; } = 20;
|
public int MaxTopMarkets { get; set; } = 20;
|
||||||
public int MaxDailySummaries { get; set; } = 10;
|
public int MaxDailySummaries { get; set; } = 10;
|
||||||
public int MaxMonthlySummaries { get; set; } = 10;
|
public int MaxMonthlySummaries { get; set; } = 10;
|
||||||
|
@ -105,9 +103,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public Int64 ChatId { get; set; }
|
public Int64 ChatId { get; set; }
|
||||||
public bool SilentMode { get; set; } = false;
|
public bool SilentMode { get; set; } = false;
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region AnalyzerSettings
|
|
||||||
public class AnalyzerSettings
|
public class AnalyzerSettings
|
||||||
{
|
{
|
||||||
public MarketAnalyzer MarketAnalyzer { get; set; }
|
public MarketAnalyzer MarketAnalyzer { get; set; }
|
||||||
|
@ -130,6 +126,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
|
|
||||||
[DefaultValue("Market")]
|
[DefaultValue("Market")]
|
||||||
public string TrendCurrency { get; set; } = "Market";
|
public string TrendCurrency { get; set; } = "Market";
|
||||||
|
public string SplitCamelCaseName { get; set; }
|
||||||
|
|
||||||
[DefaultValue(0)]
|
[DefaultValue(0)]
|
||||||
public int MaxMarkets { get; set; } = 0;
|
public int MaxMarkets { get; set; } = 0;
|
||||||
|
@ -243,18 +240,12 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
[DefaultValue(0)]
|
[DefaultValue(0)]
|
||||||
public int HoursSinceTriggered { get; set; } = 0;
|
public int HoursSinceTriggered { get; set; } = 0;
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region SecureSettings
|
|
||||||
public class SecureSettings
|
public class SecureSettings
|
||||||
{
|
{
|
||||||
public string MonitorPassword { get; set; } = "";
|
public string MonitorPassword { get; set; } = "";
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Market Analyzer Objects
|
|
||||||
public class Market
|
public class Market
|
||||||
{
|
{
|
||||||
public int Position;
|
public int Position;
|
||||||
|
@ -290,9 +281,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public DateTime FirstSeen = Constants.confMinDate;
|
public DateTime FirstSeen = Constants.confMinDate;
|
||||||
public DateTime LastSeen = Constants.confMaxDate;
|
public DateTime LastSeen = Constants.confMaxDate;
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Summary Objects
|
|
||||||
public class Summary
|
public class Summary
|
||||||
{
|
{
|
||||||
public string Version { get; set; } = "";
|
public string Version { get; set; } = "";
|
||||||
|
@ -323,14 +312,26 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public string SellStrategy { get; set; } = "";
|
public string SellStrategy { get; set; } = "";
|
||||||
public string MainMarket { get; set; } = "";
|
public string MainMarket { get; set; } = "";
|
||||||
public double MainMarketPrice { get; set; } = 0;
|
public double MainMarketPrice { get; set; } = 0;
|
||||||
public string MainFiatCurrency { get; set; } = "USD";
|
private PropertiesData _propertiesData = new PropertiesData();
|
||||||
public double MainFiatCurrencyExchangeRate { get; set; } = 1;
|
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> 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>();
|
||||||
public List<StrategySummary> DCASellStrategies { 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 class StrategySummary
|
||||||
{
|
{
|
||||||
public string Name { get; set; } = "";
|
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> DCABuyStrategies { get; set; } = new List<StrategySummary>();
|
||||||
public List<StrategySummary> DCASellStrategies { 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 class Transaction
|
||||||
{
|
{
|
||||||
public string GUID { get; set; } = "";
|
public string GUID { get; set; } = "";
|
||||||
|
@ -396,9 +382,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
return result.DateTime;
|
return result.DateTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region SingleMarketSettingSummary Objects
|
|
||||||
public class SingleMarketSettingSummary
|
public class SingleMarketSettingSummary
|
||||||
{
|
{
|
||||||
public string Market { get; set; } = "";
|
public string Market { get; set; } = "";
|
||||||
|
@ -414,24 +398,93 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public double LastPrice { get; set; } = 0;
|
public double LastPrice { get; set; } = 0;
|
||||||
public double Last24hVolume { 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 StatsData
|
||||||
|
|
||||||
public class SellLogData
|
|
||||||
{
|
{
|
||||||
public double SoldAmount { get; set; }
|
public double SalesToday { get; set; }
|
||||||
public DateTime SoldDate { get; set; }
|
public double ProfitToday { get; set; }
|
||||||
public int BoughtTimes { get; set; }
|
public double ProfitPercToday { get; set; }
|
||||||
public string Market { get; set; }
|
public double SalesYesterday { get; set; }
|
||||||
public double ProfitPercent { get; set; }
|
public double ProfitYesterday { get; set; }
|
||||||
public double Profit { get; set; }
|
public double ProfitPercYesterday { get; set; }
|
||||||
public double AverageBuyPrice { get; set; }
|
public double SalesWeek { get; set; }
|
||||||
public double TotalCost { get; set; }
|
public double ProfitWeek { get; set; }
|
||||||
public double SoldPrice { get; set; }
|
public double ProfitPercWeek { get; set; }
|
||||||
public double SoldValue { 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 class PTStrategy
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
|
@ -507,16 +560,17 @@ 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 PairsValue { get; set; }
|
public double PairsValue { get; set; }
|
||||||
public double DCAValue { get; set; }
|
public double DCAValue { get; set; }
|
||||||
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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -14,12 +14,11 @@ namespace Core.Main
|
||||||
{
|
{
|
||||||
public class PTMagic
|
public class PTMagic
|
||||||
{
|
{
|
||||||
|
|
||||||
public PTMagic(LogHelper log)
|
public PTMagic(LogHelper log)
|
||||||
{
|
{
|
||||||
this.Log = log;
|
this.Log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
private LogHelper _log;
|
private LogHelper _log;
|
||||||
private PTMagicConfiguration _systemConfiguration;
|
private PTMagicConfiguration _systemConfiguration;
|
||||||
|
@ -84,7 +83,10 @@ namespace Core.Main
|
||||||
_systemConfiguration = value;
|
_systemConfiguration = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public class IsAnalzyerRunning
|
||||||
|
{
|
||||||
|
private string _isAnalyzerRunning;
|
||||||
|
}
|
||||||
public System.Timers.Timer Timer
|
public System.Timers.Timer Timer
|
||||||
{
|
{
|
||||||
get
|
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");
|
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)
|
catch (System.NullReferenceException)
|
||||||
{
|
{
|
||||||
|
@ -871,9 +864,6 @@ namespace Core.Main
|
||||||
// Check for latest GitHub version
|
// Check for latest GitHub version
|
||||||
this.CheckLatestGitHubVersion(this.LastRuntimeSummary.Version);
|
this.CheckLatestGitHubVersion(this.LastRuntimeSummary.Version);
|
||||||
|
|
||||||
// Get latest main fiat currency exchange rate
|
|
||||||
this.GetMainFiatCurrencyDetails();
|
|
||||||
|
|
||||||
// Load current PT files
|
// Load current PT files
|
||||||
this.LoadCurrentProfitTrailerProperties();
|
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
|
// Get current PT properties
|
||||||
private void LoadCurrentProfitTrailerProperties()
|
private void LoadCurrentProfitTrailerProperties()
|
||||||
{
|
{
|
||||||
|
|
|
@ -437,7 +437,7 @@ namespace Core.ProfitTrailer
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strategyText += "<span class=\"label label-warning\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">FORM</span> ";
|
strategyText += "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -64,13 +64,16 @@
|
||||||
|
|
||||||
var loadDashboardBottom = function () {
|
var loadDashboardBottom = function () {
|
||||||
//destroy all d3 svg graph to avoid memory leak
|
//destroy all d3 svg graph to avoid memory leak
|
||||||
$(".nvtooltip").remove();
|
setTimeout(function()
|
||||||
$("svg > *").remove();
|
{
|
||||||
$("svg").remove();
|
$(".nvtooltip").remove();
|
||||||
nv.charts = {};
|
$("svg > *").remove();
|
||||||
nv.graphs = [];
|
$("svg").remove();
|
||||||
nv.logs = {};
|
nv.charts = {};
|
||||||
nv.tooltip = {};
|
nv.graphs = [];
|
||||||
|
nv.logs = {};
|
||||||
|
nv.tooltip = {};
|
||||||
|
}, 10 * intervalDashboardBottom * 1000); // 10 times intervalDashboardBottom in milliseconds
|
||||||
|
|
||||||
// Clear exisitng interval to stop multiple attempts to load at the same time.
|
// Clear exisitng interval to stop multiple attempts to load at the same time.
|
||||||
if (intervalDashboardBottom != null)
|
if (intervalDashboardBottom != null)
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p><input type="checkbox" name="cbRememberMe"/> <label for="cbRememberMe">Stay logged in</label></p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</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'"));
|
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.GeneralSettings.Monitor.IsPasswordProtected = true;
|
||||||
PTMagicConfiguration.WriteGeneralSettings();
|
//PTMagicConfiguration.WriteGeneralSettings();
|
||||||
if (cbRememberMe != null)
|
if (cbRememberMe != null)
|
||||||
{
|
{
|
||||||
if (cbRememberMe.Equals("on", StringComparison.InvariantCultureIgnoreCase))
|
if (cbRememberMe.Equals("on", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
|
|
@ -155,14 +155,14 @@ else
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="card-box">
|
<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">
|
<table class="table table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th class="text-right">Markets</th>
|
<th class="text-right">Markets</th>
|
||||||
<th class="text-right">Timeframe</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>
|
<th class="text-right">Change</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -190,9 +190,9 @@ else
|
||||||
}
|
}
|
||||||
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>
|
</tr>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using Core.Main;
|
using Core.Main;
|
||||||
using Core.Helper;
|
using Core.Helper;
|
||||||
using Core.Main.DataObjects.PTMagicData;
|
using Core.Main.DataObjects.PTMagicData;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Monitor.Pages
|
namespace Monitor.Pages
|
||||||
{
|
{
|
||||||
|
@ -11,6 +12,7 @@ namespace Monitor.Pages
|
||||||
{
|
{
|
||||||
public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
|
public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
|
||||||
public string TrendChartDataJSON = "";
|
public string TrendChartDataJSON = "";
|
||||||
|
public double DataHours { get; set; }
|
||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
|
@ -28,77 +30,85 @@ namespace Monitor.Pages
|
||||||
|
|
||||||
private void BuildMarketTrendChartData()
|
private void BuildMarketTrendChartData()
|
||||||
{
|
{
|
||||||
if (MarketTrends.Count > 0)
|
List<string> trendChartData = new List<string>();
|
||||||
{
|
if (MarketTrends.Count > 0)
|
||||||
TrendChartDataJSON = "[";
|
|
||||||
int mtIndex = 0;
|
|
||||||
foreach (MarketTrend mt in MarketTrends)
|
|
||||||
{
|
{
|
||||||
if (mt.DisplayGraph)
|
|
||||||
{
|
int mtIndex = 0;
|
||||||
string lineColor = "";
|
foreach (MarketTrend mt in MarketTrends)
|
||||||
if (mtIndex < Constants.ChartLineColors.Length)
|
|
||||||
{
|
{
|
||||||
lineColor = Constants.ChartLineColors[mtIndex];
|
if (mt.DisplayGraph)
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
List<MarketTrendChange> tickRange = marketTrendChangeSummaries.FindAll(m => m.TrendDateTime >= tickTime).OrderBy(m => m.TrendDateTime).ToList();
|
string lineColor = mtIndex < Constants.ChartLineColors.Length
|
||||||
if (tickRange.Count > 0)
|
? Constants.ChartLineColors[mtIndex]
|
||||||
{
|
: Constants.ChartLineColors[mtIndex - 20];
|
||||||
MarketTrendChange mtc = tickRange.First();
|
|
||||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
|
||||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
|
||||||
|
|
||||||
TrendChartDataJSON += "{ x: new Date('" + tickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||||
trendChartTicks++;
|
{
|
||||||
}
|
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
|
@page
|
||||||
@model SalesAnalyzer
|
@model SalesAnalyzer
|
||||||
|
@using System.Globalization
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "";
|
ViewData["Title"] = "";
|
||||||
}
|
}
|
||||||
|
@ -19,14 +20,11 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@{
|
@{
|
||||||
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
double totalCurrentValue = double.Parse(Model.PTData.Misc.TotalCurrentValue);
|
||||||
if (Model.totalCurrentValue > 100)
|
string totalCurrentValueString = Model.PTData.Misc.TotalCurrentValue;
|
||||||
{
|
|
||||||
totalCurrentValueString = Math.Round(Model.totalCurrentValue, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
<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="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.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="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>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
|
@ -34,78 +32,129 @@
|
||||||
</div>
|
</div>
|
||||||
</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="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-6">
|
||||||
<div class="card-box">
|
<div class="card-box px-2" style="height:320px;">
|
||||||
<h4 class="m-t-0 header-title">No Sales!</h4>
|
<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>
|
</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="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.DailyPNL.Count;
|
||||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
double startBalance = Model.MiscData.StartBalance;
|
||||||
double totalProfitFiat = Math.Round(totalProfit * Model.Summary.MainMarketPrice, 2);
|
double totalSales = Model.PTData.Stats.TotalSales;
|
||||||
double percentGain = Math.Round(totalProfit / Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance * 100, 2);
|
double totalProfit = Model.PTData.Stats.TotalProfit;
|
||||||
double avgDailyGain = Model.DailyGains.Values.Average(dg => dg);
|
double totalFundingFees = Model.PTData.Stats.FundingTotal;
|
||||||
double avgMonthlyGain = Model.MonthlyGains.Values.Average(dg => dg);
|
double totalPercentGain = ((totalProfit + totalFundingFees) / startBalance) * 100;
|
||||||
string percentGainText = percentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
double totalProfitFiat = @Math.Round((totalProfit + totalFundingFees) * Model.PTData.Misc.FiatConversionRate, 0);
|
||||||
if (Model.PTData.TransactionData.Transactions.Count > 0) {
|
double avgDailySales = @Math.Round(totalSales/totalDays, 1);
|
||||||
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 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">
|
<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</span></th>
|
||||||
<th class="text-right">AVG/Month</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>
|
</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>@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>
|
||||||
|
@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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Profit USD</th>
|
<th>Gain</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">@totalPercentGain.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">@avgDailyGain.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">@avgMonthlyGain.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>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -115,46 +164,52 @@
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
@{
|
@{
|
||||||
double currentTotalBalance = Model.totalCurrentValue;
|
double estimatedBalance1Week = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 7.0), 8);
|
||||||
double estimatedBalance1Month = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 30.0), 8);
|
double estimatedBalance1Month = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 30.0), 8);
|
||||||
double estimatedBalance3Months = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 90.0), 8);
|
double estimatedBalance3Months = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 90.0), 8);
|
||||||
double estimatedBalance6Months = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 180.0), 8);
|
double estimatedBalance6Months = Math.Round(totalCurrentValue * Math.Pow((1 + (avgDailyGain / 100)), 180.0), 8);
|
||||||
double estimatedBalance1Year = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 365.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">
|
<table class="table table-striped table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-right"></th>
|
<th class="text-right"></th>
|
||||||
<th class="text-right">Est. Balance</th>
|
<th class="text-right">@Model.PTData.Misc.Market</th>
|
||||||
<th class="text-right">Est. @Model.Summary.MainFiatCurrency Value</th>
|
<th class="text-right">@Model.PTData.Properties.Currency</th>
|
||||||
<th class="text-right">Est. Gain</th>
|
<th class="text-right">Gain</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<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">@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 - totalCurrentValue) / totalCurrentValue * 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 - totalCurrentValue) / totalCurrentValue * 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 - totalCurrentValue) / totalCurrentValue * 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 - totalCurrentValue) / totalCurrentValue * 100, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) %</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -162,53 +217,47 @@
|
||||||
</div>
|
</div>
|
||||||
</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="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">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">
|
<table class="table table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Day</th>
|
<th>Day</th>
|
||||||
|
<th class="text-right">Buys</th>
|
||||||
<th class="text-right">Sales</th>
|
<th class="text-right">Sales</th>
|
||||||
<th class="text-right">Profit @Model.Summary.MainMarket</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.Properties.Currency</th>
|
||||||
<th class="text-right">% Gain</th>
|
<th class="text-right">Gain</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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);
|
for (int i = 0; i < maxDays; i++)
|
||||||
double salesDateProfit = 0;
|
{
|
||||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
DateTime salesDate = DateTime.ParseExact(Model.PTData.DailyStats[i].Date, "d-M-yyyy", CultureInfo.InvariantCulture);
|
||||||
double salesDateProfitFiat = Math.Round(salesDateProfit * Model.Summary.MainMarketPrice, 2);
|
var buys = Model.PTData.DailyStats[i].TotalBuys;
|
||||||
double salesDateStartBalance = Model.PTData.GetSnapshotBalance(salesDate);
|
var sales = Model.PTData.DailyStats[i].TotalSales;
|
||||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
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>
|
<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>@salesDate.ToString("yyyy-MM-dd")</td>
|
||||||
<td class="text-right">@salesDateSales.Count</td>
|
<td class="text-right text-autocolor"">@buys</td>
|
||||||
<td class="text-right text-autocolor">@salesDateProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
<td class="text-right text-autocolor"">@sales</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">@profit.ToString("#,#0.00000000", 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">@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>
|
</tr>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -217,110 +266,83 @@
|
||||||
|
|
||||||
<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">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">
|
<table class="table table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Month</th>
|
<th>Month</th>
|
||||||
<th class="text-right">Sales</th>
|
<th class="text-right">Sales</th>
|
||||||
<th class="text-right">Profit @Model.Summary.MainMarket</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.Properties.Currency</th>
|
||||||
<th class="text-right">% Gain</th>
|
<th class="text-right">Growth</th>
|
||||||
<th class="text-right">AVG %/Day</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@{
|
@{
|
||||||
DateTime minSellLogMonthDate = new DateTime(Model.MinSellLogDate.Year, Model.MinSellLogDate.Month, 1).Date;
|
for (int i = 0; i < maxMonths; i++)
|
||||||
DateTime salesMonthStartDate = new DateTime(Model.DateTimeNow.DateTime.Year, Model.DateTimeNow.DateTime.Month, 1).Date;
|
{
|
||||||
}
|
DateTime monthDate = DateTime.ParseExact(Model.PTData.MonthlyStats[i].Month, "M-yyyy", CultureInfo.InvariantCulture);
|
||||||
@for (DateTime salesMonthDate = salesMonthStartDate.Date; salesMonthDate >= Model.DateTimeNow.DateTime.AddMonths(-Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries) && salesMonthDate >= minSellLogMonthDate; salesMonthDate = salesMonthDate.AddMonths(-1)) {
|
string monthName = monthDate.ToString("MMMM", CultureInfo.InvariantCulture);
|
||||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> salesMonthSales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date.Month == salesMonthDate.Month && sl.SoldDate.Date.Year == salesMonthDate.Year);
|
var sales = Model.PTData.MonthlyStats[i].TotalSales;
|
||||||
double salesDateProfit = 0;
|
var profit = Model.PTData.MonthlyStats[i].TotalProfitCurrency;
|
||||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
var profitFiat = Math.Round(profit * Model.PTData.Misc.FiatConversionRate, 0);
|
||||||
double salesDateProfitFiat = Math.Round(salesDateProfit * Model.Summary.MainMarketPrice, 2);
|
var growth = Math.Round(Model.PTData.MonthlyStats[i].AvgGrowth,2);
|
||||||
double salesDateStartBalance = Model.PTData.GetSnapshotBalance(salesMonthDate);
|
<tr>
|
||||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
<td>@monthName</td>
|
||||||
double salesDateAVGDailyGain = 0;
|
<td class="text-right text-autocolor">@sales</td>
|
||||||
double monthDailyProfit = 0;
|
<td class="text-right text-autocolor">@profit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||||
int days = 0;
|
<td class="text-right text-autocolor">@profitFiat</td>
|
||||||
for (int d = 1; d <= DateTime.DaysInMonth(salesMonthDate.Year, salesMonthDate.Month); d++) {
|
<td class="text-right text-autocolor">@growth %</td>
|
||||||
DateTime monthDay = salesMonthDate.AddDays(-salesMonthDate.Day + d);
|
</tr>
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
@* <div class="col-md-6"> *@
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="card-box">
|
<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>
|
<table class="tablesaw table m-b-0" data-tablesaw-sortable data-tablesaw-sortable-switch>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" data-tablesaw-priority="persist" data-tablesaw-sortable-col data-tablesaw-sortable-default-col>Rank</th>
|
<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" 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>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>Avg/Trade</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>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@{
|
@{
|
||||||
var topMarkets = Model.PTData.SellLog.GroupBy(m => m.Market).Select(mg => mg.Sum(m => m.Profit));
|
int rank = 1;
|
||||||
int marketRank = 0;
|
foreach (var pair in Model.ProfitablePairs)
|
||||||
}
|
{
|
||||||
@foreach (KeyValuePair<string, double> marketData in Model.TopMarkets) {
|
string coin = pair.Coin;
|
||||||
marketRank++;
|
double profit = Math.Round(pair.ProfitCurrency,8);
|
||||||
int trades = Model.PTData.SellLog.FindAll(m => m.Market == marketData.Key).Count;
|
int sales = pair.SoldTimes;
|
||||||
double profitFiat = Math.Round(marketData.Value * Model.Summary.MainMarketPrice, 2);
|
double avg = Math.Round(pair.Avg,8);
|
||||||
double profitFiatPerTrade = Math.Round(profitFiat / trades, 2);
|
double profitFiat = Math.Round(profit * Model.MiscData.FiatConversionRate, 0);
|
||||||
<tr>
|
<tr>
|
||||||
<td>@marketRank</td>
|
<td>@rank</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><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">@trades</td>
|
<td class="text-right text-autocolor-saw">@profit</td>
|
||||||
<td class="text-right text-autocolor-saw">@marketData.Value.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
<td class="text-right">@sales</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">@avg </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>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
rank++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@* </div> *@
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="salesList" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true" style="display: none;">
|
</div>
|
||||||
<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 -->
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Scripts {
|
@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.print.min.js"></script>
|
||||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/datatables/buttons.colVis.min.js"></script>
|
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/datatables/buttons.colVis.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function ($) {
|
(function ($) {
|
||||||
'use strict';
|
'use strict';
|
||||||
nv.addGraph(function () {
|
$('[role="tooltip"]').remove();
|
||||||
var lineChart = nv.models.lineChart();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
var height = 300;
|
$('.text-autocolor').autocolor(false);
|
||||||
/**/
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
nv.addGraph(function () {
|
var salesChart; // Keep a reference to the chart
|
||||||
var lineChart = nv.models.lineChart();
|
var salesData; // Keep a reference to the data
|
||||||
var height = 300;
|
|
||||||
/**/
|
|
||||||
var chartData = @Html.Raw(Model.ProfitChartDataJSON);
|
|
||||||
/**/
|
|
||||||
lineChart.useInteractiveGuideline(true);
|
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
|
||||||
lineChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
|
|
||||||
d3.select('.profit-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
|
||||||
nv.utils.windowResize(lineChart.update);
|
|
||||||
return lineChart;
|
|
||||||
});
|
|
||||||
|
|
||||||
nv.addGraph(function () {
|
@if (!Model.SalesChartDataJSON.Equals("")) {
|
||||||
var lineChart = nv.models.lineChart();
|
<text>
|
||||||
var height = 400;
|
nv.addGraph(function () {
|
||||||
/**/
|
salesChart = nv.models.multiBarChart();
|
||||||
var chartData = @Html.Raw(Model.BalanceChartDataJSON);
|
var height = 300;
|
||||||
/**/
|
salesChart.groupSpacing(0.5);
|
||||||
lineChart.useInteractiveGuideline(true);
|
salesChart.showControls(false);
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
//salesChart.useInteractiveGuideline(true);
|
||||||
lineChart.yAxis.axisLabel('Profit').tickFormat(d3.format(',.2f'));
|
salesChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||||
d3.select('.balance-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
salesChart.yAxis.axisLabel('').tickFormat(d3.format(',.2f'));
|
||||||
nv.utils.windowResize(lineChart.update);
|
|
||||||
return lineChart;
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#salesList").on("show.bs.modal", function (e) {
|
salesData = @Html.Raw(Model.SalesChartDataJSON);
|
||||||
$(this).find(".modal-content").html('<i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>');
|
|
||||||
var link = $(e.relatedTarget);
|
d3.select('.sales-chart svg')
|
||||||
$(this).find(".modal-content").load(link.attr("href"), function () {
|
.datum(salesData)
|
||||||
$('.text-autocolor').autocolor(false);
|
.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);
|
})(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>
|
||||||
|
|
||||||
|
<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;
|
||||||
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;
|
||||||
|
|
||||||
|
|
||||||
namespace Monitor.Pages
|
namespace Monitor.Pages
|
||||||
{
|
{
|
||||||
public class SalesAnalyzer : _Internal.BasePageModelSecure
|
public class SalesAnalyzer : _Internal.BasePageModelSecure
|
||||||
{
|
{
|
||||||
public ProfitTrailerData PTData = null;
|
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 TradesChartDataJSON = "";
|
||||||
|
public string CumulativeProfitChartDataJSON = "";
|
||||||
|
public string TCVChartDataJSON = "";
|
||||||
public string ProfitChartDataJSON = "";
|
public string ProfitChartDataJSON = "";
|
||||||
public string BalanceChartDataJSON = "";
|
public string SalesChartDataJSON = "";
|
||||||
public IEnumerable<KeyValuePair<string, double>> TopMarkets = null;
|
public IEnumerable<KeyValuePair<string, double>> TopMarkets = null;
|
||||||
public DateTime MinSellLogDate = Constants.confMinDate;
|
//public DateTime MinSellLogDate = Constants.confMinDate;
|
||||||
public Dictionary<DateTime, double> DailyGains = 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 void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
|
|
||||||
BindData();
|
BindData();
|
||||||
BuildTCV();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindData()
|
private void BindData()
|
||||||
{
|
{
|
||||||
PTData = this.PtDataObject;
|
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
|
// Convert local offset time to UTC
|
||||||
TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
|
TimeSpan offsetTimeSpan = TimeSpan.Parse(PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
|
||||||
DateTimeNow = DateTimeOffset.UtcNow.ToOffset(offsetTimeSpan);
|
DateTimeNow = DateTimeOffset.UtcNow.ToOffset(offsetTimeSpan);
|
||||||
|
|
||||||
BuildTopMarkets();
|
|
||||||
BuildSalesChartData();
|
BuildSalesChartData();
|
||||||
|
BuildProfitChartData();
|
||||||
|
BuildCumulativeProfitChartData();
|
||||||
|
BuildTCVChartData();
|
||||||
}
|
}
|
||||||
private void BuildTopMarkets()
|
|
||||||
|
private void BuildTCVChartData()
|
||||||
{
|
{
|
||||||
var markets = PTData.SellLog.GroupBy(m => m.Market);
|
List<object> TCVPerDayList = new List<object>();
|
||||||
Dictionary<string, double> topMarketsDic = new Dictionary<string, double>();
|
|
||||||
foreach (var market in markets)
|
if (PTData.DailyTCV.Count > 0)
|
||||||
{
|
{
|
||||||
double totalProfit = 0;
|
// Get timezone offset
|
||||||
totalProfit = PTData.SellLog.FindAll(m => m.Market == market.Key).Sum(m => m.Profit);
|
TimeSpan offset;
|
||||||
topMarketsDic.Add(market.Key, totalProfit);
|
bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-");
|
||||||
}
|
string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-');
|
||||||
TopMarkets = new SortedDictionary<string, double>(topMarketsDic).OrderByDescending(m => m.Value).Take(PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets);
|
|
||||||
|
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()
|
private void BuildSalesChartData()
|
||||||
{
|
{
|
||||||
if (PTData.SellLog.Count > 0)
|
List<object> salesPerDayList = new List<object>();
|
||||||
{
|
List<object> buysPerDayList = new List<object>(); // New list for daily buys
|
||||||
MinSellLogDate = PTData.SellLog.OrderBy(sl => sl.SoldDate).First().SoldDate.Date;
|
|
||||||
DateTime graphStartDate = DateTimeNow.DateTime.Date.AddDays(-1850);
|
|
||||||
if (MinSellLogDate > graphStartDate) graphStartDate = MinSellLogDate;
|
|
||||||
|
|
||||||
int tradeDayIndex = 0;
|
if (PTData.DailyStats.Count > 0)
|
||||||
string tradesPerDayJSON = "";
|
|
||||||
string profitPerDayJSON = "";
|
|
||||||
string balancePerDayJSON = "";
|
|
||||||
double balance = 0.0;
|
|
||||||
for (DateTime salesDate = graphStartDate; salesDate <= DateTimeNow.DateTime.Date; salesDate = salesDate.AddDays(1))
|
|
||||||
{
|
{
|
||||||
if (tradeDayIndex > 0)
|
// Get timezone offset
|
||||||
{
|
TimeSpan offset;
|
||||||
tradesPerDayJSON += ",\n";
|
bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-");
|
||||||
profitPerDayJSON += ",\n";
|
string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-');
|
||||||
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 += "]";
|
|
||||||
|
|
||||||
ProfitChartDataJSON = "[";
|
if (!TimeSpan.TryParse(offsetWithoutSign, out offset))
|
||||||
ProfitChartDataJSON += "{";
|
{
|
||||||
ProfitChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',";
|
offset = TimeSpan.Zero; // If offset is invalid, set it to zero
|
||||||
ProfitChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',";
|
}
|
||||||
ProfitChartDataJSON += "values: [" + profitPerDayJSON + "]";
|
|
||||||
ProfitChartDataJSON += "}";
|
|
||||||
ProfitChartDataJSON += "]";
|
|
||||||
|
|
||||||
BalanceChartDataJSON = "[";
|
DateTime endDate = DateTime.UtcNow.Add(isNegative ? -offset : offset).Date;
|
||||||
BalanceChartDataJSON += "{";
|
|
||||||
BalanceChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',";
|
// Parse dates once and adjust them to the local timezone
|
||||||
BalanceChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',";
|
Dictionary<DateTime, DailyStatsData> salesCountByDate = PTData.DailyStats
|
||||||
BalanceChartDataJSON += "values: [" + balancePerDayJSON + "]";
|
.ToDictionary(
|
||||||
BalanceChartDataJSON += "}";
|
data => DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture),
|
||||||
BalanceChartDataJSON += "]";
|
data => data
|
||||||
|
);
|
||||||
for (DateTime salesDate = DateTimeNow.DateTime.Date; salesDate >= MinSellLogDate; salesDate = salesDate.AddDays(-1))
|
|
||||||
{
|
DateTime earliestDataDate = salesCountByDate.Keys.Min();
|
||||||
List<SellLogData> salesDateSales = PTData.SellLog.FindAll(sl => sl.SoldDate.Date == salesDate);
|
DateTime startDate = earliestDataDate;
|
||||||
double salesDateProfit;
|
|
||||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
// Calculate the total days of data available
|
||||||
double salesDateStartBalance = PTData.GetSnapshotBalance(salesDate);
|
SalesDays = (endDate - startDate).Days;
|
||||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
int counter = 0;
|
||||||
DailyGains.Add(salesDate, salesDateGain);
|
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>
|
</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>
|
<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">
|
<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> *@
|
||||||
|
|
||||||
<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>
|
<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">
|
<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> *@
|
||||||
|
|
||||||
<div class="form-group row">
|
<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>
|
<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>
|
</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>
|
<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">
|
<div class="col-md-8">
|
||||||
<input type="text" class="form-control" name="Application_FreeCurrencyConverterAPIKey" value="@Model.PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey">
|
<input type="text" class="form-control" name="Application_FreeCurrencyConverterAPIKey" value="@Model.PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> *@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -196,21 +196,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<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">
|
<div class="col-md-8">
|
||||||
<input type="text" class="form-control" name="Monitor_GraphIntervalMinutes" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes.ToString(new System.Globalization.CultureInfo("en-US"))">
|
<input type="text" class="form-control" name="Monitor_GraphIntervalMinutes" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-md-4 col-form-label">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">
|
<div class="col-md-8">
|
||||||
<input type="text" class="form-control" name="Monitor_GraphMaxTimeframeHours" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours.ToString(new System.Globalization.CultureInfo("en-US"))">
|
<input type="text" class="form-control" name="Monitor_GraphMaxTimeframeHours" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-md-4 col-form-label">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">
|
<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"))">
|
<input type="text" class="form-control" name="Monitor_RefreshSeconds" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||||
</div>
|
</div>
|
||||||
|
@ -240,7 +247,14 @@
|
||||||
</div>
|
</div>
|
||||||
</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>
|
<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">
|
<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"))">
|
<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>
|
||||||
|
|
||||||
<div class="form-group row">
|
<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">
|
<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"))">
|
<input type="text" class="form-control" name="Monitor_MaxDashboardBuyEntries" value="@Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDashboardBuyEntries.ToString(new System.Globalization.CultureInfo("en-US"))">
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Core.Main;
|
using Core.Main;
|
||||||
using Core.Helper;
|
using Core.Helper;
|
||||||
|
using Core.Main.DataObjects;
|
||||||
using Core.Main.DataObjects.PTMagicData;
|
using Core.Main.DataObjects.PTMagicData;
|
||||||
|
|
||||||
|
|
||||||
namespace Monitor.Pages
|
namespace Monitor.Pages
|
||||||
{
|
{
|
||||||
public class SettingsGeneralModel : _Internal.BasePageModelSecure
|
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)
|
private string GetTimezoneOffsetString(TimeZoneInfo tzi)
|
||||||
{
|
{
|
||||||
|
@ -51,6 +54,8 @@ namespace Monitor.Pages
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
|
PTData = this.PtDataObject;
|
||||||
|
MiscData = this.PTData.Misc;
|
||||||
|
|
||||||
string notification = GetStringParameter("n", "");
|
string notification = GetStringParameter("n", "");
|
||||||
if (notification.Equals("BackupRestored"))
|
if (notification.Equals("BackupRestored"))
|
||||||
|
@ -68,27 +73,29 @@ namespace Monitor.Pages
|
||||||
// Read the new settings
|
// Read the new settings
|
||||||
PTMagicConfiguration.GeneralSettings.Application.IsEnabled = HttpContext.Request.Form["Application_IsEnabled"].Equals("on");
|
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.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.ProfitTrailerDefaultSettingName = HttpContext.Request.Form["Application_ProfitTrailerDefaultSettingName"];
|
||||||
PTMagicConfiguration.GeneralSettings.Application.Exchange = HttpContext.Request.Form["Application_Exchange"];
|
PTMagicConfiguration.GeneralSettings.Application.Exchange = HttpContext.Request.Form["Application_Exchange"];
|
||||||
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL = HttpContext.Request.Form["Application_ProfitTrailerMonitorURL"];
|
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL = HttpContext.Request.Form["Application_ProfitTrailerMonitorURL"];
|
||||||
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken = HttpContext.Request.Form["Application_ProfitTrailerServerAPIToken"];
|
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken = HttpContext.Request.Form["Application_ProfitTrailerServerAPIToken"];
|
||||||
PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset = HttpContext.Request.Form["Application_TimezoneOffset"];
|
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.FloodProtectionMinutes = SystemHelper.TextToInteger(HttpContext.Request.Form["Application_FloodProtectionMinutes"], PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes);
|
||||||
PTMagicConfiguration.GeneralSettings.Application.InstanceName = HttpContext.Request.Form["Application_InstanceName"];
|
PTMagicConfiguration.GeneralSettings.Application.InstanceName = HttpContext.Request.Form["Application_InstanceName"];
|
||||||
PTMagicConfiguration.GeneralSettings.Application.CoinMarketCapAPIKey = HttpContext.Request.Form["Application_CoinMarketCapAPIKey"];
|
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.IsPasswordProtected = HttpContext.Request.Form["Monitor_IsPasswordProtected"].Equals("on");
|
||||||
PTMagicConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart = HttpContext.Request.Form["Monitor_OpenBrowserOnStart"].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.AnalyzerChart = HttpContext.Request.Form["Monitor_AnalyzerChart"];
|
||||||
PTMagicConfiguration.GeneralSettings.Monitor.Port = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_Port"], PTMagicConfiguration.GeneralSettings.Monitor.Port);
|
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.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.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.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.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.BuyAnalyzerRefreshSeconds = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_BuyAnalyzerRefreshSeconds"], PTMagicConfiguration.GeneralSettings.Monitor.BuyAnalyzerRefreshSeconds);
|
||||||
PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform = HttpContext.Request.Form["Monitor_LinkPlatform"];
|
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.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.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);
|
PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries = SystemHelper.TextToInteger(HttpContext.Request.Form["Monitor_MaxMonthlySummaries"], PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries);
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-5">
|
|
||||||
|
<div class="col-md-6">
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
<h4 class="m-t-0 header-title">PTMagic Status <small id="last-refresh" class="pull-right"></small></h4>
|
<h4 class="m-t-0 header-title">PTMagic Status <small id="last-refresh" class="pull-right"></small></h4>
|
||||||
@{
|
@{
|
||||||
|
@ -67,11 +68,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-box">
|
<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";
|
string maxCostCaption = "Initial";
|
||||||
}
|
}
|
||||||
|
|
||||||
<table class="table table-striped table-sm">
|
<table class="table table-striped table-sm">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -86,8 +86,6 @@
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
<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>Min Vol.</td>
|
||||||
<td class="text-right">@Model.Summary.MinBuyVolume.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
<td class="text-right">@Model.Summary.MinBuyVolume.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -101,124 +99,63 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="col-md-7">
|
<div class="col-md-6">
|
||||||
<div class="row">
|
<div class="card-box">
|
||||||
<div class="col-md-6">
|
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
|
||||||
<div class="card-box">
|
<div id="gsChart24h">
|
||||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
|
<svg style="height:200px;width:100%"></svg>
|
||||||
|
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
<h4 class="m-t-0 header-title">Global Settings Log</h4>
|
<h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4>
|
||||||
|
<div id="gsChart3d">
|
||||||
<table class="table table-striped table-sm">
|
<svg style="height:200px;width:100%"></svg>
|
||||||
<thead>
|
</div>
|
||||||
<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>
|
</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>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,6 @@
|
||||||
<ul class="submenu">
|
<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)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)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>
|
<li><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)PresetFiles"><i class="fa fa-edit"></i> Presets Files</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -82,9 +82,9 @@
|
||||||
double sellTriggerPrice = Model.DCALogData.AverageBuyPrice + (Model.DCALogData.AverageBuyPrice * Model.DCALogData.SellTrigger / 100);
|
double sellTriggerPrice = Model.DCALogData.AverageBuyPrice + (Model.DCALogData.AverageBuyPrice * Model.DCALogData.SellTrigger / 100);
|
||||||
|
|
||||||
double averageProfitPercent = 0;
|
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);
|
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 investedFiatValue = Math.Round(Model.DCALogData.TotalCost * Model.Summary.MainMarketPrice, 2);
|
||||||
double currentValue = Math.Round(Model.DCALogData.Amount * Model.DCALogData.CurrentPrice, 8);
|
double currentValue = Math.Round(Model.DCALogData.Amount * Model.DCALogData.CurrentPrice, 8);
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-5 px-1">
|
<div class="col-md-5 px-1">
|
||||||
<div class="card-box px-2" style="height:305px;">
|
<div class="card-box px-2" style="height:340px;">
|
||||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
<h4 class="m-t-0 m-b-20 header-title" style="display: inline;"><b>Market Trend History </b><i class="fa fa-info-circle text-muted" 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("")) {
|
@if (!Model.TrendChartDataJSON.Equals("")) {
|
||||||
<div class="trend-chart">
|
<div class="trend-chart">
|
||||||
<svg style="height: 300px;width: 100%;"></svg>
|
<svg style="height: 300px;width: 100%;"></svg>
|
||||||
|
@ -22,9 +22,11 @@
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3 px-1">
|
<div class="col-md-3 px-1">
|
||||||
<div class="card-box px-3" style="height:305px;">
|
<div class="card-box px-3" style="height:340px;">
|
||||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"
|
||||||
|
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"));
|
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||||
if (Model.totalCurrentValue > 100) {
|
if (Model.totalCurrentValue > 100) {
|
||||||
|
@ -34,8 +36,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: <text class="text-autocolor"> @Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance @Model.Summary.MainMarket </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.PTMagicConfiguration.GeneralSettings.Application.StartBalance) / Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance) * 100, 2)%</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>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
|
@ -49,8 +51,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4 px-1">
|
<div class="col-md-4 px-1">
|
||||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
@*<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>*@
|
||||||
<div class="card-box px-2" style="height:305px;">
|
<div class="card-box px-2" style="height: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("")) {
|
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||||
<div class="profit-chart">
|
<div class="profit-chart">
|
||||||
<svg style="height:300px;width:100%"></svg>
|
<svg style="height:300px;width:100%"></svg>
|
||||||
|
@ -61,144 +64,213 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 px-1">
|
<div class="col-md-5 px-1">
|
||||||
<div class="card-box px-2">
|
<div class="card-box px-3">
|
||||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
@* <div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeco;nds * 1000)" data-color="#aaa,#414d59"></div>
|
||||||
<br>
|
<br> *@
|
||||||
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b>
|
<h4 class="m-t-0 m-b-20 header-title">Live Trends
|
||||||
<small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4>
|
<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">
|
<table class="table table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th class="text-right">Markets</th>
|
<th class="text-right">Markets</th>
|
||||||
<th class="text-right">Timeframe</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>
|
<th class="text-right">Change</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var marketTrend in Model.MarketTrends.OrderBy(mt => mt.TrendMinutes)) {
|
@foreach (var marketTrend in Model.MarketTrends.OrderBy(mt => mt.TrendMinutes)) {
|
||||||
if (Model.Summary.MarketTrendChanges.ContainsKey(marketTrend.Name)) {
|
if (Model.Summary.MarketTrendChanges.ContainsKey(marketTrend.Name)) {
|
||||||
double trendChange = Model.Summary.MarketTrendChanges[marketTrend.Name].OrderByDescending(mtc => mtc.TrendDateTime).First().TrendChange;
|
double trendChange = Model.Summary.MarketTrendChanges[marketTrend.Name].Last().TrendChange;
|
||||||
string trendChangeOutput = trendChange.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
string trendChangeOutput = trendChange.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||||
|
|
||||||
int marketCount = marketTrend.MaxMarkets;
|
int marketCount = marketTrend.MaxMarkets;
|
||||||
string marketCountString = marketCount.ToString();
|
string marketCountString = marketCount.ToString();
|
||||||
|
|
||||||
if (marketCount == 0) {
|
if (marketCount == 0) {
|
||||||
marketCountString = "All";
|
marketCountString = "All";
|
||||||
} else if (marketCount > Model.Summary.MarketSummary.Keys.Count && marketTrend.Platform.Equals("Exchange", StringComparison.InvariantCultureIgnoreCase)) {
|
} else if (marketCount > Model.Summary.MarketSummary.Keys.Count && marketTrend.Platform.Equals("Exchange", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
marketCountString = Model.Summary.MarketSummary.Keys.Count.ToString();
|
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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 px-1">
|
<div class="col-md-7 px-1">
|
||||||
<div class="card-box px-2">
|
<div class="card-box px-3">
|
||||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
<h4 class="m-t-0 m-b-20 header-title">Sales Overview
|
||||||
<br>
|
<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>
|
||||||
<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>
|
<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;
|
double avgGrowthThisMonth = Model.PTData.MonthlyStats.FirstOrDefault(data => data.Order == 1)?.AvgGrowth ?? 0.0;
|
||||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
double avgGrowthLastMonth = Model.PTData.MonthlyStats.FirstOrDefault(data => data.Order == 2)?.AvgGrowth ?? 0.0;
|
||||||
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 todaysProfit = 0;
|
//var startingBalance = Model.MiscData.StartBalance;
|
||||||
todaysProfit = Model.PTData.SellLogToday.Sum(s => s.Profit);
|
var totalCurrentValue = Model.totalCurrentValue;
|
||||||
double todaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime);
|
var overviewStats = Model.StatsData;
|
||||||
double todaysProfitFiat = Math.Round(todaysProfit * Model.Summary.MainMarketPrice, 2);
|
|
||||||
double todaysPercentGain = Math.Round(todaysProfit / todaysStartBalance * 100, 2);
|
|
||||||
|
|
||||||
double yesterdaysProfit = 0;
|
var todaysSales = overviewStats.SalesToday;
|
||||||
yesterdaysProfit = Model.PTData.SellLogYesterday.Sum(s => s.Profit);
|
var todaysProfit = overviewStats.ProfitToday;
|
||||||
double yesterdaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-1));
|
var todaysFunding = overviewStats.FundingToday;
|
||||||
double yesterdaysProfitFiat = Math.Round(yesterdaysProfit * Model.Summary.MainMarketPrice, 2);
|
var todaysPercentGain = overviewStats.ProfitPercToday + Model.PTData.Stats.TotalFundingPercToday;
|
||||||
double yesterdaysPercentGain = Math.Round(yesterdaysProfit / yesterdaysStartBalance * 100, 2);
|
|
||||||
|
var yesterdaysSales = overviewStats.SalesYesterday;
|
||||||
|
var yesterdaysProfit = overviewStats.ProfitYesterday;
|
||||||
|
var yesterdaysFunding = overviewStats.FundingYesterday;
|
||||||
|
var yesterdaysPercentGain = overviewStats.ProfitPercYesterday + Model.PTData.Stats.TotalFundingPercYesterday;
|
||||||
|
|
||||||
double last7DaysProfit = 0;
|
var last7DaysSales = overviewStats.SalesWeek;
|
||||||
last7DaysProfit = Model.PTData.SellLogLast7Days.Sum(s => s.Profit);
|
var last7DaysProfit = overviewStats.ProfitWeek;
|
||||||
double last7DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-7));
|
var last7DaysFunding = overviewStats.FundingWeek;
|
||||||
double last7DaysProfitFiat = Math.Round(last7DaysProfit * Model.Summary.MainMarketPrice, 2);
|
var last7DaysPercentGain = overviewStats.ProfitPercWeek + Model.PTData.Stats.TotalFundingPercWeek;
|
||||||
double last7DaysPercentGain = Math.Round(last7DaysProfit / last7DaysStartBalance * 100, 2);
|
|
||||||
|
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">
|
<table class="table table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th class="text-right">Sales</th>
|
<th class="text-right">Sales</th>
|
||||||
<th class="text-right">Profit @Model.Summary.MainMarket</th>
|
<th class="text-right">Profit @Model.PTData.Misc.Market</th>
|
||||||
<th class="text-right">Profit @Model.Summary.MainFiatCurrency</th>
|
@if (futuresFunding)
|
||||||
|
{
|
||||||
|
<th class="text-right">Funding</th>
|
||||||
|
}
|
||||||
|
<th class="text-right">@Model.PTData.Properties.Currency</th>
|
||||||
<th class="text-right">Gain</th>
|
<th class="text-right">Gain</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Today</th>
|
<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">@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>
|
@if (futuresFunding)
|
||||||
<td class="text-right text-autocolor">@todaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
{
|
||||||
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Yesterday</th>
|
<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">@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>
|
@if (futuresFunding)
|
||||||
<td class="text-right text-autocolor">@yesterdaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
{
|
||||||
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Last 7 Days</th>
|
<th>7 Days</th>
|
||||||
<td class="text-right">@Model.PTData.SellLogLast7Days.Count</td>
|
<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">@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>
|
@if (futuresFunding)
|
||||||
<td class="text-right text-autocolor">@last7DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
{
|
||||||
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Last 30 Days</th>
|
@{
|
||||||
<td class="text-right">@Model.PTData.SellLogLast30Days.Count</td>
|
var timeParts = @Model.MiscData.TimeZoneOffset.Split(':');
|
||||||
<td class="text-right text-autocolor">@last30DaysProfit.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
var timeZoneOffsetHours = int.Parse(timeParts[0]);
|
||||||
<td class="text-right text-autocolor">@Html.Raw(Model.MainFiatCurrencySymbol + last30DaysProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
var timeZoneOffset = TimeSpan.FromHours(timeZoneOffsetHours);
|
||||||
<td class="text-right text-autocolor">@last30DaysPercentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Total</th>
|
<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">@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>
|
@if (futuresFunding)
|
||||||
<td class="text-right text-autocolor">@Html.Raw(percentGainText)</td>
|
{
|
||||||
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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/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.js"></script>
|
||||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/tablesaw/js/tablesaw-init.js"></script>
|
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/tablesaw/js/tablesaw-init.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$(".cdev").circlos();
|
$(".cdev").circlos();
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
$('.text-autocolor').autocolor(false);
|
$('.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")
|
d3.select("#AssetDistribution svg")
|
||||||
.datum(@Html.Raw(Model.AssetDistributionData))
|
.datum(assetDistributionData)
|
||||||
.transition().duration(350)
|
.transition().duration(0)
|
||||||
.call(chart);
|
.call(assetDistributionChart);
|
||||||
return chart;
|
|
||||||
});
|
|
||||||
</text>
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 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 ($) {
|
(function ($) {
|
||||||
'use strict';
|
'use strict';
|
||||||
$('[role="tooltip"]').remove();
|
$('[role="tooltip"]').remove();
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
$('.text-autocolor').autocolor(false);
|
$('.text-autocolor').autocolor(false);
|
||||||
|
|
||||||
@if (!Model.Summary.CurrentGlobalSetting.SettingName.Equals(Model.LastGlobalSetting)) {
|
var trendChart; // Keep a reference to the chart
|
||||||
<text>
|
var trendData; // Keep a reference to the data
|
||||||
$.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>
|
|
||||||
}
|
|
||||||
@if (!Model.TrendChartDataJSON.Equals("")) {
|
@if (!Model.TrendChartDataJSON.Equals("")) {
|
||||||
<text>
|
<text>
|
||||||
nv.addGraph(function () {
|
nv.addGraph(function () {
|
||||||
var lineChart = nv.models.lineChart();
|
trendChart = nv.models.lineChart();
|
||||||
var height = 300;
|
var height = 300;
|
||||||
var chartData = @Html.Raw(Model.TrendChartDataJSON);
|
trendChart.useInteractiveGuideline(true);
|
||||||
lineChart.useInteractiveGuideline(true);
|
trendChart.xAxis.tickFormat(function (d) { return d3.time.format('%H:%M')(new Date(d)); });
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%H:%M')(new Date(d)); });
|
trendChart.yAxis.axisLabel('Trend %').tickFormat(d3.format(',.2f'));
|
||||||
lineChart.yAxis.axisLabel('Trend %').tickFormat(d3.format(',.2f'));
|
|
||||||
d3.select('.trend-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
trendData = @Html.Raw(Model.TrendChartDataJSON);
|
||||||
//nv.utils.windowResize(lineChart.update); v1.3.0 => Removed this line to prevent memory leak
|
|
||||||
return lineChart;
|
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("")) {
|
})(jQuery);
|
||||||
<text>
|
</script>
|
||||||
nv.addGraph(function () {
|
|
||||||
var lineChart = nv.models.lineChart();
|
<script type="text/javascript">
|
||||||
var height = 300;
|
(function ($) {
|
||||||
var chartData = @Html.Raw(Model.ProfitChartDataJSON);
|
'use strict';
|
||||||
lineChart.useInteractiveGuideline(true);
|
$('[role="tooltip"]').remove();
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
lineChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
|
$('.text-autocolor').autocolor(false);
|
||||||
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
|
var profitChart; // Keep a reference to the chart
|
||||||
return lineChart;
|
var profitData; // Keep a reference to the data
|
||||||
});
|
|
||||||
</text>
|
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||||
}
|
<text>
|
||||||
})(jQuery);
|
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>
|
</script>
|
||||||
|
|
|
@ -6,14 +6,20 @@ using Core.Main;
|
||||||
using Core.Helper;
|
using Core.Helper;
|
||||||
using Core.Main.DataObjects;
|
using Core.Main.DataObjects;
|
||||||
using Core.Main.DataObjects.PTMagicData;
|
using Core.Main.DataObjects.PTMagicData;
|
||||||
using Core.MarketAnalyzer;
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Monitor.Pages
|
namespace Monitor.Pages
|
||||||
{
|
{
|
||||||
public class DashboardBottomModel : _Internal.BasePageModelSecureAJAX
|
public class DashboardBottomModel : _Internal.BasePageModelSecureAJAX
|
||||||
{
|
{
|
||||||
public ProfitTrailerData PTData = null;
|
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 List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
|
||||||
|
public double DataHours { get; set; }
|
||||||
|
public int ProfitDays { get; set; }
|
||||||
public string TrendChartDataJSON = "";
|
public string TrendChartDataJSON = "";
|
||||||
public string ProfitChartDataJSON = "";
|
public string ProfitChartDataJSON = "";
|
||||||
public string LastGlobalSetting = "Default";
|
public string LastGlobalSetting = "Default";
|
||||||
|
@ -26,12 +32,18 @@ namespace Monitor.Pages
|
||||||
base.Init();
|
base.Init();
|
||||||
|
|
||||||
BindData();
|
BindData();
|
||||||
BuildAssetDistributionData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindData()
|
private void BindData()
|
||||||
{
|
{
|
||||||
PTData = this.PtDataObject;
|
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
|
// Cleanup temp files
|
||||||
FileHelper.CleanupFilesMinutes(PTMagicMonitorBasePath + "wwwroot" + System.IO.Path.DirectorySeparatorChar + "assets" + System.IO.Path.DirectorySeparatorChar + "tmp" + System.IO.Path.DirectorySeparatorChar, 5);
|
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();
|
MarketTrends = PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.OrderBy(mt => mt.TrendMinutes).ThenByDescending(mt => mt.Platform).ToList();
|
||||||
|
|
||||||
BuildMarketTrendChartData();
|
BuildMarketTrendChartData();
|
||||||
|
BuildAssetDistributionData();
|
||||||
BuildProfitChartData();
|
BuildProfitChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildMarketTrendChartData()
|
private void BuildMarketTrendChartData()
|
||||||
{
|
{
|
||||||
if (MarketTrends.Count > 0)
|
List<string> trendChartData = new List<string>();
|
||||||
{
|
if (MarketTrends.Count > 0)
|
||||||
TrendChartDataJSON = "[";
|
|
||||||
int mtIndex = 0;
|
|
||||||
foreach (MarketTrend mt in MarketTrends)
|
|
||||||
{
|
{
|
||||||
if (mt.DisplayGraph)
|
|
||||||
{
|
int mtIndex = 0;
|
||||||
string lineColor = "";
|
foreach (MarketTrend mt in MarketTrends)
|
||||||
if (mtIndex < Constants.ChartLineColors.Length)
|
|
||||||
{
|
{
|
||||||
lineColor = Constants.ChartLineColors[mtIndex];
|
if (mt.DisplayGraph)
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
List<MarketTrendChange> tickRange = marketTrendChangeSummaries.FindAll(m => m.TrendDateTime >= tickTime).OrderBy(m => m.TrendDateTime).ToList();
|
string lineColor = mtIndex < Constants.ChartLineColors.Length
|
||||||
if (tickRange.Count > 0)
|
? Constants.ChartLineColors[mtIndex]
|
||||||
{
|
: Constants.ChartLineColors[mtIndex - 20];
|
||||||
MarketTrendChange mtc = tickRange.First();
|
|
||||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
|
||||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
|
||||||
|
|
||||||
TrendChartDataJSON += "{ x: new Date('" + tickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||||
trendChartTicks++;
|
{
|
||||||
}
|
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()
|
private void BuildProfitChartData()
|
||||||
{
|
{
|
||||||
int tradeDayIndex = 0;
|
List<object> profitPerDayList = new List<object>();
|
||||||
string profitPerDayJSON = "";
|
|
||||||
|
if (PTData.DailyPNL.Count > 0)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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()
|
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.
|
// 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)
|
foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog)
|
||||||
{
|
{
|
||||||
string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive);
|
string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive);
|
||||||
|
|
||||||
// Aggregate totals
|
// Aggregate totals
|
||||||
double leverage = dcaLogEntry.Leverage;
|
double leverage = dcaLogEntry.Leverage;
|
||||||
if (leverage == 0)
|
if (leverage == 0)
|
||||||
|
|
|
@ -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.AddDistributedMemoryCache();
|
||||||
services.AddSession(options =>
|
services.AddSession(options =>
|
||||||
{
|
{
|
||||||
options.IdleTimeout = TimeSpan.FromSeconds(900);
|
options.IdleTimeout = TimeSpan.FromSeconds(1800);
|
||||||
options.Cookie.HttpOnly = true;
|
options.Cookie.HttpOnly = true;
|
||||||
options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString();
|
options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString();
|
||||||
});
|
});
|
||||||
|
|
|
@ -639,7 +639,7 @@ a.text-dark:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-success {
|
.bg-success {
|
||||||
background-color: #81c868 !important;
|
background-color: #296a12 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-info {
|
.bg-info {
|
||||||
|
@ -647,11 +647,11 @@ a.text-dark:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-warning {
|
.bg-warning {
|
||||||
background-color: #ffbd4a !important;
|
background-color: #563a09 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-danger {
|
.bg-danger {
|
||||||
background-color: #f05050 !important;
|
background-color: #6e0e0e !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-muted {
|
.bg-muted {
|
||||||
|
@ -759,7 +759,7 @@ a.text-dark:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-success {
|
.label-success {
|
||||||
background-color: #81c868;
|
background-color: #3b5e2f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-info {
|
.label-info {
|
||||||
|
@ -767,11 +767,11 @@ a.text-dark:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-warning {
|
.label-warning {
|
||||||
background-color: #ffbd4a;
|
background-color: #847f0a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-danger {
|
.label-danger {
|
||||||
background-color: #f05050;
|
background-color: #601f1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-purple {
|
.label-purple {
|
||||||
|
@ -829,7 +829,7 @@ a.text-dark:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-success {
|
.badge-success {
|
||||||
background-color: #81c868;
|
background-color: #307516;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-info {
|
.badge-info {
|
||||||
|
@ -837,11 +837,11 @@ a.text-dark:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-warning {
|
.badge-warning {
|
||||||
background-color: #ffbd4a;
|
background-color: #6f5019;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-danger {
|
.badge-danger {
|
||||||
background-color: #f05050;
|
background-color: #6a1414;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-purple {
|
.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;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|
||||||
[assembly: AssemblyVersion("2.6.1")]
|
[assembly: AssemblyVersion("2.7.1")]
|
||||||
[assembly: AssemblyProduct("PT Magic")]
|
[assembly: AssemblyProduct("PT Magic")]
|
||||||
|
|
||||||
namespace PTMagic
|
namespace PTMagic
|
||||||
|
|
|
@ -10,13 +10,10 @@
|
||||||
"ProfitTrailerMonitorURLXtra": "", // URLs for additional bots you want PTM to update (optional - comma separated list)
|
"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)
|
"ProfitTrailerDefaultSettingName": "default", // Your Profit Trailer default setting name (needed to change your settings)
|
||||||
"Exchange": "Bittrex", // The exchange your are running Profit Trailer on
|
"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
|
"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
|
"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": {
|
"Monitor": {
|
||||||
"IsPasswordProtected": true, // Defines if your monitor will be asking to setup a password on its first start
|
"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
|
"Port": 8080, // The port you want to run your monitor on
|
||||||
"RootUrl": "/", // The root Url of your monitor
|
"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)
|
"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
|
"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
|
"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
|
"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
|
"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
|
"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)
|
"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)
|
"ProfitTrailerDefaultSettingName": "default", // Your Profit Trailer default setting name (needed to change your settings)
|
||||||
"Exchange": "Bittrex", // The exchange your are running Profit Trailer on
|
"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
|
"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
|
"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
|
"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": {
|
"Monitor": {
|
||||||
"IsPasswordProtected": true, // Defines if your monitor will be asking to setup a password on its first start
|
"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
|
"Port": 8080, // The port you want to run your monitor on
|
||||||
"RootUrl": "/", // The root Url of your monitor
|
"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)
|
"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
|
"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
|
"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
|
"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
|
"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
|
"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
|
- This version of PT Magic only works with Profit Trailer v2.4.x and above
|
||||||
|
|
||||||
### .Net
|
### .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
|
### 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.
|
- **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