PTMagic/Core/DataObjects/ProfitTrailerData.cs

1023 lines
41 KiB
C#
Raw Normal View History

2018-05-22 10:11:50 +02:00
using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
2019-01-07 15:33:02 +01:00
using System.Net;
using System.Threading.Tasks;
using System.Diagnostics;
2024-01-10 16:58:09 +01:00
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
2018-05-22 10:11:50 +02:00
using Core.Main.DataObjects.PTMagicData;
namespace Core.Main.DataObjects
{
2018-05-22 10:11:50 +02:00
public class ProfitTrailerData
{
2024-01-15 15:12:46 +01:00
private MiscData _misc = null;
2024-01-07 22:53:49 +01:00
private PropertiesData _properties = null;
private StatsData _stats = null;
private List<DailyPNLData> _dailyPNL = new List<DailyPNLData>();
2024-01-16 17:56:52 +01:00
private List<DailyTCVData> _dailyTCV = new List<DailyTCVData>();
2024-01-15 15:12:46 +01:00
private List<MonthlyStatsData> _monthlyStats = new List<MonthlyStatsData>();
2024-01-17 18:13:09 +01:00
private List<ProfitablePairsData> _profitablePairs = new List<ProfitablePairsData>();
2024-01-19 00:11:16 +01:00
private List<DailyStatsData> _dailyStats = new List<DailyStatsData>();
2024-01-10 16:58:09 +01:00
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; }
}
2018-05-22 10:11:50 +02:00
private List<SellLogData> _sellLog = new List<SellLogData>();
private List<DCALogData> _dcaLog = new List<DCALogData>();
private List<BuyLogData> _buyLog = new List<BuyLogData>();
private string _ptmBasePath = "";
private PTMagicConfiguration _systemConfiguration = null;
private TransactionData _transactionData = null;
2024-01-07 22:53:49 +01:00
private DateTime _dailyPNLRefresh = DateTime.UtcNow;
2024-01-16 17:56:52 +01:00
private DateTime _dailyTCVRefresh = DateTime.UtcNow;
2024-01-15 15:12:46 +01:00
private DateTime _monthlyStatsRefresh = DateTime.UtcNow;
2024-01-07 22:53:49 +01:00
private DateTime _statsRefresh = DateTime.UtcNow;
private DateTime _buyLogRefresh = DateTime.UtcNow;
private DateTime _sellLogRefresh = DateTime.UtcNow;
private DateTime _dcaLogRefresh = DateTime.UtcNow;
2024-01-15 15:12:46 +01:00
private DateTime _miscRefresh = DateTime.UtcNow;
2024-01-16 17:56:52 +01:00
private DateTime _propertiesRefresh = DateTime.UtcNow;
2024-01-19 00:11:16 +01:00
private DateTime _profitablePairsRefresh = DateTime.UtcNow;
private DateTime _dailyStatsRefresh = DateTime.UtcNow;
2024-01-16 17:56:52 +01:00
private volatile object _dailyPNLLock = new object();
private volatile object _dailyTCVLock = new object();
2024-01-15 15:12:46 +01:00
private volatile object _monthlyStatsLock = new object();
2024-01-07 22:53:49 +01:00
private volatile object _statsLock = new object();
private volatile object _buyLock = new object();
private volatile object _sellLock = new object();
private volatile object _dcaLock = new object();
2024-01-15 15:12:46 +01:00
private volatile object _miscLock = new object();
2024-01-17 18:13:09 +01:00
private volatile object _propertiesLock = new object();
2024-01-19 00:11:16 +01:00
private volatile object _profitablePairsLock = new object();
private volatile object _dailyStatsLock = new object();
private TimeSpan? _offsetTimeSpan = null;
public void DoLog(string message)
{
// Implement your logging logic here
Console.WriteLine(message);
}
2019-10-19 12:14:40 +02:00
// Constructor
2019-01-07 15:33:02 +01:00
public ProfitTrailerData(PTMagicConfiguration systemConfiguration)
2018-12-31 04:26:45 +01:00
{
2019-01-13 13:43:47 +01:00
_systemConfiguration = systemConfiguration;
2019-10-19 12:14:40 +02:00
}
// Get a time span for the UTC offset from the settings
private TimeSpan OffsetTimeSpan
{
get
{
if (!_offsetTimeSpan.HasValue)
{
// Get offset for settings.
_offsetTimeSpan = TimeSpan.Parse(_systemConfiguration.GeneralSettings.Application.TimezoneOffset.Replace("+", ""));
}
2019-01-13 13:43:47 +01:00
2019-10-19 12:14:40 +02:00
return _offsetTimeSpan.Value;
}
}
// Get the time with the settings UTC offset applied
private DateTimeOffset LocalizedTime
{
get
{
return DateTimeOffset.UtcNow.ToOffset(OffsetTimeSpan);
}
2018-05-22 10:11:50 +02:00
}
2024-01-15 15:12:46 +01:00
public MiscData Misc
{
get
{
2024-01-15 15:12:46 +01:00
if (_misc == null || (DateTime.UtcNow > _miscRefresh))
{
2024-01-15 15:12:46 +01:00
lock (_miscLock)
{
// Thread double locking
2024-01-15 15:12:46 +01:00
if (_misc == null || (DateTime.UtcNow > _miscRefresh))
{
2024-01-15 15:12:46 +01:00
_misc = BuildMiscData(GetDataFromProfitTrailer("api/v2/data/misc"));
_miscRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
}
}
}
2024-01-07 22:53:49 +01:00
2024-01-15 15:12:46 +01:00
return _misc;
}
}
2024-01-15 15:12:46 +01:00
private MiscData BuildMiscData(dynamic PTData)
2024-01-07 22:53:49 +01:00
{
2024-01-15 15:12:46 +01:00
return new MiscData()
2024-01-07 22:53:49 +01:00
{
Market = PTData.market,
FiatConversionRate = PTData.priceDataFiatConversionRate,
Balance = PTData.realBalance,
PairsValue = PTData.totalPairsCurrentValue,
DCAValue = PTData.totalDCACurrentValue,
PendingValue = PTData.totalPendingCurrentValue,
DustValue = PTData.totalDustCurrentValue,
StartBalance = PTData.startBalance,
2024-01-15 15:12:46 +01:00
TotalCurrentValue = PTData.totalCurrentValue,
TimeZoneOffset = PTData.timeZoneOffset,
2024-01-07 22:53:49 +01:00
};
}
2024-01-19 00:11:16 +01:00
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"],
};
}
2024-01-07 22:53:49 +01:00
public PropertiesData Properties
2020-07-19 13:07:52 +02:00
{
get
{
if (_properties == null || (DateTime.UtcNow > _propertiesRefresh))
{
lock (_propertiesLock)
{
// Thread double locking
if (_properties == null || (DateTime.UtcNow > _propertiesRefresh))
{
_properties = BuildProptertiesData(GetDataFromProfitTrailer("api/v2/data/properties"));
2020-07-19 13:07:52 +02:00
_propertiesRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
}
}
}
return _properties;
}
}
2024-01-07 22:53:49 +01:00
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
};
}
2024-01-10 16:58:09 +01:00
2024-01-07 22:53:49 +01:00
public StatsData Stats
{
get
{
if (_stats == null || DateTime.UtcNow > _statsRefresh)
{
lock (_statsLock)
{
if (_stats == null || DateTime.UtcNow > _statsRefresh)
{
2024-01-10 16:58:09 +01:00
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
using (var reader = new StreamReader(stream))
using (var jsonReader = new JsonTextReader(reader))
{
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.PropertyName && (string)jsonReader.Value == "basic")
{
jsonReader.Read(); // Move to the value of the "basic" property
JObject basicSection = JObject.Load(jsonReader);
_stats = BuildStatsData(basicSection);
_statsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
break;
}
}
}
}
}
}
return _stats;
}
}
2024-01-07 22:53:49 +01:00
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"],
2024-01-16 17:56:52 +01:00
FundingTotal = statsDataJson["totalFunding"],
TotalFundingPerc = statsDataJson["totalFundingPerc"],
TotalFundingPercYesterday = statsDataJson["totalFundingPercYesterday"],
TotalFundingPercWeek = statsDataJson["totalFundingPercWeekPerc"],
TotalFundingPercToday = statsDataJson["totalFundingPercTodayPerc"]
2024-01-07 22:53:49 +01:00
};
}
public List<DailyPNLData> DailyPNL
2024-01-15 15:12:46 +01:00
{
get
{
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
{
lock (_dailyPNLLock)
{
if (_dailyPNL == null || DateTime.UtcNow > _dailyPNLRefresh)
{
using (var stream = GetDataFromProfitTrailerAsStream("/api/v2/data/stats"))
using (var reader = new StreamReader(stream))
using (var jsonReader = new JsonTextReader(reader))
{
JObject basicSection = null;
JObject extraSection = null;
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.PropertyName)
{
if ((string)jsonReader.Value == "basic")
{
jsonReader.Read(); // Move to the value of the "basic" property
basicSection = JObject.Load(jsonReader);
}
else if ((string)jsonReader.Value == "extra")
{
jsonReader.Read(); // Move to the value of the "extra" property
extraSection = JObject.Load(jsonReader);
}
}
if (basicSection != null && extraSection != null)
{
break;
}
}
if (basicSection != null &&
((_totalProfit == null ||
!Decimal.Equals(_totalProfit.Value, basicSection["totalProfit"].Value<decimal>())) ||
(_totalSales == null ||
!Decimal.Equals(_totalSales.Value, basicSection["totalSales"].Value<decimal>()))))
{
_totalProfit = basicSection["totalProfit"].Value<decimal>();
_totalSales = basicSection["totalSales"].Value<decimal>();
if (extraSection != null)
{
JArray dailyPNLSection = (JArray)extraSection["dailyPNLStats"];
_dailyPNL = dailyPNLSection.Select(j => BuildDailyPNLData(j as JObject)).ToList();
_dailyPNLRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
}
}
}
}
}
}
return _dailyPNL;
}
}
private DailyPNLData BuildDailyPNLData(dynamic dailyPNLDataJson)
{
return new DailyPNLData()
{
Date = dailyPNLDataJson["date"],
CumulativeProfitCurrency = dailyPNLDataJson["cumulativeProfitCurrency"],
Order = dailyPNLDataJson["order"],
};
}
2024-01-17 18:13:09 +01:00
public List<ProfitablePairsData> ProfitablePairs
{
get
{
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);
}
}
if (basicSection != null && extraSection != null)
{
break;
}
}
2024-01-19 00:11:16 +01:00
if (basicSection != null)
{
2024-01-17 18:13:09 +01:00
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>(),
};
}
2024-01-16 17:56:52 +01:00
public List<DailyTCVData> DailyTCV
{
get
{
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))
{
2024-01-19 00:11:16 +01:00
JObject basicSection = null;
JObject extraSection = null;
2024-01-16 17:56:52 +01:00
while (jsonReader.Read())
{
2024-01-19 00:11:16 +01:00
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);
}
}
2024-01-16 17:56:52 +01:00
2024-01-19 00:11:16 +01:00
if (basicSection != null && extraSection != null)
{
break;
}
2024-01-16 17:56:52 +01:00
}
2024-01-19 00:11:16 +01:00
if (basicSection != null)
{
2024-01-16 17:56:52 +01:00
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);
}
2024-01-19 00:11:16 +01:00
}
2024-01-16 17:56:52 +01:00
}
}
}
}
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"],
};
}
2024-01-15 15:12:46 +01:00
public List<MonthlyStatsData> MonthlyStats
2024-01-07 22:53:49 +01:00
{
get
{
2024-01-15 15:12:46 +01:00
if (_monthlyStats == null || DateTime.UtcNow > _monthlyStatsRefresh)
2024-01-07 22:53:49 +01:00
{
2024-01-15 15:12:46 +01:00
lock (_monthlyStatsLock)
2024-01-07 22:53:49 +01:00
{
2024-01-15 15:12:46 +01:00
if (_monthlyStats == null || DateTime.UtcNow > _monthlyStatsRefresh)
2024-01-07 22:53:49 +01:00
{
2024-01-10 16:58:09 +01:00
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;
}
}
2024-01-15 15:12:46 +01:00
if (basicSection != null)// &&
2024-01-19 00:11:16 +01:00
{
2024-01-10 16:58:09 +01:00
if (extraSection != null)
{
2024-01-15 15:12:46 +01:00
JArray monthlyStatsSection = (JArray)extraSection["monthlyStats"];
_monthlyStats = monthlyStatsSection.Select(j => BuildMonthlyStatsData(j as JObject)).ToList();
_monthlyStatsRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
2024-01-10 16:58:09 +01:00
}
}
}
2024-01-07 22:53:49 +01:00
}
}
}
2024-01-15 15:12:46 +01:00
return _monthlyStats;
2024-01-07 22:53:49 +01:00
}
}
2024-01-15 15:12:46 +01:00
private MonthlyStatsData BuildMonthlyStatsData(dynamic monthlyStatsDataJson)
{
return new MonthlyStatsData()
2024-01-07 22:53:49 +01:00
{
2024-01-15 15:12:46 +01:00
Month = monthlyStatsDataJson["month"],
TotalSales = monthlyStatsDataJson["totalSales"],
TotalProfitCurrency = monthlyStatsDataJson["totalProfitCurrency"],
AvgGrowth = monthlyStatsDataJson["avgGrowth"],
2024-01-16 17:56:52 +01:00
Order = monthlyStatsDataJson["order"],
2024-01-07 22:53:49 +01:00
};
}
public List<SellLogData> SellLog
{
get
{
2024-01-07 22:53:49 +01:00
if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh))
{
lock (_sellLock)
{
// Thread double locking
if (_sellLog == null || (DateTime.UtcNow > _sellLogRefresh))
{
_sellLog.Clear();
2024-01-07 22:53:49 +01:00
2021-08-08 18:30:01 +02:00
// Page through the sales data summarizing it.
bool exitLoop = false;
int pageIndex = 1;
2024-01-07 22:53:49 +01:00
// 1 record per page to allow user to set max records to retrieve
int maxPages = _systemConfiguration.GeneralSettings.Monitor.MaxSalesRecords;
int requestedPages = 0;
2024-01-07 22:53:49 +01:00
while (!exitLoop && requestedPages < maxPages)
2021-08-08 18:30:01 +02:00
{
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++;
2024-01-19 00:11:16 +01:00
Console.WriteLine($"Importing salesLog: {pageIndex}");
}
else
{
// All data retrieved
exitLoop = true;
}
2021-08-08 18:30:01 +02:00
}
2024-01-07 22:53:49 +01:00
// Update sell log refresh time
_sellLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds -1);
2021-08-08 18:30:01 +02:00
}
}
}
2018-05-22 10:11:50 +02:00
return _sellLog;
}
}
2024-01-07 22:53:49 +01:00
public List<DCALogData> DCALog
{
get
{
if (_dcaLog == null || (DateTime.UtcNow > _dcaLogRefresh))
{
lock (_dcaLock)
{
// Thread double locking
if (_dcaLog == null || (DateTime.UtcNow > _dcaLogRefresh))
{
dynamic dcaData = null, pairsData = null, pendingData = null, watchData = null;
_dcaLog.Clear();
Parallel.Invoke(() =>
{
dcaData = GetDataFromProfitTrailer("/api/v2/data/dca", true);
},
() =>
{
pairsData = GetDataFromProfitTrailer("/api/v2/data/pairs", true);
},
() =>
{
pendingData = GetDataFromProfitTrailer("/api/v2/data/pending", true);
},
() =>
{
watchData = GetDataFromProfitTrailer("/api/v2/data/watchmode", true);
});
this.BuildDCALogData(dcaData, pairsData, pendingData, watchData);
_dcaLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.BagAnalyzerRefreshSeconds - 1);
}
}
}
2018-05-22 10:11:50 +02:00
return _dcaLog;
}
}
public List<BuyLogData> BuyLog
{
get
{
if (_buyLog == null || (DateTime.UtcNow > _buyLogRefresh))
{
lock (_buyLock)
{
// Thread double locking
if (_buyLog == null || (DateTime.UtcNow > _buyLogRefresh))
{
_buyLog.Clear();
this.BuildBuyLogData(GetDataFromProfitTrailer("/api/v2/data/pbl", true));
_buyLogRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.BuyAnalyzerRefreshSeconds - 1);
}
}
}
2018-05-22 10:11:50 +02:00
return _buyLog;
}
}
public TransactionData TransactionData
{
get
{
2018-05-22 10:11:50 +02:00
if (_transactionData == null) _transactionData = new TransactionData(_ptmBasePath);
return _transactionData;
}
}
public double GetCurrentBalance()
{
return
2024-01-15 15:12:46 +01:00
(this.Misc.Balance);
2018-05-22 10:11:50 +02:00
}
public double GetPairsBalance()
2019-04-30 17:36:27 +02:00
{
return
2024-01-15 15:12:46 +01:00
(this.Misc.PairsValue);
2019-04-30 17:36:27 +02:00
}
public double GetDCABalance()
2019-04-30 17:36:27 +02:00
{
return
2024-01-15 15:12:46 +01:00
(this.Misc.DCAValue);
2019-04-30 17:36:27 +02:00
}
public double GetPendingBalance()
2019-04-30 17:36:27 +02:00
{
return
2024-01-15 15:12:46 +01:00
(this.Misc.PendingValue);
2019-04-30 17:36:27 +02:00
}
public double GetDustBalance()
{
return
2024-01-15 15:12:46 +01:00
(this.Misc.DustValue);
2019-04-30 17:36:27 +02:00
}
2024-01-07 22:53:49 +01:00
public double GetSnapshotBalance(DateTime snapshotDateTime)
{
2024-01-15 15:12:46 +01:00
double result = _misc.StartBalance;
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
result += this.SellLog.FindAll(sl => sl.SoldDate.Date < snapshotDateTime.Date).Sum(sl => sl.Profit);
result += this.TransactionData.Transactions.FindAll(t => t.UTCDateTime < snapshotDateTime).Sum(t => t.Amount);
2024-01-07 22:53:49 +01:00
// Calculate holdings for snapshot date
result += this.DCALog.FindAll(pairs => pairs.FirstBoughtDate <= snapshotDateTime).Sum(pairs => pairs.CurrentValue);
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
return result;
}
2024-01-07 22:53:49 +01:00
2019-10-13 19:19:26 +02:00
private dynamic GetDataFromProfitTrailer(string callPath, bool arrayReturned = false)
{
string rawBody = "";
2021-08-08 18:30:01 +02:00
string url = string.Format("{0}{1}{2}token={3}", _systemConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL,
callPath,
callPath.Contains("?") ? "&" : "?",
_systemConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken);
2024-01-07 22:53:49 +01:00
2019-10-13 19:19:26 +02:00
// Get the data from PT
Debug.WriteLine(String.Format("{0} - Calling '{1}'", DateTime.UtcNow, url));
2019-10-13 19:19:26 +02:00
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
request.KeepAlive = true;
2024-01-07 22:53:49 +01:00
2019-10-13 19:19:26 +02:00
WebResponse response = request.GetResponse();
2024-01-07 22:53:49 +01:00
2019-10-13 19:19:26 +02:00
using (Stream dataStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(dataStream);
rawBody = reader.ReadToEnd();
reader.Close();
}
response.Close();
2024-01-07 22:53:49 +01:00
2019-10-13 19:19:26 +02:00
if (!arrayReturned)
{
return JObject.Parse(rawBody);
}
else
{
return JArray.Parse(rawBody);
}
2019-10-13 19:19:26 +02:00
}
2024-01-10 16:58:09 +01:00
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);
// Get the data from PT
Debug.WriteLine(String.Format("{0} - Calling '{1}'", DateTime.UtcNow, url));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
request.KeepAlive = true;
WebResponse response = request.GetResponse();
return response.GetResponseStream();
}
2019-10-13 19:19:26 +02:00
2024-01-07 22:53:49 +01:00
2019-10-13 19:19:26 +02:00
private void BuildSellLogData(dynamic rawSellLogData)
{
2019-10-13 19:19:26 +02:00
foreach (var rsld in rawSellLogData.data)
{
2018-05-22 10:11:50 +02:00
SellLogData sellLogData = new SellLogData();
sellLogData.SoldAmount = rsld.soldAmount;
sellLogData.BoughtTimes = rsld.boughtTimes;
sellLogData.Market = rsld.market;
sellLogData.ProfitPercent = rsld.profit;
sellLogData.SoldPrice = rsld.currentPrice;
2019-01-15 13:43:07 +01:00
sellLogData.AverageBuyPrice = rsld.avgPrice;
2021-08-24 05:48:50 +02:00
sellLogData.TotalCost = rsld.totalCost;
sellLogData.Profit = rsld.profitCurrency;
2024-01-07 22:53:49 +01:00
2019-01-07 15:33:02 +01:00
//Convert Unix Timestamp to Datetime
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds((double)rsld.soldDate).ToUniversalTime();
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
// Profit Trailer sales are saved in UTC
2019-01-07 15:33:02 +01:00
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);
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
// Convert UTC sales time to local offset time
2024-01-07 22:53:49 +01:00
2019-10-19 12:14:40 +02:00
ptSoldDate = ptSoldDate.ToOffset(OffsetTimeSpan);
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
sellLogData.SoldDate = ptSoldDate.DateTime;
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
_sellLog.Add(sellLogData);
}
}
2019-10-13 19:19:26 +02:00
private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData)
{
// Parse DCA data
_dcaLog.AddRange(ParsePairsData(rawDCALogData, true));
2024-01-07 22:53:49 +01:00
// Parse Pairs data
_dcaLog.AddRange(ParsePairsData(rawPairsLogData, false));
2024-01-07 22:53:49 +01:00
// Parse pending pairs data
2023-06-22 11:57:47 +02:00
_dcaLog.AddRange(ParsePairsData(rawPendingLogData, false));
2024-01-07 22:53:49 +01:00
// Parse watch only pairs data
_dcaLog.AddRange(ParsePairsData(rawWatchModeLogData, false));
}
2018-05-22 10:11:50 +02:00
// Parse the pairs data from PT to our own common data structure.
private List<DCALogData> ParsePairsData(dynamic pairsData, bool processBuyStrategies)
{
List<DCALogData> pairs = new List<DCALogData>();
2024-01-07 22:53:49 +01:00
foreach (var pair in pairsData)
{
2018-05-22 10:11:50 +02:00
DCALogData dcaLogData = new DCALogData();
dcaLogData.Amount = pair.totalAmount;
dcaLogData.BoughtTimes = pair.boughtTimes;
dcaLogData.Market = pair.market;
dcaLogData.ProfitPercent = pair.profit;
dcaLogData.AverageBuyPrice = pair.avgPrice;
dcaLogData.TotalCost = pair.totalCost;
dcaLogData.BuyTriggerPercent = pair.buyProfit;
dcaLogData.CurrentLowBBValue = pair.bbLow == null ? 0 : pair.bbLow;
dcaLogData.CurrentHighBBValue = pair.highBb == null ? 0 : pair.highBb;
dcaLogData.BBTrigger = pair.bbTrigger == null ? 0 : pair.bbTrigger;
dcaLogData.CurrentPrice = pair.currentPrice;
dcaLogData.SellTrigger = pair.triggerValue == null ? 0 : pair.triggerValue;
dcaLogData.PercChange = pair.percChange;
2020-07-17 14:34:07 +02:00
dcaLogData.Leverage = pair.leverage == null ? 0 : pair.leverage;
dcaLogData.BuyStrategy = pair.buyStrategy == null ? "" : pair.buyStrategy;
dcaLogData.SellStrategy = pair.sellStrategy == null ? "" : pair.sellStrategy;
2019-05-04 13:57:49 +02:00
dcaLogData.IsTrailing = false;
2024-01-07 22:53:49 +01:00
// See if they are using PT 2.5 (buyStrategiesData) or 2.4 (buyStrategies)
var buyStrats = pair.buyStrategies != null ? pair.buyStrategies : pair.buyStrategiesData.data;
if (buyStrats != null && processBuyStrategies)
2019-05-04 13:57:49 +02:00
{
foreach (var bs in buyStrats)
2019-05-04 13:57:49 +02:00
{
Strategy buyStrategy = new Strategy();
buyStrategy.Type = bs.type;
buyStrategy.Name = bs.name;
buyStrategy.EntryValue = bs.entryValue;
buyStrategy.EntryValueLimit = bs.entryValueLimit;
buyStrategy.TriggerValue = bs.triggerValue;
buyStrategy.CurrentValue = bs.currentValue;
buyStrategy.CurrentValuePercentage = bs.currentValuePercentage;
buyStrategy.Decimals = bs.decimals;
buyStrategy.IsTrailing = bs.trailing;
buyStrategy.IsTrue = bs.strategyResult;
2024-01-07 22:53:49 +01:00
dcaLogData.BuyStrategies.Add(buyStrategy);
2019-05-04 13:57:49 +02:00
}
}
// See if they are using PT 2.5 (sellStrategiesData) or 2.4 (sellStrategies)
var sellStrats = pair.sellStrategies != null ? pair.sellStrategies : pair.sellStrategiesData.data;
if (sellStrats != null)
{
foreach (var ss in sellStrats)
{
2018-05-22 10:11:50 +02:00
Strategy sellStrategy = new Strategy();
sellStrategy.Type = ss.type;
sellStrategy.Name = ss.name;
sellStrategy.EntryValue = ss.entryValue;
sellStrategy.EntryValueLimit = ss.entryValueLimit;
sellStrategy.TriggerValue = ss.triggerValue;
sellStrategy.CurrentValue = ss.currentValue;
sellStrategy.CurrentValuePercentage = ss.currentValuePercentage;
sellStrategy.Decimals = ss.decimals;
sellStrategy.IsTrailing = ss.trailing;
sellStrategy.IsTrue = ss.strategyResult;
2024-01-07 22:53:49 +01:00
2018-05-22 10:11:50 +02:00
dcaLogData.SellStrategies.Add(sellStrategy);
2024-01-07 22:53:49 +01:00
// Find the target percentage gain to sell.
if (sellStrategy.Name.Contains("GAIN", StringComparison.InvariantCultureIgnoreCase))
{
if (!dcaLogData.TargetGainValue.HasValue || dcaLogData.TargetGainValue.Value > sellStrategy.EntryValue)
{
// Set the target sell percentage
dcaLogData.TargetGainValue = sellStrategy.EntryValue;
}
}
2019-05-12 16:27:50 +02:00
}
}
2024-01-07 22:53:49 +01:00
// Calculate current value
dcaLogData.CurrentValue = dcaLogData.CurrentPrice * dcaLogData.Amount;
2024-01-07 22:53:49 +01:00
// Convert Unix Timestamp to Datetime
System.DateTime rdldDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
rdldDateTime = rdldDateTime.AddSeconds((double)pair.firstBoughtDate).ToUniversalTime();
2024-01-07 22:53:49 +01:00
2019-05-12 16:27:50 +02:00
// Profit Trailer bought times are saved in UTC
if (pair.firstBoughtDate > 0)
2019-05-12 16:27:50 +02:00
{
DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rdldDateTime.Year.ToString() + "-" + rdldDateTime.Month.ToString("00") + "-" + rdldDateTime.Day.ToString("00") + "T" + rdldDateTime.Hour.ToString("00") + ":" + rdldDateTime.Minute.ToString("00") + ":" + rdldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
2019-05-12 16:27:50 +02:00
// Convert UTC bought time to local offset time
2019-10-19 12:14:40 +02:00
ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(OffsetTimeSpan);
2019-05-12 16:27:50 +02:00
dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime;
}
else
{
dcaLogData.FirstBoughtDate = Constants.confMinDate;
}
2024-01-07 22:53:49 +01:00
2019-05-12 16:27:50 +02:00
_dcaLog.Add(dcaLogData);
}
return pairs;
2018-05-22 10:11:50 +02:00
}
private void BuildBuyLogData(dynamic rawBuyLogData)
{
foreach (var rbld in rawBuyLogData)
{
BuyLogData buyLogData = new BuyLogData() { IsTrailing = false, IsTrue = false, IsSom = false, TrueStrategyCount = 0 };
2018-05-22 10:11:50 +02:00
buyLogData.Market = rbld.market;
buyLogData.ProfitPercent = rbld.profit;
buyLogData.CurrentPrice = rbld.currentPrice;
buyLogData.PercChange = rbld.percChange;
buyLogData.Volume24h = rbld.volume;
2024-01-07 22:53:49 +01:00
if (rbld.positive != null)
{
buyLogData.IsTrailing = ((string)(rbld.positive)).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
buyLogData.IsTrue = ((string)(rbld.positive)).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
}
else
{
// Parse buy strategies
2024-01-07 22:53:49 +01:00
// See if they are using PT 2.5 (buyStrategiesData) or 2.4 (buyStrategies)
var buyStrats = rbld.buyStrategies != null ? rbld.buyStrategies : rbld.buyStrategiesData.data;
2024-01-07 22:53:49 +01:00
if (buyStrats != null)
{
foreach (var bs in buyStrats)
{
2018-05-22 10:11:50 +02:00
Strategy buyStrategy = new Strategy();
buyStrategy.Type = bs.type;
buyStrategy.Name = bs.name;
buyStrategy.EntryValue = bs.entryValue;
buyStrategy.EntryValueLimit = bs.entryValueLimit;
buyStrategy.TriggerValue = bs.triggerValue;
buyStrategy.CurrentValue = bs.currentValue;
buyStrategy.CurrentValuePercentage = bs.currentValuePercentage;
buyStrategy.Decimals = bs.decimals;
buyStrategy.IsTrailing = bs.trailing;
buyStrategy.IsTrue = bs.strategyResult;
2024-01-07 22:53:49 +01:00
// Is SOM?
2019-10-15 15:05:53 +02:00
buyLogData.IsSom = buyLogData.IsSom || buyStrategy.Name.Contains("som enabled", StringComparison.OrdinalIgnoreCase);
2024-01-07 22:53:49 +01:00
// Is the pair trailing?
buyLogData.IsTrailing = buyLogData.IsTrailing || buyStrategy.IsTrailing;
buyLogData.IsTrue = buyLogData.IsTrue || buyStrategy.IsTrue;
2024-01-07 22:53:49 +01:00
// True status strategy count total
buyLogData.TrueStrategyCount += buyStrategy.IsTrue ? 1 : 0;
2024-01-07 22:53:49 +01:00
// Add
2018-05-22 10:11:50 +02:00
buyLogData.BuyStrategies.Add(buyStrategy);
}
}
}
_buyLog.Add(buyLogData);
}
}
}
}