commit
111c1b153b
|
@ -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,13 +312,25 @@ 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
|
||||||
{
|
{
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
#region Profit Trailer JSON Objects
|
// 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; }
|
||||||
|
// }
|
||||||
|
|
||||||
public class SellLogData
|
public class StatsData
|
||||||
{
|
{
|
||||||
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
|
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Core.Main.DataObjects.PTMagicData;
|
using Core.Main.DataObjects.PTMagicData;
|
||||||
|
|
||||||
|
@ -14,18 +15,60 @@ namespace Core.Main.DataObjects
|
||||||
|
|
||||||
public class ProfitTrailerData
|
public class ProfitTrailerData
|
||||||
{
|
{
|
||||||
private SummaryData _summary = null;
|
private MiscData _misc = null;
|
||||||
private Properties _properties = null;
|
private PropertiesData _properties = null;
|
||||||
private List<SellLogData> _sellLog = new List<SellLogData>();
|
private StatsData _stats = null;
|
||||||
|
private List<DailyPNLData> _dailyPNL = new List<DailyPNLData>();
|
||||||
|
private List<DailyTCVData> _dailyTCV = new List<DailyTCVData>();
|
||||||
|
private List<MonthlyStatsData> _monthlyStats = new List<MonthlyStatsData>();
|
||||||
|
private List<ProfitablePairsData> _profitablePairs = new List<ProfitablePairsData>();
|
||||||
|
private List<DailyStatsData> _dailyStats = new List<DailyStatsData>();
|
||||||
|
private decimal? _totalProfit = null;
|
||||||
|
public decimal? TotalProfit
|
||||||
|
{
|
||||||
|
get { return _totalProfit; }
|
||||||
|
set { _totalProfit = value; }
|
||||||
|
}
|
||||||
|
private decimal? _totalSales = null;
|
||||||
|
public decimal? TotalSales
|
||||||
|
{
|
||||||
|
get { return _totalSales; }
|
||||||
|
set { _totalSales = value; }
|
||||||
|
}
|
||||||
|
//private List<SellLogData> _sellLog = new List<SellLogData>();
|
||||||
private List<DCALogData> _dcaLog = new List<DCALogData>();
|
private List<DCALogData> _dcaLog = new List<DCALogData>();
|
||||||
private List<BuyLogData> _buyLog = new List<BuyLogData>();
|
private List<BuyLogData> _buyLog = new List<BuyLogData>();
|
||||||
private string _ptmBasePath = "";
|
private string _ptmBasePath = "";
|
||||||
private PTMagicConfiguration _systemConfiguration = null;
|
private PTMagicConfiguration _systemConfiguration = null;
|
||||||
private TransactionData _transactionData = null;
|
private TransactionData _transactionData = null;
|
||||||
private DateTime _buyLogRefresh = DateTime.UtcNow, _sellLogRefresh = DateTime.UtcNow, _dcaLogRefresh = DateTime.UtcNow, _summaryRefresh = DateTime.UtcNow, _propertiesRefresh = DateTime.UtcNow;
|
private DateTime _dailyPNLRefresh = DateTime.UtcNow;
|
||||||
private volatile object _buyLock = new object(), _sellLock = new object(), _dcaLock = new object(), _summaryLock = new object(), _propertiesLock = new object();
|
private DateTime _dailyTCVRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _monthlyStatsRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _statsRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _buyLogRefresh = DateTime.UtcNow;
|
||||||
|
//private DateTime _sellLogRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _dcaLogRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _miscRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _propertiesRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _profitablePairsRefresh = DateTime.UtcNow;
|
||||||
|
private DateTime _dailyStatsRefresh = DateTime.UtcNow;
|
||||||
|
private volatile object _dailyPNLLock = new object();
|
||||||
|
private volatile object _dailyTCVLock = new object();
|
||||||
|
private volatile object _monthlyStatsLock = new object();
|
||||||
|
private volatile object _statsLock = new object();
|
||||||
|
private volatile object _buyLock = new object();
|
||||||
|
private volatile object _sellLock = new object();
|
||||||
|
private volatile object _dcaLock = new object();
|
||||||
|
private volatile object _miscLock = new object();
|
||||||
|
private volatile object _propertiesLock = new object();
|
||||||
|
private volatile object _profitablePairsLock = new object();
|
||||||
|
private volatile object _dailyStatsLock = new object();
|
||||||
private TimeSpan? _offsetTimeSpan = null;
|
private TimeSpan? _offsetTimeSpan = null;
|
||||||
|
public void DoLog(string message)
|
||||||
|
{
|
||||||
|
// Implement your logging logic here
|
||||||
|
Console.WriteLine(message);
|
||||||
|
}
|
||||||
// Constructor
|
// Constructor
|
||||||
public ProfitTrailerData(PTMagicConfiguration systemConfiguration)
|
public ProfitTrailerData(PTMagicConfiguration systemConfiguration)
|
||||||
{
|
{
|
||||||
|
@ -56,27 +99,111 @@ namespace Core.Main.DataObjects
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SummaryData Summary
|
public MiscData Misc
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_summary == null || (DateTime.UtcNow > _summaryRefresh))
|
if (_misc == null || (DateTime.UtcNow > _miscRefresh))
|
||||||
{
|
{
|
||||||
lock (_summaryLock)
|
lock (_miscLock)
|
||||||
{
|
{
|
||||||
// Thread double locking
|
// Thread double locking
|
||||||
if (_summary == null || (DateTime.UtcNow > _summaryRefresh))
|
if (_misc == null || (DateTime.UtcNow > _miscRefresh))
|
||||||
{
|
{
|
||||||
_summary = BuildSummaryData(GetDataFromProfitTrailer("api/v2/data/misc"));
|
_misc = BuildMiscData(GetDataFromProfitTrailer("api/v2/data/misc"));
|
||||||
_summaryRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
_miscRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _summary;
|
return _misc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Properties Properties
|
private MiscData BuildMiscData(dynamic PTData)
|
||||||
|
{
|
||||||
|
return new MiscData()
|
||||||
|
{
|
||||||
|
Market = PTData.market,
|
||||||
|
FiatConversionRate = PTData.priceDataFiatConversionRate,
|
||||||
|
Balance = PTData.realBalance,
|
||||||
|
PairsValue = PTData.totalPairsCurrentValue,
|
||||||
|
DCAValue = PTData.totalDCACurrentValue,
|
||||||
|
PendingValue = PTData.totalPendingCurrentValue,
|
||||||
|
DustValue = PTData.totalDustCurrentValue,
|
||||||
|
StartBalance = PTData.startBalance,
|
||||||
|
TotalCurrentValue = PTData.totalCurrentValue,
|
||||||
|
TimeZoneOffset = PTData.timeZoneOffset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<DailyStatsData> DailyStats
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_dailyStats == null || DateTime.UtcNow > _dailyStatsRefresh)
|
||||||
|
{
|
||||||
|
lock (_dailyStatsLock)
|
||||||
|
{
|
||||||
|
if (_dailyStats == null || DateTime.UtcNow > _dailyStatsRefresh)
|
||||||
|
{
|
||||||
|
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
JObject basicSection = null;
|
||||||
|
JObject extraSection = null;
|
||||||
|
|
||||||
|
while (jsonReader.Read())
|
||||||
|
{
|
||||||
|
if (jsonReader.TokenType == JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
if ((string)jsonReader.Value == "basic")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "basic" property
|
||||||
|
basicSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
else if ((string)jsonReader.Value == "extra")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "extra" property
|
||||||
|
extraSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basicSection != null && extraSection != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basicSection != null)
|
||||||
|
{
|
||||||
|
if (extraSection != null)
|
||||||
|
{
|
||||||
|
JArray dailyStatsSection = (JArray)extraSection["dailyStats"];
|
||||||
|
_dailyStats = dailyStatsSection.Select(j => BuildDailyStatsData(j as JObject)).ToList();
|
||||||
|
_dailyStatsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _dailyStats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private DailyStatsData BuildDailyStatsData(dynamic dailyStatsDataJson)
|
||||||
|
{
|
||||||
|
return new DailyStatsData()
|
||||||
|
{
|
||||||
|
Date = dailyStatsDataJson["date"],
|
||||||
|
TotalSales = dailyStatsDataJson["totalSales"],
|
||||||
|
TotalBuys = dailyStatsDataJson["totalBuys"],
|
||||||
|
TotalProfit = dailyStatsDataJson["totalProfitCurrency"],
|
||||||
|
AvgProfit = dailyStatsDataJson["avgProfit"],
|
||||||
|
AvgGrowth = dailyStatsDataJson["avgGrowth"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertiesData Properties
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -96,81 +223,420 @@ namespace Core.Main.DataObjects
|
||||||
return _properties;
|
return _properties;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public List<SellLogData> SellLog
|
private PropertiesData BuildProptertiesData(dynamic PTProperties)
|
||||||
|
{
|
||||||
|
return new PropertiesData()
|
||||||
|
{
|
||||||
|
Currency = PTProperties.currency,
|
||||||
|
Shorting = PTProperties.shorting,
|
||||||
|
Margin = PTProperties.margin,
|
||||||
|
UpTime = PTProperties.upTime,
|
||||||
|
Port = PTProperties.port,
|
||||||
|
IsLeverageExchange = PTProperties.isLeverageExchange,
|
||||||
|
BaseUrl = PTProperties.baseUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatsData Stats
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh))
|
if (_stats == null || DateTime.UtcNow > _statsRefresh)
|
||||||
{
|
{
|
||||||
lock (_sellLock)
|
lock (_statsLock)
|
||||||
{
|
{
|
||||||
// Thread double locking
|
if (_stats == null || DateTime.UtcNow > _statsRefresh)
|
||||||
if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh))
|
|
||||||
{
|
{
|
||||||
_sellLog.Clear();
|
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
// Page through the sales data summarizing it.
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
bool exitLoop = false;
|
|
||||||
int pageIndex = 1;
|
|
||||||
|
|
||||||
while (!exitLoop)
|
|
||||||
{
|
{
|
||||||
var sellDataPage = GetDataFromProfitTrailer("/api/v2/data/sales?perPage=5000&sort=SOLDDATE&sortDirection=ASCENDING&page=" + pageIndex);
|
while (jsonReader.Read())
|
||||||
if (sellDataPage != null && sellDataPage.data.Count > 0)
|
|
||||||
{
|
{
|
||||||
// Add sales data page to collection
|
if (jsonReader.TokenType == JsonToken.PropertyName && (string)jsonReader.Value == "basic")
|
||||||
this.BuildSellLogData(sellDataPage);
|
|
||||||
pageIndex++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// All data retrieved
|
jsonReader.Read(); // Move to the value of the "basic" property
|
||||||
exitLoop = true;
|
JObject basicSection = JObject.Load(jsonReader);
|
||||||
}
|
_stats = BuildStatsData(basicSection);
|
||||||
}
|
_statsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
|
break;
|
||||||
// Update sell log refresh time
|
|
||||||
_sellLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _sellLog;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public List<SellLogData> SellLogToday
|
return _stats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private StatsData BuildStatsData(dynamic statsDataJson)
|
||||||
|
{
|
||||||
|
return new StatsData()
|
||||||
|
{
|
||||||
|
SalesToday = statsDataJson["totalSalesToday"],
|
||||||
|
ProfitToday = statsDataJson["totalProfitToday"],
|
||||||
|
ProfitPercToday = statsDataJson["totalProfitPercToday"],
|
||||||
|
SalesYesterday = statsDataJson["totalSalesYesterday"],
|
||||||
|
ProfitYesterday = statsDataJson["totalProfitYesterday"],
|
||||||
|
ProfitPercYesterday = statsDataJson["totalProfitPercYesterday"],
|
||||||
|
SalesWeek = statsDataJson["totalSalesWeek"],
|
||||||
|
ProfitWeek = statsDataJson["totalProfitWeek"],
|
||||||
|
ProfitPercWeek = statsDataJson["totalProfitPercWeek"],
|
||||||
|
SalesThisMonth = statsDataJson["totalSalesThisMonth"],
|
||||||
|
ProfitThisMonth = statsDataJson["totalProfitThisMonth"],
|
||||||
|
ProfitPercThisMonth = statsDataJson["totalProfitPercThisMonth"],
|
||||||
|
SalesLastMonth = statsDataJson["totalSalesLastMonth"],
|
||||||
|
ProfitLastMonth = statsDataJson["totalProfitLastMonth"],
|
||||||
|
ProfitPercLastMonth = statsDataJson["totalProfitPercLastMonth"],
|
||||||
|
TotalProfit = statsDataJson["totalProfit"],
|
||||||
|
TotalSales = statsDataJson["totalSales"],
|
||||||
|
TotalProfitPerc = statsDataJson["totalProfitPerc"],
|
||||||
|
FundingToday = statsDataJson["totalFundingToday"],
|
||||||
|
FundingYesterday = statsDataJson["totalFundingYesterday"],
|
||||||
|
FundingWeek = statsDataJson["totalFundingWeek"],
|
||||||
|
FundingThisMonth = statsDataJson["totalFundingThisMonth"],
|
||||||
|
FundingLastMonth = statsDataJson["totalFundingLastMonth"],
|
||||||
|
FundingTotal = statsDataJson["totalFunding"],
|
||||||
|
TotalFundingPerc = statsDataJson["totalFundingPerc"],
|
||||||
|
TotalFundingPercYesterday = statsDataJson["totalFundingPercYesterday"],
|
||||||
|
TotalFundingPercWeek = statsDataJson["totalFundingPercWeekPerc"],
|
||||||
|
TotalFundingPercToday = statsDataJson["totalFundingPercTodayPerc"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<DailyPNLData> DailyPNL
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return SellLog.FindAll(sl => sl.SoldDate.Date == LocalizedTime.DateTime.Date);
|
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||||
|
{
|
||||||
|
lock (_dailyPNLLock)
|
||||||
|
{
|
||||||
|
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
|
||||||
|
{
|
||||||
|
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
JObject basicSection = null;
|
||||||
|
JObject extraSection = null;
|
||||||
|
|
||||||
|
while (jsonReader.Read())
|
||||||
|
{
|
||||||
|
if (jsonReader.TokenType == JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
if ((string)jsonReader.Value == "basic")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "basic" property
|
||||||
|
basicSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
else if ((string)jsonReader.Value == "extra")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "extra" property
|
||||||
|
extraSection = JObject.Load(jsonReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SellLogData> SellLogYesterday
|
if (basicSection != null && extraSection != null)
|
||||||
{
|
{
|
||||||
get
|
break;
|
||||||
{
|
|
||||||
return SellLog.FindAll(sl => sl.SoldDate.Date == LocalizedTime.DateTime.AddDays(-1).Date);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SellLogData> SellLogLast7Days
|
if (basicSection != null &&
|
||||||
|
((_totalProfit == null ||
|
||||||
|
!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) ||
|
||||||
|
(_totalSales == null ||
|
||||||
|
!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>()))))
|
||||||
|
{
|
||||||
|
_totalProfit = basicSection["totalProfit"].Value<decimal>();
|
||||||
|
_totalSales = basicSection["totalSales"].Value<decimal>();
|
||||||
|
|
||||||
|
if (extraSection != null)
|
||||||
|
{
|
||||||
|
JArray dailyPNLSection = (JArray)extraSection["dailyPNLStats"];
|
||||||
|
_dailyPNL = dailyPNLSection.Select(j => BuildDailyPNLData(j as JObject)).ToList();
|
||||||
|
_dailyPNLRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _dailyPNL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private DailyPNLData BuildDailyPNLData(dynamic dailyPNLDataJson)
|
||||||
|
{
|
||||||
|
return new DailyPNLData()
|
||||||
|
{
|
||||||
|
Date = dailyPNLDataJson["date"],
|
||||||
|
CumulativeProfitCurrency = dailyPNLDataJson["cumulativeProfitCurrency"],
|
||||||
|
Order = dailyPNLDataJson["order"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<ProfitablePairsData> ProfitablePairs
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return SellLog.FindAll(sl => sl.SoldDate.Date >= LocalizedTime.DateTime.AddDays(-7).Date);
|
if (_profitablePairs == null || DateTime.UtcNow > _profitablePairsRefresh)
|
||||||
|
{
|
||||||
|
lock (_profitablePairsLock)
|
||||||
|
{
|
||||||
|
if (_profitablePairs == null || DateTime.UtcNow > _profitablePairsRefresh)
|
||||||
|
{
|
||||||
|
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
JObject basicSection = null;
|
||||||
|
JObject extraSection = null;
|
||||||
|
while (jsonReader.Read())
|
||||||
|
{
|
||||||
|
if (jsonReader.TokenType == JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
if ((string)jsonReader.Value == "basic")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "basic" property
|
||||||
|
basicSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
else if ((string)jsonReader.Value == "extra")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "extra" property
|
||||||
|
extraSection = JObject.Load(jsonReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SellLogData> SellLogLast30Days
|
if (basicSection != null && extraSection != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (basicSection != null)
|
||||||
|
{
|
||||||
|
if (extraSection != null)
|
||||||
|
{
|
||||||
|
JObject profitablePairsSection = (JObject)extraSection["profitablePairs"];
|
||||||
|
_profitablePairs = new List<ProfitablePairsData>();
|
||||||
|
int counter = 0;
|
||||||
|
foreach (var j in profitablePairsSection)
|
||||||
|
{
|
||||||
|
if (counter >= _systemConfiguration.GeneralSettings.Monitor.MaxTopMarkets)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Process each JObject in the dictionary
|
||||||
|
JObject profitablePair = (JObject)j.Value;
|
||||||
|
_profitablePairs.Add(BuildProfitablePairs(profitablePair));
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
_profitablePairsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _profitablePairs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private ProfitablePairsData BuildProfitablePairs(JObject profitablePairsJson)
|
||||||
|
{
|
||||||
|
return new ProfitablePairsData()
|
||||||
|
{
|
||||||
|
Coin = profitablePairsJson["coin"].Value<string>(),
|
||||||
|
ProfitCurrency = profitablePairsJson["profitCurrency"].Value<double>(),
|
||||||
|
SoldTimes = profitablePairsJson["soldTimes"].Value<int>(),
|
||||||
|
Avg = profitablePairsJson["avg"].Value<double>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DailyTCVData> DailyTCV
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return SellLog.FindAll(sl => sl.SoldDate.Date >= LocalizedTime.DateTime.AddDays(-30).Date);
|
if (_dailyTCV == null || DateTime.UtcNow > _dailyTCVRefresh)
|
||||||
|
{
|
||||||
|
lock (_dailyTCVLock)
|
||||||
|
{
|
||||||
|
if (_dailyTCV == null || DateTime.UtcNow > _dailyTCVRefresh)
|
||||||
|
{
|
||||||
|
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
JObject basicSection = null;
|
||||||
|
JObject extraSection = null;
|
||||||
|
|
||||||
|
while (jsonReader.Read())
|
||||||
|
{
|
||||||
|
if (jsonReader.TokenType == JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
if ((string)jsonReader.Value == "basic")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "basic" property
|
||||||
|
basicSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
else if ((string)jsonReader.Value == "extra")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "extra" property
|
||||||
|
extraSection = JObject.Load(jsonReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (basicSection != null && extraSection != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basicSection != null)
|
||||||
|
{
|
||||||
|
if (extraSection != null)
|
||||||
|
{
|
||||||
|
JArray dailyTCVSection = (JArray)extraSection["dailyTCVStats"];
|
||||||
|
_dailyTCV = dailyTCVSection.Select(j => BuildDailyTCVData(j as JObject)).ToList();
|
||||||
|
_dailyTCVRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _dailyTCV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int GetTotalTCVDays()
|
||||||
|
{
|
||||||
|
return DailyTCV?.Count ?? 0;
|
||||||
|
}
|
||||||
|
private DailyTCVData BuildDailyTCVData(dynamic dailyTCVDataJson)
|
||||||
|
{
|
||||||
|
return new DailyTCVData()
|
||||||
|
{
|
||||||
|
Date = dailyTCVDataJson["date"],
|
||||||
|
TCV = dailyTCVDataJson["TCV"],
|
||||||
|
Order = dailyTCVDataJson["order"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<MonthlyStatsData> MonthlyStats
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_monthlyStats == null || DateTime.UtcNow > _monthlyStatsRefresh)
|
||||||
|
{
|
||||||
|
lock (_monthlyStatsLock)
|
||||||
|
{
|
||||||
|
if (_monthlyStats == null || DateTime.UtcNow > _monthlyStatsRefresh)
|
||||||
|
{
|
||||||
|
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
using (var jsonReader = new JsonTextReader(reader))
|
||||||
|
{
|
||||||
|
JObject basicSection = null;
|
||||||
|
JObject extraSection = null;
|
||||||
|
|
||||||
|
while (jsonReader.Read())
|
||||||
|
{
|
||||||
|
if (jsonReader.TokenType == JsonToken.PropertyName)
|
||||||
|
{
|
||||||
|
if ((string)jsonReader.Value == "basic")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "basic" property
|
||||||
|
basicSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
else if ((string)jsonReader.Value == "extra")
|
||||||
|
{
|
||||||
|
jsonReader.Read(); // Move to the value of the "extra" property
|
||||||
|
extraSection = JObject.Load(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basicSection != null && extraSection != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basicSection != null)// &&
|
||||||
|
{
|
||||||
|
if (extraSection != null)
|
||||||
|
{
|
||||||
|
JArray monthlyStatsSection = (JArray)extraSection["monthlyStats"];
|
||||||
|
_monthlyStats = monthlyStatsSection.Select(j => BuildMonthlyStatsData(j as JObject)).ToList();
|
||||||
|
_monthlyStatsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _monthlyStats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MonthlyStatsData BuildMonthlyStatsData(dynamic monthlyStatsDataJson)
|
||||||
|
{
|
||||||
|
return new MonthlyStatsData()
|
||||||
|
{
|
||||||
|
Month = monthlyStatsDataJson["month"],
|
||||||
|
TotalSales = monthlyStatsDataJson["totalSales"],
|
||||||
|
TotalProfitCurrency = monthlyStatsDataJson["totalProfitCurrency"],
|
||||||
|
AvgGrowth = monthlyStatsDataJson["avgGrowth"],
|
||||||
|
Order = monthlyStatsDataJson["order"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// public List<SellLogData> SellLog
|
||||||
|
// {
|
||||||
|
// get
|
||||||
|
// {
|
||||||
|
|
||||||
|
// if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh))
|
||||||
|
// {
|
||||||
|
// lock (_sellLock)
|
||||||
|
// {
|
||||||
|
// // Thread double locking
|
||||||
|
// if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh))
|
||||||
|
// {
|
||||||
|
// _sellLog.Clear();
|
||||||
|
|
||||||
|
|
||||||
|
// // Page through the sales data summarizing it.
|
||||||
|
// bool exitLoop = false;
|
||||||
|
// int pageIndex = 1;
|
||||||
|
|
||||||
|
// // 1 record per page to allow user to set max records to retrieve
|
||||||
|
// int maxPages = _systemConfiguration.GeneralSettings.Monitor.MaxSalesRecords;
|
||||||
|
// int requestedPages = 0;
|
||||||
|
|
||||||
|
// while (!exitLoop && requestedPages < maxPages)
|
||||||
|
// {
|
||||||
|
// var sellDataPage = GetDataFromProfitTrailer("/api/v2/data/sales?Page=1&perPage=1&sort=SOLDDATE&sortDirection=DESCENDING&page=" + pageIndex);
|
||||||
|
// if (sellDataPage != null && sellDataPage.data.Count > 0)
|
||||||
|
// {
|
||||||
|
// // Add sales data page to collection
|
||||||
|
// this.BuildSellLogData(sellDataPage);
|
||||||
|
// pageIndex++;
|
||||||
|
// requestedPages++;
|
||||||
|
// Console.WriteLine($"Importing salesLog: {pageIndex}");
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // All data retrieved
|
||||||
|
// exitLoop = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Update sell log refresh time
|
||||||
|
// _sellLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds -1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return _sellLog;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
public List<DCALogData> DCALog
|
public List<DCALogData> DCALog
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -196,7 +662,6 @@ namespace Core.Main.DataObjects
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
pendingData = GetDataFromProfitTrailer("/api/v2/data/pending", true);
|
pendingData = GetDataFromProfitTrailer("/api/v2/data/pending", true);
|
||||||
|
|
||||||
},
|
},
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
|
@ -247,41 +712,42 @@ namespace Core.Main.DataObjects
|
||||||
public double GetCurrentBalance()
|
public double GetCurrentBalance()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(this.Summary.Balance);
|
(this.Misc.Balance);
|
||||||
}
|
}
|
||||||
public double GetPairsBalance()
|
public double GetPairsBalance()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(this.Summary.PairsValue);
|
(this.Misc.PairsValue);
|
||||||
}
|
}
|
||||||
public double GetDCABalance()
|
public double GetDCABalance()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(this.Summary.DCAValue);
|
(this.Misc.DCAValue);
|
||||||
}
|
}
|
||||||
public double GetPendingBalance()
|
public double GetPendingBalance()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(this.Summary.PendingValue);
|
(this.Misc.PendingValue);
|
||||||
}
|
}
|
||||||
public double GetDustBalance()
|
public double GetDustBalance()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(this.Summary.DustValue);
|
(this.Misc.DustValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double GetSnapshotBalance(DateTime snapshotDateTime)
|
|
||||||
{
|
|
||||||
double result = _systemConfiguration.GeneralSettings.Application.StartBalance;
|
|
||||||
|
|
||||||
result += this.SellLog.FindAll(sl => sl.SoldDate.Date < snapshotDateTime.Date).Sum(sl => sl.Profit);
|
// public double GetSnapshotBalance(DateTime snapshotDateTime)
|
||||||
result += this.TransactionData.Transactions.FindAll(t => t.UTCDateTime < snapshotDateTime).Sum(t => t.Amount);
|
// {
|
||||||
|
// double result = _misc.StartBalance;
|
||||||
|
|
||||||
// Calculate holdings for snapshot date
|
// result += this.SellLog.FindAll(sl => sl.SoldDate.Date < snapshotDateTime.Date).Sum(sl => sl.Profit);
|
||||||
result += this.DCALog.FindAll(pairs => pairs.FirstBoughtDate <= snapshotDateTime).Sum(pairs => pairs.CurrentValue);
|
// result += this.TransactionData.Transactions.FindAll(t => t.UTCDateTime < snapshotDateTime).Sum(t => t.Amount);
|
||||||
|
|
||||||
return result;
|
// // Calculate holdings for snapshot date
|
||||||
}
|
// result += this.DCALog.FindAll(pairs => pairs.FirstBoughtDate <= snapshotDateTime).Sum(pairs => pairs.CurrentValue);
|
||||||
|
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
private dynamic GetDataFromProfitTrailer(string callPath, bool arrayReturned = false)
|
private dynamic GetDataFromProfitTrailer(string callPath, bool arrayReturned = false)
|
||||||
{
|
{
|
||||||
|
@ -308,7 +774,7 @@ namespace Core.Main.DataObjects
|
||||||
|
|
||||||
response.Close();
|
response.Close();
|
||||||
|
|
||||||
// Parse the JSON and build the data sets
|
|
||||||
if (!arrayReturned)
|
if (!arrayReturned)
|
||||||
{
|
{
|
||||||
return JObject.Parse(rawBody);
|
return JObject.Parse(rawBody);
|
||||||
|
@ -318,62 +784,58 @@ namespace Core.Main.DataObjects
|
||||||
return JArray.Parse(rawBody);
|
return JArray.Parse(rawBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private Stream GetDataFromProfitTrailerAsStream(string callPath)
|
||||||
|
{
|
||||||
|
string url = string.Format("{0}{1}{2}token={3}", _systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL,
|
||||||
|
callPath,
|
||||||
|
callPath.Contains("?") ? "&" : "?",
|
||||||
|
_systemConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken);
|
||||||
|
|
||||||
private SummaryData BuildSummaryData(dynamic PTData)
|
// Get the data from PT
|
||||||
{
|
Debug.WriteLine(String.Format("{0} - Calling '{1}'", DateTime.UtcNow, url));
|
||||||
return new SummaryData()
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||||
{
|
request.AutomaticDecompression = DecompressionMethods.GZip;
|
||||||
Market = PTData.market,
|
request.KeepAlive = true;
|
||||||
Balance = PTData.realBalance,
|
|
||||||
PairsValue = PTData.totalPairsCurrentValue,
|
WebResponse response = request.GetResponse();
|
||||||
DCAValue = PTData.totalDCACurrentValue,
|
|
||||||
PendingValue = PTData.totalPendingCurrentValue,
|
return response.GetResponseStream();
|
||||||
DustValue = PTData.totalDustCurrentValue
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
private Properties BuildProptertiesData(dynamic PTProperties)
|
|
||||||
{
|
|
||||||
return new Properties()
|
|
||||||
{
|
|
||||||
Currency = PTProperties.currency,
|
|
||||||
Shorting = PTProperties.shorting,
|
|
||||||
Margin = PTProperties.margin,
|
|
||||||
UpTime = PTProperties.upTime,
|
|
||||||
Port = PTProperties.port,
|
|
||||||
IsLeverageExchange = PTProperties.isLeverageExchange,
|
|
||||||
BaseUrl = PTProperties.baseUrl
|
|
||||||
};
|
|
||||||
}
|
|
||||||
private void BuildSellLogData(dynamic rawSellLogData)
|
|
||||||
{
|
|
||||||
foreach (var rsld in rawSellLogData.data)
|
|
||||||
{
|
|
||||||
SellLogData sellLogData = new SellLogData();
|
|
||||||
sellLogData.SoldAmount = rsld.soldAmount;
|
|
||||||
sellLogData.BoughtTimes = rsld.boughtTimes;
|
|
||||||
sellLogData.Market = rsld.market;
|
|
||||||
sellLogData.ProfitPercent = rsld.profit;
|
|
||||||
sellLogData.SoldPrice = rsld.currentPrice;
|
|
||||||
sellLogData.AverageBuyPrice = rsld.avgPrice;
|
|
||||||
sellLogData.TotalCost = rsld.totalCost;
|
|
||||||
sellLogData.Profit = rsld.profitCurrency;
|
|
||||||
|
|
||||||
|
|
||||||
//Convert Unix Timestamp to Datetime
|
// private void BuildSellLogData(dynamic rawSellLogData)
|
||||||
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
// {
|
||||||
dtDateTime = dtDateTime.AddSeconds((double)rsld.soldDate).ToUniversalTime();
|
// foreach (var rsld in rawSellLogData.data)
|
||||||
|
// {
|
||||||
|
// SellLogData sellLogData = new SellLogData();
|
||||||
|
// sellLogData.SoldAmount = rsld.soldAmount;
|
||||||
|
// sellLogData.BoughtTimes = rsld.boughtTimes;
|
||||||
|
// sellLogData.Market = rsld.market;
|
||||||
|
// sellLogData.ProfitPercent = rsld.profit;
|
||||||
|
// sellLogData.SoldPrice = rsld.currentPrice;
|
||||||
|
// sellLogData.AverageBuyPrice = rsld.avgPrice;
|
||||||
|
// sellLogData.TotalCost = rsld.totalCost;
|
||||||
|
// sellLogData.Profit = rsld.profitCurrency;
|
||||||
|
|
||||||
// Profit Trailer sales are saved in UTC
|
|
||||||
DateTimeOffset ptSoldDate = DateTimeOffset.Parse(dtDateTime.Year.ToString() + "-" + dtDateTime.Month.ToString("00") + "-" + dtDateTime.Day.ToString("00") + "T" + dtDateTime.Hour.ToString("00") + ":" + dtDateTime.Minute.ToString("00") + ":" + dtDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
|
||||||
|
|
||||||
// Convert UTC sales time to local offset time
|
// //Convert Unix Timestamp to Datetime
|
||||||
ptSoldDate = ptSoldDate.ToOffset(OffsetTimeSpan);
|
// System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
||||||
|
// dtDateTime = dtDateTime.AddSeconds((double)rsld.soldDate).ToUniversalTime();
|
||||||
|
|
||||||
sellLogData.SoldDate = ptSoldDate.DateTime;
|
|
||||||
|
|
||||||
_sellLog.Add(sellLogData);
|
// // Profit Trailer sales are saved in UTC
|
||||||
}
|
// DateTimeOffset ptSoldDate = DateTimeOffset.Parse(dtDateTime.Year.ToString() + "-" + dtDateTime.Month.ToString("00") + "-" + dtDateTime.Day.ToString("00") + "T" + dtDateTime.Hour.ToString("00") + ":" + dtDateTime.Minute.ToString("00") + ":" + dtDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||||
}
|
|
||||||
|
|
||||||
|
// // Convert UTC sales time to local offset time
|
||||||
|
|
||||||
|
// ptSoldDate = ptSoldDate.ToOffset(OffsetTimeSpan);
|
||||||
|
|
||||||
|
// sellLogData.SoldDate = ptSoldDate.DateTime;
|
||||||
|
|
||||||
|
// _sellLog.Add(sellLogData);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData)
|
private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData)
|
||||||
{
|
{
|
||||||
|
@ -388,7 +850,6 @@ namespace Core.Main.DataObjects
|
||||||
|
|
||||||
// Parse watch only pairs data
|
// Parse watch only pairs data
|
||||||
_dcaLog.AddRange(ParsePairsData(rawWatchModeLogData, false));
|
_dcaLog.AddRange(ParsePairsData(rawWatchModeLogData, false));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the pairs data from PT to our own common data structure.
|
// Parse the pairs data from PT to our own common data structure.
|
||||||
|
|
|
@ -14,7 +14,6 @@ namespace Core.Main
|
||||||
{
|
{
|
||||||
public class PTMagic
|
public class PTMagic
|
||||||
{
|
{
|
||||||
|
|
||||||
public PTMagic(LogHelper log)
|
public PTMagic(LogHelper log)
|
||||||
{
|
{
|
||||||
this.Log = log;
|
this.Log = log;
|
||||||
|
@ -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,6 +64,8 @@
|
||||||
|
|
||||||
var loadDashboardBottom = function () {
|
var loadDashboardBottom = function () {
|
||||||
//destroy all d3 svg graph to avoid memory leak
|
//destroy all d3 svg graph to avoid memory leak
|
||||||
|
setTimeout(function()
|
||||||
|
{
|
||||||
$(".nvtooltip").remove();
|
$(".nvtooltip").remove();
|
||||||
$("svg > *").remove();
|
$("svg > *").remove();
|
||||||
$("svg").remove();
|
$("svg").remove();
|
||||||
|
@ -71,6 +73,7 @@
|
||||||
nv.graphs = [];
|
nv.graphs = [];
|
||||||
nv.logs = {};
|
nv.logs = {};
|
||||||
nv.tooltip = {};
|
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,23 +30,18 @@ namespace Monitor.Pages
|
||||||
|
|
||||||
private void BuildMarketTrendChartData()
|
private void BuildMarketTrendChartData()
|
||||||
{
|
{
|
||||||
|
List<string> trendChartData = new List<string>();
|
||||||
if (MarketTrends.Count > 0)
|
if (MarketTrends.Count > 0)
|
||||||
{
|
{
|
||||||
TrendChartDataJSON = "[";
|
|
||||||
int mtIndex = 0;
|
int mtIndex = 0;
|
||||||
foreach (MarketTrend mt in MarketTrends)
|
foreach (MarketTrend mt in MarketTrends)
|
||||||
{
|
{
|
||||||
if (mt.DisplayGraph)
|
if (mt.DisplayGraph)
|
||||||
{
|
{
|
||||||
string lineColor = "";
|
string lineColor = mtIndex < Constants.ChartLineColors.Length
|
||||||
if (mtIndex < Constants.ChartLineColors.Length)
|
? Constants.ChartLineColors[mtIndex]
|
||||||
{
|
: Constants.ChartLineColors[mtIndex - 20];
|
||||||
lineColor = Constants.ChartLineColors[mtIndex];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lineColor = Constants.ChartLineColors[mtIndex - 20];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||||
{
|
{
|
||||||
|
@ -52,53 +49,66 @@ namespace Monitor.Pages
|
||||||
|
|
||||||
if (marketTrendChangeSummaries.Count > 0)
|
if (marketTrendChangeSummaries.Count > 0)
|
||||||
{
|
{
|
||||||
if (!TrendChartDataJSON.Equals("[")) TrendChartDataJSON += ",";
|
List<string> trendValues = new List<string>();
|
||||||
|
|
||||||
TrendChartDataJSON += "{";
|
// Sort marketTrendChangeSummaries by TrendDateTime
|
||||||
TrendChartDataJSON += "key: '" + SystemHelper.SplitCamelCase(mt.Name) + "',";
|
marketTrendChangeSummaries = marketTrendChangeSummaries.OrderBy(m => m.TrendDateTime).ToList();
|
||||||
TrendChartDataJSON += "color: '" + lineColor + "',";
|
|
||||||
TrendChartDataJSON += "values: [";
|
|
||||||
|
|
||||||
// Get trend ticks for chart
|
// Get trend ticks for chart
|
||||||
DateTime currentDateTime = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, DateTime.UtcNow.Hour, 0, 0);
|
TimeSpan offset;
|
||||||
|
bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-");
|
||||||
|
string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-');
|
||||||
|
|
||||||
|
if (!TimeSpan.TryParse(offsetWithoutSign, out offset))
|
||||||
|
{
|
||||||
|
offset = TimeSpan.Zero; // If offset is invalid, set it to zero
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime currentDateTime = DateTime.UtcNow;
|
||||||
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
||||||
DateTime endDateTime = currentDateTime;
|
DateTime endDateTime = currentDateTime;
|
||||||
int trendChartTicks = 0;
|
|
||||||
|
// 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))
|
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();
|
// Use binary search to find the range of items that match the condition
|
||||||
if (tickRange.Count > 0)
|
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 = tickRange.First();
|
MarketTrendChange mtc = marketTrendChangeSummaries[index];
|
||||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
|
||||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
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")) + "}";
|
// Adjust tickTime to the desired timezone before converting to string
|
||||||
trendChartTicks++;
|
DateTime adjustedTickTime = tickTime.Add(isNegative ? -offset : offset);
|
||||||
|
trendValues.Add("{ x: new Date('" + adjustedTickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add most recent tick
|
// Add most recent tick
|
||||||
List<MarketTrendChange> latestTickRange = marketTrendChangeSummaries.OrderByDescending(m => m.TrendDateTime).ToList();
|
MarketTrendChange latestMtc = marketTrendChangeSummaries.Last();
|
||||||
if (latestTickRange.Count > 0)
|
if (Double.IsInfinity(latestMtc.TrendChange)) latestMtc.TrendChange = 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")) + "}";
|
// 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) + "}");
|
||||||
TrendChartDataJSON += "]";
|
|
||||||
TrendChartDataJSON += "}";
|
|
||||||
|
|
||||||
|
// Use cached splitCamelCaseName
|
||||||
|
trendChartData.Add("{ key: '" + splitCamelCaseName + "', color: '" + lineColor + "', values: [" + string.Join(",\n", trendValues) + "] }");
|
||||||
mtIndex++;
|
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 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="m-t-0 header-title text-left">Total Account Value: <text class="text-autocolor"> @totalCurrentValueString @Model.Summary.MainMarket </text> <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is based on your sales history, entries on the Transactions page and any currently held positions."></i></small></th>
|
<th class="text-right">Starting Value: <text class="text-autocolor"> @Model.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>
|
||||||
<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>
|
|
||||||
</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,54 +217,48 @@
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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);
|
|
||||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
|
||||||
double salesDateAVGDailyGain = 0;
|
|
||||||
double monthDailyProfit = 0;
|
|
||||||
int days = 0;
|
|
||||||
for (int d = 1; d <= DateTime.DaysInMonth(salesMonthDate.Year, salesMonthDate.Month); d++) {
|
|
||||||
DateTime monthDay = salesMonthDate.AddDays(-salesMonthDate.Day + d);
|
|
||||||
if (monthDay <= Model.DateTimeNow) {
|
|
||||||
days++;
|
|
||||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> monthDaySales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date == monthDay.Date);
|
|
||||||
double monthDayProfit = 0;
|
|
||||||
monthDayProfit = monthDaySales.Sum(sl => sl.Profit);
|
|
||||||
double monthDayStartBalance = Model.PTData.GetSnapshotBalance(monthDay);
|
|
||||||
monthDailyProfit += Math.Round(monthDayProfit / monthDayStartBalance * 100, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
salesDateAVGDailyGain = Math.Round(monthDailyProfit / days, 2);
|
|
||||||
<tr>
|
<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>@monthName</td>
|
||||||
<td class="text-right text-autocolor">@salesMonthSales.Count</td>
|
<td class="text-right text-autocolor">@sales</td>
|
||||||
<td class="text-right text-autocolor">@salesDateProfit.ToString("#,#0.00000000", 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">@Html.Raw(Model.MainFiatCurrencySymbol + salesDateProfitFiat.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))</td>
|
<td class="text-right text-autocolor">@profitFiat</td>
|
||||||
<td class="text-right text-autocolor">@salesDateGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
<td class="text-right text-autocolor">@growth %</td>
|
||||||
<td class="text-right text-autocolor">@salesDateAVGDailyGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
|
||||||
</tr>
|
</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;
|
|
||||||
/**/
|
|
||||||
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 lineChart = nv.models.lineChart();
|
|
||||||
var height = 300;
|
|
||||||
/**/
|
|
||||||
var chartData = @Html.Raw(Model.ProfitChartDataJSON);
|
|
||||||
/**/
|
|
||||||
lineChart.useInteractiveGuideline(true);
|
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
|
||||||
lineChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
|
|
||||||
d3.select('.profit-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
|
||||||
nv.utils.windowResize(lineChart.update);
|
|
||||||
return lineChart;
|
|
||||||
});
|
|
||||||
|
|
||||||
nv.addGraph(function () {
|
|
||||||
var lineChart = nv.models.lineChart();
|
|
||||||
var height = 400;
|
|
||||||
/**/
|
|
||||||
var chartData = @Html.Raw(Model.BalanceChartDataJSON);
|
|
||||||
/**/
|
|
||||||
lineChart.useInteractiveGuideline(true);
|
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
|
||||||
lineChart.yAxis.axisLabel('Profit').tickFormat(d3.format(',.2f'));
|
|
||||||
d3.select('.balance-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
|
||||||
nv.utils.windowResize(lineChart.update);
|
|
||||||
return lineChart;
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#salesList").on("show.bs.modal", function (e) {
|
|
||||||
$(this).find(".modal-content").html('<i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>');
|
|
||||||
var link = $(e.relatedTarget);
|
|
||||||
$(this).find(".modal-content").load(link.attr("href"), function () {
|
|
||||||
$('.text-autocolor').autocolor(false);
|
$('.text-autocolor').autocolor(false);
|
||||||
|
|
||||||
|
var salesChart; // Keep a reference to the chart
|
||||||
|
var salesData; // Keep a reference to the data
|
||||||
|
|
||||||
|
@if (!Model.SalesChartDataJSON.Equals("")) {
|
||||||
|
<text>
|
||||||
|
nv.addGraph(function () {
|
||||||
|
salesChart = nv.models.multiBarChart();
|
||||||
|
var height = 300;
|
||||||
|
salesChart.groupSpacing(0.5);
|
||||||
|
salesChart.showControls(false);
|
||||||
|
//salesChart.useInteractiveGuideline(true);
|
||||||
|
salesChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||||
|
salesChart.yAxis.axisLabel('').tickFormat(d3.format(',.2f'));
|
||||||
|
|
||||||
|
salesData = @Html.Raw(Model.SalesChartDataJSON);
|
||||||
|
|
||||||
|
d3.select('.sales-chart svg')
|
||||||
|
.datum(salesData)
|
||||||
|
.transition().duration(0)
|
||||||
|
.call(salesChart);
|
||||||
|
|
||||||
|
// Add mouseleave, and mousemove event listeners to hide tooltip
|
||||||
|
d3.select('.sales-chart').on('mouseleave', function() {
|
||||||
|
d3.select('.nvtooltip').style('opacity', 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
d3.select('body').on('mousemove', function() {
|
||||||
|
var chartBounds = d3.select('.sales-chart')[0][0].getBoundingClientRect();
|
||||||
|
var mouseX = d3.event.clientX;
|
||||||
|
var mouseY = d3.event.clientY;
|
||||||
|
|
||||||
|
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
|
||||||
|
d3.select('.nvtooltip').style('opacity', 0);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
nv.utils.windowResize(salesChart.update);
|
||||||
|
return salesChart;
|
||||||
|
});
|
||||||
|
</text>
|
||||||
|
}
|
||||||
})(jQuery);
|
})(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('+', '-');
|
||||||
|
|
||||||
|
if (!TimeSpan.TryParse(offsetWithoutSign, out offset))
|
||||||
|
{
|
||||||
|
offset = TimeSpan.Zero; // If offset is invalid, set it to zero
|
||||||
}
|
}
|
||||||
TopMarkets = new SortedDictionary<string, double>(topMarketsDic).OrderByDescending(m => m.Value).Take(PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets);
|
|
||||||
|
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 + "',";
|
|
||||||
BalanceChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',";
|
|
||||||
BalanceChartDataJSON += "values: [" + balancePerDayJSON + "]";
|
|
||||||
BalanceChartDataJSON += "}";
|
|
||||||
BalanceChartDataJSON += "]";
|
|
||||||
|
|
||||||
for (DateTime salesDate = DateTimeNow.DateTime.Date; salesDate >= MinSellLogDate; salesDate = salesDate.AddDays(-1))
|
// Parse dates once and adjust them to the local timezone
|
||||||
|
Dictionary<DateTime, DailyStatsData> salesCountByDate = PTData.DailyStats
|
||||||
|
.ToDictionary(
|
||||||
|
data => DateTime.ParseExact(data.Date, "d-M-yyyy", CultureInfo.InvariantCulture),
|
||||||
|
data => data
|
||||||
|
);
|
||||||
|
|
||||||
|
DateTime earliestDataDate = salesCountByDate.Keys.Min();
|
||||||
|
DateTime startDate = earliestDataDate;
|
||||||
|
|
||||||
|
// Calculate the total days of data available
|
||||||
|
SalesDays = (endDate - startDate).Days;
|
||||||
|
int counter = 0;
|
||||||
|
for (DateTime date = startDate; date <= endDate && counter < 30; date = date.AddDays(1)) // Check the counter
|
||||||
{
|
{
|
||||||
List<SellLogData> salesDateSales = PTData.SellLog.FindAll(sl => sl.SoldDate.Date == salesDate);
|
if (salesCountByDate.TryGetValue(date, out DailyStatsData dailyStatsData))
|
||||||
double salesDateProfit;
|
|
||||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
|
||||||
double salesDateStartBalance = PTData.GetSnapshotBalance(salesDate);
|
|
||||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
|
||||||
DailyGains.Add(salesDate, salesDateGain);
|
|
||||||
}
|
|
||||||
DateTime 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);
|
buysPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = Convert.ToInt32(dailyStatsData.TotalBuys) });
|
||||||
double salesDateProfit;
|
salesPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = Convert.ToInt32(dailyStatsData.TotalSales) });
|
||||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
|
||||||
double salesDateStartBalance = PTData.GetSnapshotBalance(salesMonthDate);
|
|
||||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
|
||||||
MonthlyGains.Add(salesMonthDate, salesDateGain);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
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,6 +247,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@* <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">
|
<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">
|
||||||
|
@ -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,90 +99,32 @@
|
||||||
</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>
|
||||||
|
|
||||||
<div class="card-box">
|
|
||||||
<h4 class="m-t-0 header-title">Active Sell Strategies</h4>
|
|
||||||
|
|
||||||
<table class="table table-striped table-sm">
|
|
||||||
<tbody>
|
|
||||||
@if (Model.Summary.SellStrategies.Count == 0) {
|
|
||||||
<tr>
|
|
||||||
<td>Sell Strat.</td>
|
|
||||||
<td class="text-right">@Model.Summary.SellStrategy</td>
|
|
||||||
<td>Sell Value</td>
|
|
||||||
<td class="text-right">@Model.Summary.SellValue.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
|
||||||
</tr>
|
|
||||||
} else {
|
|
||||||
char sellStrategyIndex = 'A';
|
|
||||||
foreach (Core.Main.DataObjects.PTMagicData.StrategySummary sellStrategy in Model.Summary.SellStrategies) {
|
|
||||||
<tr>
|
|
||||||
<td>Sell Strat. @sellStrategyIndex</td>
|
|
||||||
<td class="text-right">@sellStrategy.Name</td>
|
|
||||||
<td>Sell Value @sellStrategyIndex</td>
|
|
||||||
<td class="text-right">@sellStrategy.Value.ToString(new System.Globalization.CultureInfo("en-US"))</td>
|
|
||||||
</tr>
|
|
||||||
sellStrategyIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-7">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
|
<h4 class="m-t-0 header-title">Settings Active Time (Last 24h)</h4>
|
||||||
|
|
||||||
<div id="gsChart24h">
|
<div id="gsChart24h">
|
||||||
<svg style="height:300px;width:100%"></svg>
|
<svg style="height:200px;width:100%"></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
<h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4>
|
<h4 class="m-t-0 header-title">Settings Active Time (Last 3 days)</h4>
|
||||||
|
|
||||||
<div id="gsChart3d">
|
<div id="gsChart3d">
|
||||||
<svg style="height:300px;width:100%"></svg>
|
<svg style="height:200px;width:100%"></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="card-box">
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card-box">
|
||||||
<h4 class="m-t-0 header-title">Global Settings Log</h4>
|
<h4 class="m-t-0 header-title">Global Settings Log</h4>
|
||||||
|
|
||||||
<table class="table table-striped table-sm">
|
<table class="table table-striped table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -216,9 +156,6 @@
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</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,27 +64,31 @@
|
||||||
</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;
|
||||||
|
@ -92,8 +99,12 @@
|
||||||
} 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>
|
<tr>
|
||||||
<td>@Core.Helper.SystemHelper.SplitCamelCase(marketTrend.Name)</td>
|
<td>@splitCamelCaseName</td> <!-- Use the cached value here -->
|
||||||
<td class="text-right">@marketCountString</td>
|
<td class="text-right">@marketCountString</td>
|
||||||
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td>
|
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td>
|
||||||
@if (marketTrend.TrendThreshold == 0)
|
@if (marketTrend.TrendThreshold == 0)
|
||||||
|
@ -102,9 +113,9 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<td class="text-right">@marketTrend.TrendThreshold</td>
|
<td class="text-right">@marketTrend.TrendThreshold %</td>
|
||||||
}
|
}
|
||||||
<td class="text-right text-autocolor">@trendChangeOutput%</td>
|
<td class="text-right text-autocolor" style="font-weight:bold;">@trendChangeOutput %</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,92 +124,153 @@
|
||||||
</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);
|
|
||||||
|
|
||||||
double last7DaysProfit = 0;
|
var yesterdaysSales = overviewStats.SalesYesterday;
|
||||||
last7DaysProfit = Model.PTData.SellLogLast7Days.Sum(s => s.Profit);
|
var yesterdaysProfit = overviewStats.ProfitYesterday;
|
||||||
double last7DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-7));
|
var yesterdaysFunding = overviewStats.FundingYesterday;
|
||||||
double last7DaysProfitFiat = Math.Round(last7DaysProfit * Model.Summary.MainMarketPrice, 2);
|
var yesterdaysPercentGain = overviewStats.ProfitPercYesterday + Model.PTData.Stats.TotalFundingPercYesterday;
|
||||||
double last7DaysPercentGain = Math.Round(last7DaysProfit / last7DaysStartBalance * 100, 2);
|
|
||||||
|
var last7DaysSales = overviewStats.SalesWeek;
|
||||||
|
var last7DaysProfit = overviewStats.ProfitWeek;
|
||||||
|
var last7DaysFunding = overviewStats.FundingWeek;
|
||||||
|
var last7DaysPercentGain = overviewStats.ProfitPercWeek + Model.PTData.Stats.TotalFundingPercWeek;
|
||||||
|
|
||||||
|
var thisMonthSales = overviewStats.SalesThisMonth;
|
||||||
|
var thisMonthProfit = overviewStats.ProfitThisMonth;
|
||||||
|
var thisMonthFunding = overviewStats.FundingThisMonth;
|
||||||
|
var thisMonthPercentGain = avgGrowthThisMonth;
|
||||||
|
|
||||||
|
var lastMonthSales = overviewStats.SalesLastMonth;
|
||||||
|
var lastMonthProfit = overviewStats.ProfitLastMonth;
|
||||||
|
var lastMonthFunding = overviewStats.FundingLastMonth;
|
||||||
|
var lastMonthPercentGain = avgGrowthLastMonth;
|
||||||
|
|
||||||
|
var totalSales = overviewStats.TotalSales;
|
||||||
|
var totalProfit = overviewStats.TotalProfit;
|
||||||
|
var totalFunding = overviewStats.FundingTotal;
|
||||||
|
var totalPercentGain = overviewStats.TotalProfitPerc + Model.PTData.Stats.TotalFundingPerc;
|
||||||
|
|
||||||
|
double todaysProfitFiat = Math.Round((todaysProfit + todaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||||
|
double yesterdaysProfitFiat = Math.Round((yesterdaysProfit + yesterdaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||||
|
double last7DaysProfitFiat = Math.Round((last7DaysProfit + last7DaysFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||||
|
double thisMonthProfitFiat = Math.Round((thisMonthProfit + thisMonthFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||||
|
double lastMonthProfitFiat = Math.Round((lastMonthProfit + lastMonthFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||||
|
double totalProfitFiat = Math.Round((totalProfit + totalFunding) * Model.PTData.Misc.FiatConversionRate, 2);
|
||||||
|
|
||||||
|
bool futuresFunding = Model.PropertiesData.IsLeverageExchange;
|
||||||
|
|
||||||
double last30DaysProfit = 0;
|
|
||||||
last30DaysProfit = Model.PTData.SellLogLast30Days.Sum(s => s.Profit);
|
|
||||||
double last30DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-30));
|
|
||||||
double last30DaysProfitFiat = Math.Round(last30DaysProfit * Model.Summary.MainMarketPrice, 2);
|
|
||||||
double last30DaysPercentGain = Math.Round(last30DaysProfit / last30DaysStartBalance * 100, 2);
|
|
||||||
}
|
}
|
||||||
<table class="table table-sm">
|
<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("")) {
|
@if (!Model.AssetDistributionData.Equals("")) {
|
||||||
<text>
|
<text>
|
||||||
nv.addGraph(function() {
|
nv.addGraph(function() {
|
||||||
var chart = nv.models.pieChart()
|
assetDistributionChart = nv.models.pieChart()
|
||||||
.x(function(d) { return d.label })
|
.x(function(d) { return d.label })
|
||||||
.y(function(d) { return d.value })
|
.y(function(d) { return d.value })
|
||||||
.showLabels(true) //Display pie labels
|
.showLabels(true)
|
||||||
.labelThreshold(.1) //Configure the minimum slice size for labels to show up
|
.labelThreshold(.1)
|
||||||
.labelType("percent") //Configure what type of data to show in the label. Can be "key", "value" or "percent"
|
.labelType("percent")
|
||||||
.donut(true) //Turn on Donut mode. Makes pie chart look tasty!
|
.donut(true)
|
||||||
.donutRatio(0.3) //Configure how big you want the donut hole size to be.
|
.donutRatio(0.3);
|
||||||
;
|
|
||||||
|
assetDistributionData = @Html.Raw(Model.AssetDistributionData);
|
||||||
|
|
||||||
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;
|
|
||||||
|
// 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>
|
</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);
|
||||||
});
|
});
|
||||||
</text>
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
});
|
||||||
<text>
|
nv.utils.windowResize(trendChart.update);
|
||||||
nv.addGraph(function () {
|
return trendChart;
|
||||||
var lineChart = nv.models.lineChart();
|
|
||||||
var height = 300;
|
|
||||||
var chartData = @Html.Raw(Model.ProfitChartDataJSON);
|
|
||||||
lineChart.useInteractiveGuideline(true);
|
|
||||||
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%Y/%m/%d')(new Date(d)); });
|
|
||||||
lineChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
|
|
||||||
d3.select('.profit-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
|
|
||||||
//nv.utils.windowResize(lineChart.update); v1.3.0 => Removed this line to prevent memory leak
|
|
||||||
return lineChart;
|
|
||||||
});
|
});
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function ($) {
|
||||||
|
'use strict';
|
||||||
|
$('[role="tooltip"]').remove();
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
$('.text-autocolor').autocolor(false);
|
||||||
|
|
||||||
|
var profitChart; // Keep a reference to the chart
|
||||||
|
var profitData; // Keep a reference to the data
|
||||||
|
|
||||||
|
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||||
|
<text>
|
||||||
|
nv.addGraph(function () {
|
||||||
|
profitChart = nv.models.lineChart();
|
||||||
|
var height = 300;
|
||||||
|
profitChart.useInteractiveGuideline(true);
|
||||||
|
profitChart.xAxis.tickFormat(function (d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||||
|
profitChart.yAxis.axisLabel('Daily Profit').tickFormat(d3.format(',.2f'));
|
||||||
|
|
||||||
|
profitData = @Html.Raw(Model.ProfitChartDataJSON);
|
||||||
|
|
||||||
|
d3.select('.profit-chart svg')
|
||||||
|
.datum(profitData)
|
||||||
|
.transition().duration(0)
|
||||||
|
.call(profitChart);
|
||||||
|
|
||||||
|
// Add mouseleave, and mousemove event listeners to hide tooltip
|
||||||
|
d3.select('.profit-chart').on('mouseleave', function() {
|
||||||
|
d3.select('.nvtooltip').style('opacity', 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
d3.select('body').on('mousemove', function() {
|
||||||
|
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
|
||||||
|
var mouseX = d3.event.clientX;
|
||||||
|
var mouseY = d3.event.clientY;
|
||||||
|
|
||||||
|
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
|
||||||
|
d3.select('.nvtooltip').style('opacity', 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nv.utils.windowResize(profitChart.update);
|
||||||
|
return profitChart;
|
||||||
|
});
|
||||||
|
</text>
|
||||||
|
}
|
||||||
|
})(jQuery);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
var originalLeave = $.fn.tooltip.Constructor.prototype.leave;
|
||||||
|
$.fn.tooltip.Constructor.prototype.leave = function(obj){
|
||||||
|
var self = obj instanceof this.constructor ?
|
||||||
|
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type);
|
||||||
|
var container, timeout;
|
||||||
|
|
||||||
|
originalLeave.call(this, obj);
|
||||||
|
|
||||||
|
if(obj.currentTarget) {
|
||||||
|
container = $(obj.currentTarget).siblings('.tooltip');
|
||||||
|
timeout = self.timeout;
|
||||||
|
container.one('mouseenter', function(){
|
||||||
|
//We entered the actual tooltip – call off the dogs
|
||||||
|
clearTimeout(timeout);
|
||||||
|
//Let's monitor tooltip content instead
|
||||||
|
container.one('mouseleave', function(){
|
||||||
|
$.fn.tooltip.Constructor.prototype.leave.call(self, self);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -6,14 +6,20 @@ using Core.Main;
|
||||||
using Core.Helper;
|
using Core.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,27 +63,24 @@ 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()
|
||||||
{
|
{
|
||||||
|
List<string> trendChartData = new List<string>();
|
||||||
if (MarketTrends.Count > 0)
|
if (MarketTrends.Count > 0)
|
||||||
{
|
{
|
||||||
TrendChartDataJSON = "[";
|
|
||||||
int mtIndex = 0;
|
int mtIndex = 0;
|
||||||
foreach (MarketTrend mt in MarketTrends)
|
foreach (MarketTrend mt in MarketTrends)
|
||||||
{
|
{
|
||||||
if (mt.DisplayGraph)
|
if (mt.DisplayGraph)
|
||||||
{
|
{
|
||||||
string lineColor = "";
|
string lineColor = mtIndex < Constants.ChartLineColors.Length
|
||||||
if (mtIndex < Constants.ChartLineColors.Length)
|
? Constants.ChartLineColors[mtIndex]
|
||||||
{
|
: Constants.ChartLineColors[mtIndex - 20];
|
||||||
lineColor = Constants.ChartLineColors[mtIndex];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lineColor = Constants.ChartLineColors[mtIndex - 20];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||||
{
|
{
|
||||||
|
@ -79,85 +88,141 @@ namespace Monitor.Pages
|
||||||
|
|
||||||
if (marketTrendChangeSummaries.Count > 0)
|
if (marketTrendChangeSummaries.Count > 0)
|
||||||
{
|
{
|
||||||
if (!TrendChartDataJSON.Equals("[")) TrendChartDataJSON += ",";
|
List<string> trendValues = new List<string>();
|
||||||
|
|
||||||
TrendChartDataJSON += "{";
|
// Sort marketTrendChangeSummaries by TrendDateTime
|
||||||
TrendChartDataJSON += "key: '" + SystemHelper.SplitCamelCase(mt.Name) + "',";
|
marketTrendChangeSummaries = marketTrendChangeSummaries.OrderBy(m => m.TrendDateTime).ToList();
|
||||||
TrendChartDataJSON += "color: '" + lineColor + "',";
|
|
||||||
TrendChartDataJSON += "values: [";
|
|
||||||
|
|
||||||
// Get trend ticks for chart
|
// Get trend ticks for chart
|
||||||
DateTime currentDateTime = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, DateTime.UtcNow.Hour, 0, 0);
|
TimeSpan offset;
|
||||||
|
bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-");
|
||||||
|
string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-');
|
||||||
|
|
||||||
|
if (!TimeSpan.TryParse(offsetWithoutSign, out offset))
|
||||||
|
{
|
||||||
|
offset = TimeSpan.Zero; // If offset is invalid, set it to zero
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime currentDateTime = DateTime.UtcNow;
|
||||||
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
||||||
DateTime endDateTime = currentDateTime;
|
DateTime endDateTime = currentDateTime;
|
||||||
int trendChartTicks = 0;
|
|
||||||
|
// 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))
|
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();
|
// Use binary search to find the range of items that match the condition
|
||||||
if (tickRange.Count > 0)
|
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 = tickRange.First();
|
MarketTrendChange mtc = marketTrendChangeSummaries[index];
|
||||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
|
||||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
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")) + "}";
|
// Adjust tickTime to the desired timezone before converting to string
|
||||||
trendChartTicks++;
|
DateTime adjustedTickTime = tickTime.Add(isNegative ? -offset : offset);
|
||||||
|
trendValues.Add("{ x: new Date('" + adjustedTickTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add most recent tick
|
// Add most recent tick
|
||||||
List<MarketTrendChange> latestTickRange = marketTrendChangeSummaries.OrderByDescending(m => m.TrendDateTime).ToList();
|
MarketTrendChange latestMtc = marketTrendChangeSummaries.Last();
|
||||||
if (latestTickRange.Count > 0)
|
if (Double.IsInfinity(latestMtc.TrendChange)) latestMtc.TrendChange = 0;
|
||||||
{
|
|
||||||
MarketTrendChange mtc = latestTickRange.First();
|
// Adjust latestMtc.TrendDateTime to the desired timezone before converting to string
|
||||||
if (trendChartTicks > 0) TrendChartDataJSON += ",\n";
|
DateTime adjustedLatestTrendDateTime = latestMtc.TrendDateTime.Add(isNegative ? -offset : offset);
|
||||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
trendValues.Add("{ x: new Date('" + adjustedLatestTrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + latestMtc.TrendChange.ToString("0.00", CultureInfo.InvariantCulture) + "}");
|
||||||
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")) + "}";
|
|
||||||
}
|
// Use cached splitCamelCaseName
|
||||||
TrendChartDataJSON += "]";
|
trendChartData.Add("{ key: '" + splitCamelCaseName + "', color: '" + lineColor + "', values: [" + string.Join(",\n", trendValues) + "] }");
|
||||||
TrendChartDataJSON += "}";
|
|
||||||
mtIndex++;
|
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.SellLog.Count > 0)
|
if (PTData.DailyPNL.Count > 0)
|
||||||
{
|
{
|
||||||
DateTime minSellLogDate = PTData.SellLog.OrderBy(sl => sl.SoldDate).First().SoldDate.Date;
|
// Get timezone offset
|
||||||
DateTime graphStartDate = DateTime.UtcNow.Date.AddDays(-30);
|
TimeSpan offset;
|
||||||
if (minSellLogDate > graphStartDate)
|
bool isNegative = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.StartsWith("-");
|
||||||
|
string offsetWithoutSign = PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset.TrimStart('+', '-');
|
||||||
|
|
||||||
|
if (!TimeSpan.TryParse(offsetWithoutSign, out offset))
|
||||||
{
|
{
|
||||||
graphStartDate = minSellLogDate;
|
offset = TimeSpan.Zero; // If offset is invalid, set it to zero
|
||||||
}
|
}
|
||||||
for (DateTime salesDate = graphStartDate; salesDate <= DateTime.UtcNow.Date; salesDate = salesDate.AddDays(1))
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
if (tradeDayIndex > 0)
|
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))
|
||||||
{
|
{
|
||||||
profitPerDayJSON += ",\n";
|
// Use the dictionary to find the DailyPNLData for the date
|
||||||
|
if (dailyPNLByDate.TryGetValue(date, out DailyPNLData dailyPNL))
|
||||||
|
{
|
||||||
|
if (isFirstDay)
|
||||||
|
{
|
||||||
|
isFirstDay = false;
|
||||||
}
|
}
|
||||||
int trades = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate).Count;
|
else
|
||||||
double profit = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate).Sum(t => t.Profit);
|
{
|
||||||
double profitFiat = Math.Round(profit * Summary.MainMarketPrice, 2);
|
// Calculate the profit for the current day
|
||||||
profitPerDayJSON += "{x: new Date('" + salesDate.ToString("yyyy-MM-dd") + "'), y: " + profitFiat.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
double profitFiat = Math.Round(dailyPNL.CumulativeProfitCurrency - previousDayCumulativeProfit, 2);
|
||||||
tradeDayIndex++;
|
|
||||||
|
// Add the data point to the list
|
||||||
|
profitPerDayList.Add(new { x = new DateTimeOffset(date).ToUnixTimeMilliseconds(), y = profitFiat });
|
||||||
}
|
}
|
||||||
ProfitChartDataJSON = "[";
|
previousDayCumulativeProfit = dailyPNL.CumulativeProfitCurrency;
|
||||||
ProfitChartDataJSON += "{";
|
|
||||||
ProfitChartDataJSON += "key: 'Profit in " + Summary.MainFiatCurrency + "',";
|
|
||||||
ProfitChartDataJSON += "color: '" + Constants.ChartLineColors[1] + "',";
|
|
||||||
ProfitChartDataJSON += "values: [" + profitPerDayJSON + "]";
|
|
||||||
ProfitChartDataJSON += "}";
|
|
||||||
ProfitChartDataJSON += "]";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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