commit
d78fe1e7a7
|
@ -361,6 +361,19 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
}
|
||||
#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
|
||||
{
|
||||
|
@ -456,6 +469,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public double AverageBuyPrice { get; set; }
|
||||
public double TotalCost { get; set; }
|
||||
public double CurrentValue { get; set; }
|
||||
public double? TargetGainValue { get; set; }
|
||||
public double Amount { get; set; }
|
||||
public double CurrentPrice { get; set; }
|
||||
public double SellTrigger { get; set; }
|
||||
|
@ -463,6 +477,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public DateTime FirstBoughtDate { get; set; }
|
||||
public string SellStrategy { get; set; }
|
||||
public string BuyStrategy { get; set; }
|
||||
public double Leverage { get; set; }
|
||||
public List<Strategy> BuyStrategies { get; set; } = new List<Strategy>();
|
||||
public List<Strategy> SellStrategies { get; set; } = new List<Strategy>();
|
||||
}
|
||||
|
@ -484,6 +499,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public double CurrentPrice { get; set; }
|
||||
public int BoughtTimes { get; set; }
|
||||
public double PercChange { get; set; }
|
||||
public double Volume24h { get; set; }
|
||||
public List<Strategy> BuyStrategies { get; set; } = new List<Strategy>();
|
||||
}
|
||||
|
||||
|
@ -497,5 +513,6 @@ namespace Core.Main.DataObjects.PTMagicData
|
|||
public double DustValue { get; set; }
|
||||
public string Market { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -15,14 +15,15 @@ namespace Core.Main.DataObjects
|
|||
public class ProfitTrailerData
|
||||
{
|
||||
private SummaryData _summary = null;
|
||||
private Properties _properties = null;
|
||||
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;
|
||||
private DateTime _buyLogRefresh = DateTime.UtcNow, _sellLogRefresh = DateTime.UtcNow, _dcaLogRefresh = DateTime.UtcNow, _summaryRefresh = DateTime.UtcNow;
|
||||
private volatile object _buyLock = new object(), _sellLock = new object(), _dcaLock = new object(), _summaryLock = new object();
|
||||
private DateTime _buyLogRefresh = DateTime.UtcNow, _sellLogRefresh = DateTime.UtcNow, _dcaLogRefresh = DateTime.UtcNow, _summaryRefresh = DateTime.UtcNow, _propertiesRefresh = DateTime.UtcNow;
|
||||
private volatile object _buyLock = new object(), _sellLock = new object(), _dcaLock = new object(), _summaryLock = new object(), _propertiesLock = new object();
|
||||
private TimeSpan? _offsetTimeSpan = null;
|
||||
|
||||
// Constructor
|
||||
|
@ -75,6 +76,26 @@ namespace Core.Main.DataObjects
|
|||
return _summary;
|
||||
}
|
||||
}
|
||||
public Properties Properties
|
||||
{
|
||||
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"));
|
||||
_propertiesRefresh = DateTime.UtcNow.AddSeconds(_systemConfiguration.GeneralSettings.Monitor.RefreshSeconds - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _properties;
|
||||
}
|
||||
}
|
||||
public List<SellLogData> SellLog
|
||||
{
|
||||
get
|
||||
|
@ -205,11 +226,7 @@ namespace Core.Main.DataObjects
|
|||
public double GetCurrentBalance()
|
||||
{
|
||||
return
|
||||
(this.Summary.Balance +
|
||||
this.Summary.PairsValue +
|
||||
this.Summary.DCAValue +
|
||||
this.Summary.PendingValue +
|
||||
this.Summary.DustValue);
|
||||
(this.Summary.Balance);
|
||||
}
|
||||
public double GetPairsBalance()
|
||||
{
|
||||
|
@ -290,7 +307,19 @@ namespace Core.Main.DataObjects
|
|||
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)
|
||||
|
@ -304,21 +333,13 @@ namespace Core.Main.DataObjects
|
|||
sellLogData.AverageBuyPrice = rsld.avgPrice;
|
||||
sellLogData.TotalCost = sellLogData.SoldAmount * sellLogData.AverageBuyPrice;
|
||||
|
||||
// check if sale was a short position
|
||||
if ((sellLogData.ProfitPercent > 0) && (sellLogData.AverageBuyPrice > sellLogData.SoldPrice))
|
||||
{
|
||||
double soldValueRaw = (sellLogData.SoldAmount * sellLogData.SoldPrice);
|
||||
double soldValueAfterFees = soldValueRaw + (soldValueRaw * ((double)rsld.fee / 100));
|
||||
sellLogData.SoldValue = soldValueAfterFees;
|
||||
sellLogData.Profit = Math.Abs(Math.Round(sellLogData.SoldValue - sellLogData.TotalCost, 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
double soldValueRaw = (sellLogData.SoldAmount * sellLogData.SoldPrice);
|
||||
double soldValueAfterFees = soldValueRaw - (soldValueRaw * ((double)rsld.fee / 100));
|
||||
sellLogData.SoldValue = soldValueAfterFees;
|
||||
sellLogData.Profit = Math.Round(sellLogData.SoldValue - sellLogData.TotalCost, 8);
|
||||
}
|
||||
// check if bot is a shortbot via PT API. Losses on short bot currently showing as gains. Issue #195
|
||||
// code removed
|
||||
|
||||
double soldValueRaw = (sellLogData.SoldAmount * sellLogData.SoldPrice);
|
||||
double soldValueAfterFees = soldValueRaw - (soldValueRaw * ((double)rsld.fee / 100));
|
||||
sellLogData.SoldValue = soldValueAfterFees;
|
||||
sellLogData.Profit = Math.Round(sellLogData.SoldValue - sellLogData.TotalCost, 8);
|
||||
|
||||
//Convert Unix Timestamp to Datetime
|
||||
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
|
@ -338,69 +359,92 @@ namespace Core.Main.DataObjects
|
|||
|
||||
private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData)
|
||||
{
|
||||
foreach (var rdld in rawDCALogData)
|
||||
// Parse DCA data
|
||||
_dcaLog.AddRange(ParsePairsData(rawDCALogData, true));
|
||||
|
||||
// Parse Pairs data
|
||||
_dcaLog.AddRange(ParsePairsData(rawPairsLogData, false));
|
||||
|
||||
// Parse pending pairs data
|
||||
_dcaLog.AddRange(ParsePairsData(rawPendingLogData, false));
|
||||
|
||||
// Parse watch only pairs data
|
||||
_dcaLog.AddRange(ParsePairsData(rawWatchModeLogData, false));
|
||||
|
||||
}
|
||||
|
||||
// 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>();
|
||||
|
||||
foreach (var pair in pairsData)
|
||||
{
|
||||
DCALogData dcaLogData = new DCALogData();
|
||||
dcaLogData.Amount = rdld.totalAmount;
|
||||
dcaLogData.BoughtTimes = rdld.boughtTimes;
|
||||
dcaLogData.Market = rdld.market;
|
||||
dcaLogData.ProfitPercent = rdld.profit;
|
||||
dcaLogData.AverageBuyPrice = rdld.avgPrice;
|
||||
dcaLogData.TotalCost = rdld.totalCost;
|
||||
dcaLogData.BuyTriggerPercent = rdld.buyProfit;
|
||||
dcaLogData.CurrentLowBBValue = rdld.bbLow == null ? 0 : rdld.bbLow;
|
||||
dcaLogData.CurrentHighBBValue = rdld.highBb == null ? 0 : rdld.highBb;
|
||||
dcaLogData.BBTrigger = rdld.bbTrigger == null ? 0 : rdld.bbTrigger;
|
||||
dcaLogData.CurrentPrice = rdld.currentPrice;
|
||||
dcaLogData.SellTrigger = rdld.triggerValue == null ? 0 : rdld.triggerValue;
|
||||
dcaLogData.PercChange = rdld.percChange;
|
||||
dcaLogData.BuyStrategy = rdld.buyStrategy == null ? "" : rdld.buyStrategy;
|
||||
dcaLogData.SellStrategy = rdld.sellStrategy == null ? "" : rdld.sellStrategy;
|
||||
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;
|
||||
dcaLogData.Leverage = pair.leverage == null ? 0 : pair.leverage;
|
||||
dcaLogData.BuyStrategy = pair.buyStrategy == null ? "" : pair.buyStrategy;
|
||||
dcaLogData.SellStrategy = pair.sellStrategy == null ? "" : pair.sellStrategy;
|
||||
dcaLogData.IsTrailing = false;
|
||||
|
||||
if (rdld.positive != null)
|
||||
if (pair.buyStrategies != null && processBuyStrategies)
|
||||
{
|
||||
dcaLogData.IsTrailing = ((string)rdld.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
dcaLogData.IsTrue = ((string)rdld.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rdld.buyStrategies != null)
|
||||
foreach (var bs in pair.buyStrategies)
|
||||
{
|
||||
foreach (var bs in rdld.buyStrategies)
|
||||
{
|
||||
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 = ((string)bs.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
buyStrategy.IsTrue = ((string)bs.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
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 = ((string)bs.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
buyStrategy.IsTrue = ((string)bs.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
|
||||
dcaLogData.BuyStrategies.Add(buyStrategy);
|
||||
}
|
||||
dcaLogData.BuyStrategies.Add(buyStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
if (rdld.sellStrategies != null)
|
||||
if (pair.sellStrategies != null)
|
||||
{
|
||||
foreach (var ss in pair.sellStrategies)
|
||||
{
|
||||
foreach (var ss in rdld.sellStrategies)
|
||||
{
|
||||
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 = ((string)ss.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
sellStrategy.IsTrue = ((string)ss.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
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 = ((string)ss.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
sellStrategy.IsTrue = ((string)ss.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
|
||||
dcaLogData.SellStrategies.Add(sellStrategy);
|
||||
dcaLogData.SellStrategies.Add(sellStrategy);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,12 +452,12 @@ namespace Core.Main.DataObjects
|
|||
// Calculate current value
|
||||
dcaLogData.CurrentValue = dcaLogData.CurrentPrice * dcaLogData.Amount;
|
||||
|
||||
//Convert Unix Timestamp to Datetime
|
||||
// Convert Unix Timestamp to Datetime
|
||||
System.DateTime rdldDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
rdldDateTime = rdldDateTime.AddSeconds((double)rdld.firstBoughtDate).ToUniversalTime();
|
||||
rdldDateTime = rdldDateTime.AddSeconds((double)pair.firstBoughtDate).ToUniversalTime();
|
||||
|
||||
// Profit Trailer bought times are saved in UTC
|
||||
if (rdld.firstBoughtDate > 0)
|
||||
if (pair.firstBoughtDate > 0)
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -430,182 +474,7 @@ namespace Core.Main.DataObjects
|
|||
_dcaLog.Add(dcaLogData);
|
||||
}
|
||||
|
||||
foreach (var rpld in rawPairsLogData)
|
||||
{
|
||||
DCALogData dcaLogData = new DCALogData();
|
||||
dcaLogData.Amount = rpld.totalAmount;
|
||||
dcaLogData.BoughtTimes = 0;
|
||||
dcaLogData.Market = rpld.market;
|
||||
dcaLogData.ProfitPercent = rpld.profit;
|
||||
dcaLogData.AverageBuyPrice = rpld.avgPrice;
|
||||
dcaLogData.TotalCost = rpld.totalCost;
|
||||
dcaLogData.BuyTriggerPercent = rpld.buyProfit;
|
||||
dcaLogData.CurrentPrice = rpld.currentPrice;
|
||||
dcaLogData.SellTrigger = rpld.triggerValue == null ? 0 : rpld.triggerValue;
|
||||
dcaLogData.PercChange = rpld.percChange;
|
||||
dcaLogData.BuyStrategy = rpld.buyStrategy == null ? "" : rpld.buyStrategy;
|
||||
dcaLogData.SellStrategy = rpld.sellStrategy == null ? "" : rpld.sellStrategy;
|
||||
dcaLogData.IsTrailing = false;
|
||||
|
||||
if (rpld.sellStrategies != null)
|
||||
{
|
||||
foreach (var ss in rpld.sellStrategies)
|
||||
{
|
||||
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 = ((string)ss.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
sellStrategy.IsTrue = ((string)ss.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
|
||||
dcaLogData.SellStrategies.Add(sellStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
//Convert Unix Timestamp to Datetime
|
||||
System.DateTime rpldDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
rpldDateTime = rpldDateTime.AddSeconds((double)rpld.firstBoughtDate).ToUniversalTime();
|
||||
|
||||
// Profit Trailer bought times are saved in UTC
|
||||
if (rpld.firstBoughtDate > 0)
|
||||
{
|
||||
DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rpldDateTime.Year.ToString() + "-" + rpldDateTime.Month.ToString("00") + "-" + rpldDateTime.Day.ToString("00") + "T" + rpldDateTime.Hour.ToString("00") + ":" + rpldDateTime.Minute.ToString("00") + ":" + rpldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
|
||||
// Convert UTC bought time to local offset time
|
||||
ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(OffsetTimeSpan);
|
||||
|
||||
dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcaLogData.FirstBoughtDate = Constants.confMinDate;
|
||||
}
|
||||
|
||||
_dcaLog.Add(dcaLogData);
|
||||
}
|
||||
|
||||
foreach (var rpld in rawPendingLogData)
|
||||
{
|
||||
DCALogData dcaLogData = new DCALogData();
|
||||
dcaLogData.Amount = rpld.totalAmount;
|
||||
dcaLogData.BoughtTimes = 0;
|
||||
dcaLogData.Market = rpld.market;
|
||||
dcaLogData.ProfitPercent = rpld.profit;
|
||||
dcaLogData.AverageBuyPrice = rpld.avgPrice;
|
||||
dcaLogData.TotalCost = rpld.totalCost;
|
||||
dcaLogData.BuyTriggerPercent = rpld.buyProfit;
|
||||
dcaLogData.CurrentPrice = rpld.currentPrice;
|
||||
dcaLogData.SellTrigger = rpld.triggerValue == null ? 0 : rpld.triggerValue;
|
||||
dcaLogData.PercChange = rpld.percChange;
|
||||
dcaLogData.BuyStrategy = rpld.buyStrategy == null ? "" : rpld.buyStrategy;
|
||||
dcaLogData.SellStrategy = rpld.sellStrategy == null ? "" : rpld.sellStrategy;
|
||||
dcaLogData.IsTrailing = false;
|
||||
|
||||
if (rpld.sellStrategies != null)
|
||||
{
|
||||
foreach (var ss in rpld.sellStrategies)
|
||||
{
|
||||
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 = ((string)ss.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
sellStrategy.IsTrue = ((string)ss.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
|
||||
dcaLogData.SellStrategies.Add(sellStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
//Convert Unix Timestamp to Datetime
|
||||
System.DateTime rpldDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
rpldDateTime = rpldDateTime.AddSeconds((double)rpld.firstBoughtDate).ToUniversalTime();
|
||||
|
||||
// Profit Trailer bought times are saved in UTC
|
||||
if (rpld.firstBoughtDate > 0)
|
||||
{
|
||||
DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rpldDateTime.Year.ToString() + "-" + rpldDateTime.Month.ToString("00") + "-" + rpldDateTime.Day.ToString("00") + "T" + rpldDateTime.Hour.ToString("00") + ":" + rpldDateTime.Minute.ToString("00") + ":" + rpldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
|
||||
// Convert UTC bought time to local offset time
|
||||
ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(OffsetTimeSpan);
|
||||
|
||||
dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcaLogData.FirstBoughtDate = Constants.confMinDate;
|
||||
}
|
||||
|
||||
_dcaLog.Add(dcaLogData);
|
||||
}
|
||||
|
||||
foreach (var rpld in rawWatchModeLogData)
|
||||
{
|
||||
DCALogData dcaLogData = new DCALogData();
|
||||
dcaLogData.Amount = rpld.totalAmount;
|
||||
dcaLogData.BoughtTimes = 0;
|
||||
dcaLogData.Market = rpld.market;
|
||||
dcaLogData.ProfitPercent = rpld.profit;
|
||||
dcaLogData.AverageBuyPrice = rpld.avgPrice;
|
||||
dcaLogData.TotalCost = rpld.totalCost;
|
||||
dcaLogData.BuyTriggerPercent = rpld.buyProfit;
|
||||
dcaLogData.CurrentPrice = rpld.currentPrice;
|
||||
dcaLogData.SellTrigger = rpld.triggerValue == null ? 0 : rpld.triggerValue;
|
||||
dcaLogData.PercChange = rpld.percChange;
|
||||
dcaLogData.BuyStrategy = rpld.buyStrategy == null ? "" : rpld.buyStrategy;
|
||||
dcaLogData.SellStrategy = rpld.sellStrategy == null ? "" : rpld.sellStrategy;
|
||||
dcaLogData.IsTrailing = false;
|
||||
|
||||
if (rpld.sellStrategies != null)
|
||||
{
|
||||
foreach (var ss in rpld.sellStrategies)
|
||||
{
|
||||
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 = ((string)ss.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
sellStrategy.IsTrue = ((string)ss.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||
|
||||
dcaLogData.SellStrategies.Add(sellStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
//Convert Unix Timestamp to Datetime
|
||||
System.DateTime rpldDateTime = new DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
rpldDateTime = rpldDateTime.AddSeconds((double)rpld.firstBoughtDate).ToUniversalTime();
|
||||
|
||||
// Profit Trailer bought times are saved in UTC
|
||||
if (rpld.firstBoughtDate > 0)
|
||||
{
|
||||
DateTimeOffset ptFirstBoughtDate = DateTimeOffset.Parse(rpldDateTime.Year.ToString() + "-" + rpldDateTime.Month.ToString("00") + "-" + rpldDateTime.Day.ToString("00") + "T" + rpldDateTime.Hour.ToString("00") + ":" + rpldDateTime.Minute.ToString("00") + ":" + rpldDateTime.Second.ToString("00"), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
|
||||
// Convert UTC bought time to local offset time
|
||||
ptFirstBoughtDate = ptFirstBoughtDate.ToOffset(OffsetTimeSpan);
|
||||
|
||||
dcaLogData.FirstBoughtDate = ptFirstBoughtDate.DateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcaLogData.FirstBoughtDate = Constants.confMinDate;
|
||||
}
|
||||
|
||||
_dcaLog.Add(dcaLogData);
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
private void BuildBuyLogData(dynamic rawBuyLogData)
|
||||
|
@ -617,6 +486,7 @@ namespace Core.Main.DataObjects
|
|||
buyLogData.ProfitPercent = rbld.profit;
|
||||
buyLogData.CurrentPrice = rbld.currentPrice;
|
||||
buyLogData.PercChange = rbld.percChange;
|
||||
buyLogData.Volume24h = rbld.volume;
|
||||
|
||||
if (rbld.positive != null)
|
||||
{
|
||||
|
|
|
@ -547,6 +547,19 @@ namespace Core.Helper
|
|||
|
||||
result += pairName;
|
||||
}
|
||||
else if (platform.Equals("TradingViewFutures"))
|
||||
{
|
||||
result = "https://www.tradingview.com/chart/?symbol=";
|
||||
|
||||
string pairName = SystemHelper.StripBadCode(market, Constants.WhiteListMinimal);
|
||||
|
||||
if (pairName.StartsWith(mainMarket))
|
||||
{
|
||||
pairName = pairName.Replace(mainMarket, "") + mainMarket;
|
||||
}
|
||||
|
||||
result += pairName + "PERP";
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (exchange)
|
||||
|
|
|
@ -2564,7 +2564,7 @@ namespace Core.Main
|
|||
}
|
||||
}
|
||||
|
||||
this.LastRuntimeSummary.MarketSummary.Add(marketPair, mpSummary);
|
||||
this.LastRuntimeSummary.MarketSummary.TryAdd(marketPair, mpSummary);
|
||||
}
|
||||
|
||||
this.Log.DoLogInfo("Summary: Current single market properties saved.");
|
||||
|
|
|
@ -20,27 +20,32 @@ namespace Core.MarketAnalyzer
|
|||
public static double GetMainCurrencyPrice(string mainMarket, PTMagicConfiguration systemConfiguration, LogHelper log)
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
try
|
||||
if (mainMarket != "USD")
|
||||
{
|
||||
string baseUrl = "https://api.binance.us/api/v1/ticker/24hr?symbol=" + mainMarket + "USDT";
|
||||
|
||||
log.DoLogInfo("BinanceUS - Getting main market price...");
|
||||
Newtonsoft.Json.Linq.JObject jsonObject = GetSimpleJsonObjectFromURL(baseUrl, log, null);
|
||||
if (jsonObject != null)
|
||||
try
|
||||
{
|
||||
log.DoLogInfo("BinanceUS - Market data received for " + mainMarket + "USDT");
|
||||
string baseUrl = "https://api.binance.us/api/v1/ticker/24hr?symbol=" + mainMarket + "USDT";
|
||||
|
||||
result = (double)jsonObject.GetValue("lastPrice");
|
||||
log.DoLogInfo("BinanceUS - Current price for " + mainMarket + "USDT: " + result.ToString("#,#0.00") + " USD");
|
||||
log.DoLogInfo("BinanceUS - Getting main market price...");
|
||||
Newtonsoft.Json.Linq.JObject jsonObject = GetSimpleJsonObjectFromURL(baseUrl, log, null);
|
||||
if (jsonObject != null)
|
||||
{
|
||||
log.DoLogInfo("BinanceUS - Market data received for " + mainMarket + "USDT");
|
||||
|
||||
result = (double)jsonObject.GetValue("lastPrice");
|
||||
log.DoLogInfo("BinanceUS - Current price for " + mainMarket + "USDT: " + result.ToString("#,#0.00") + " USD");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.DoLogCritical(ex.Message, ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.DoLogCritical(ex.Message, ex);
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<string> GetMarketData(string mainMarket, Dictionary<string, MarketInfo> marketInfos, PTMagicConfiguration systemConfiguration, LogHelper log)
|
||||
|
@ -58,7 +63,7 @@ namespace Core.MarketAnalyzer
|
|||
if (jsonArray.Count > 0)
|
||||
{
|
||||
double mainCurrencyPrice = 1;
|
||||
if (!mainMarket.Equals("USDT", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!mainMarket.Equals("USDT", StringComparison.InvariantCultureIgnoreCase) && !mainMarket.Equals("USD", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
mainCurrencyPrice = BinanceUS.GetMainCurrencyPrice(mainMarket, systemConfiguration, log);
|
||||
}
|
||||
|
@ -238,40 +243,45 @@ namespace Core.MarketAnalyzer
|
|||
}
|
||||
|
||||
bool go = true;
|
||||
while (ticksFetched < ticksNeeded && go)
|
||||
if (!(marketName == "USDUSDT"))
|
||||
{
|
||||
baseUrl = "https://api.binance.us/api/v1/klines?interval=1m&symbol=" + marketName + "&endTime=" + endTime.ToString() + "&limit=" + ticksLimit.ToString();
|
||||
|
||||
log.DoLogDebug("BinanceUS - Getting " + ticksLimit.ToString() + " ticks for '" + marketName + "'...");
|
||||
Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log);
|
||||
if (jsonArray.Count > 0)
|
||||
while (ticksFetched < ticksNeeded && go)
|
||||
{
|
||||
log.DoLogDebug("BinanceUS - " + jsonArray.Count.ToString() + " ticks received.");
|
||||
|
||||
baseUrl = "https://api.binance.us/api/v1/klines?interval=1m&symbol=" + marketName + "&endTime=" + endTime.ToString() + "&limit=" + ticksLimit.ToString();
|
||||
|
||||
foreach (Newtonsoft.Json.Linq.JArray marketTick in jsonArray)
|
||||
log.DoLogDebug("BinanceUS - Getting " + ticksLimit.ToString() + " ticks for '" + marketName + "'...");
|
||||
Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log);
|
||||
if (jsonArray.Count > 0)
|
||||
{
|
||||
log.DoLogDebug("BinanceUS - " + jsonArray.Count.ToString() + " ticks received.");
|
||||
|
||||
MarketTick tick = new MarketTick();
|
||||
tick.Price = (double)marketTick[4];
|
||||
tick.Volume24h = (double)marketTick[7];
|
||||
tick.Time = Constants.Epoch.AddMilliseconds((Int64)marketTick[0]);
|
||||
foreach (Newtonsoft.Json.Linq.JArray marketTick in jsonArray)
|
||||
{
|
||||
|
||||
result.Add(tick);
|
||||
MarketTick tick = new MarketTick();
|
||||
tick.Price = (double)marketTick[4];
|
||||
tick.Volume24h = (double)marketTick[7];
|
||||
tick.Time = Constants.Epoch.AddMilliseconds((Int64)marketTick[0]);
|
||||
|
||||
result.Add(tick);
|
||||
}
|
||||
|
||||
ticksFetched = ticksFetched + jsonArray.Count;
|
||||
endTime = endTime - ticksLimit * 60 * 1000;
|
||||
if (ticksNeeded - ticksFetched < ticksLimit)
|
||||
{
|
||||
ticksLimit = ticksNeeded - ticksFetched;
|
||||
}
|
||||
}
|
||||
|
||||
ticksFetched = ticksFetched + jsonArray.Count;
|
||||
endTime = endTime - ticksLimit * 60 * 1000;
|
||||
if (ticksNeeded - ticksFetched < ticksLimit)
|
||||
else
|
||||
{
|
||||
ticksLimit = ticksNeeded - ticksFetched;
|
||||
log.DoLogDebug("BinanceUS - No ticks received.");
|
||||
go = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.DoLogDebug("BinanceUS - No ticks received.");
|
||||
go = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
|
|
|
@ -1,222 +1,212 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Core.Main;
|
||||
using Core.Helper;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Core.ProfitTrailer
|
||||
{
|
||||
public class OperandToken : Token
|
||||
{
|
||||
}
|
||||
public class OrToken : OperandToken
|
||||
{
|
||||
}
|
||||
|
||||
public class AndToken : OperandToken
|
||||
{
|
||||
}
|
||||
|
||||
public class BooleanValueToken : Token
|
||||
{
|
||||
}
|
||||
|
||||
public class FalseToken : BooleanValueToken
|
||||
{
|
||||
}
|
||||
|
||||
public class TrueToken : BooleanValueToken
|
||||
{
|
||||
}
|
||||
|
||||
public class ParenthesisToken : Token
|
||||
{
|
||||
}
|
||||
|
||||
public class ClosedParenthesisToken : ParenthesisToken
|
||||
{
|
||||
}
|
||||
|
||||
public class OpenParenthesisToken : ParenthesisToken
|
||||
{
|
||||
}
|
||||
|
||||
public class NegationToken : Token
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class Token
|
||||
{
|
||||
}
|
||||
|
||||
public class Tokenizer
|
||||
{
|
||||
private readonly StringReader _reader;
|
||||
private string _text;
|
||||
|
||||
public Tokenizer(string text)
|
||||
{
|
||||
}
|
||||
public class OrToken : OperandToken
|
||||
{
|
||||
_text = text;
|
||||
_reader = new StringReader(text);
|
||||
}
|
||||
|
||||
public class AndToken : OperandToken
|
||||
public IEnumerable<Token> Tokenize()
|
||||
{
|
||||
}
|
||||
|
||||
public class BooleanValueToken : Token
|
||||
{
|
||||
}
|
||||
|
||||
public class FalseToken : BooleanValueToken
|
||||
{
|
||||
}
|
||||
|
||||
public class TrueToken : BooleanValueToken
|
||||
{
|
||||
}
|
||||
|
||||
public class ParenthesisToken : Token
|
||||
{
|
||||
}
|
||||
|
||||
public class ClosedParenthesisToken : ParenthesisToken
|
||||
{
|
||||
}
|
||||
|
||||
public class OpenParenthesisToken : ParenthesisToken
|
||||
{
|
||||
}
|
||||
|
||||
public class NegationToken : Token
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class Token
|
||||
{
|
||||
}
|
||||
|
||||
public class Tokenizer
|
||||
{
|
||||
private readonly StringReader _reader;
|
||||
private string _text;
|
||||
|
||||
public Tokenizer(string text)
|
||||
var tokens = new List<Token>();
|
||||
while (_reader.Peek() != -1)
|
||||
{
|
||||
while (Char.IsWhiteSpace((char)_reader.Peek()))
|
||||
{
|
||||
_text = text;
|
||||
_reader = new StringReader(text);
|
||||
_reader.Read();
|
||||
}
|
||||
|
||||
public IEnumerable<Token> Tokenize()
|
||||
if (_reader.Peek() == -1)
|
||||
break;
|
||||
|
||||
var c = (char)_reader.Peek();
|
||||
switch (c)
|
||||
{
|
||||
var tokens = new List<Token>();
|
||||
while (_reader.Peek() != -1)
|
||||
case '!':
|
||||
tokens.Add(new NegationToken());
|
||||
_reader.Read();
|
||||
break;
|
||||
case '(':
|
||||
tokens.Add(new OpenParenthesisToken());
|
||||
_reader.Read();
|
||||
break;
|
||||
case ')':
|
||||
tokens.Add(new ClosedParenthesisToken());
|
||||
_reader.Read();
|
||||
break;
|
||||
default:
|
||||
if (Char.IsLetter(c))
|
||||
{
|
||||
while (Char.IsWhiteSpace((char) _reader.Peek()))
|
||||
{
|
||||
_reader.Read();
|
||||
}
|
||||
|
||||
if (_reader.Peek() == -1)
|
||||
break;
|
||||
|
||||
var c = (char) _reader.Peek();
|
||||
switch (c)
|
||||
{
|
||||
case '!':
|
||||
tokens.Add(new NegationToken());
|
||||
_reader.Read();
|
||||
break;
|
||||
case '(':
|
||||
tokens.Add(new OpenParenthesisToken());
|
||||
_reader.Read();
|
||||
break;
|
||||
case ')':
|
||||
tokens.Add(new ClosedParenthesisToken());
|
||||
_reader.Read();
|
||||
break;
|
||||
default:
|
||||
if (Char.IsLetter(c))
|
||||
{
|
||||
var token = ParseKeyword();
|
||||
tokens.Add(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
var remainingText = _reader.ReadToEnd() ?? string.Empty;
|
||||
throw new Exception(string.Format("Unknown grammar found at position {0} : '{1}'", _text.Length - remainingText.Length, remainingText));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private Token ParseKeyword()
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
while (Char.IsLetter((char) _reader.Peek()))
|
||||
{
|
||||
text.Append((char) _reader.Read());
|
||||
}
|
||||
|
||||
var potentialKeyword = text.ToString().ToLower();
|
||||
|
||||
switch (potentialKeyword)
|
||||
{
|
||||
case "true":
|
||||
return new TrueToken();
|
||||
case "false":
|
||||
return new FalseToken();
|
||||
case "and":
|
||||
return new AndToken();
|
||||
case "or":
|
||||
return new OrToken();
|
||||
default:
|
||||
throw new Exception("Expected keyword (True, False, and, or) but found "+ potentialKeyword);
|
||||
var token = ParseKeyword();
|
||||
tokens.Add(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
var remainingText = _reader.ReadToEnd() ?? string.Empty;
|
||||
throw new Exception(string.Format("Unknown grammar found at position {0} : '{1}'", _text.Length - remainingText.Length, remainingText));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
public class Parser
|
||||
|
||||
private Token ParseKeyword()
|
||||
{
|
||||
private readonly IEnumerator<Token> _tokens;
|
||||
var text = new StringBuilder();
|
||||
while (Char.IsLetter((char)_reader.Peek()))
|
||||
{
|
||||
text.Append((char)_reader.Read());
|
||||
}
|
||||
|
||||
public Parser(IEnumerable<Token> tokens)
|
||||
{
|
||||
_tokens = tokens.GetEnumerator();
|
||||
_tokens.MoveNext();
|
||||
}
|
||||
var potentialKeyword = text.ToString().ToLower();
|
||||
|
||||
public bool Parse()
|
||||
{
|
||||
while (_tokens.Current != null)
|
||||
{
|
||||
var isNegated = _tokens.Current is NegationToken;
|
||||
if (isNegated)
|
||||
_tokens.MoveNext();
|
||||
|
||||
var boolean = ParseBoolean();
|
||||
if (isNegated)
|
||||
boolean = !boolean;
|
||||
|
||||
while (_tokens.Current is OperandToken)
|
||||
{
|
||||
var operand = _tokens.Current;
|
||||
if (!_tokens.MoveNext())
|
||||
{
|
||||
throw new Exception("Missing expression after operand");
|
||||
}
|
||||
var nextBoolean = ParseBoolean();
|
||||
|
||||
if (operand is AndToken)
|
||||
boolean = boolean && nextBoolean;
|
||||
else
|
||||
boolean = boolean || nextBoolean;
|
||||
|
||||
}
|
||||
|
||||
return boolean;
|
||||
}
|
||||
|
||||
throw new Exception("Empty expression");
|
||||
}
|
||||
|
||||
private bool ParseBoolean()
|
||||
{
|
||||
if (_tokens.Current is BooleanValueToken)
|
||||
{
|
||||
var current = _tokens.Current;
|
||||
_tokens.MoveNext();
|
||||
|
||||
if (current is TrueToken)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
if (_tokens.Current is OpenParenthesisToken)
|
||||
{
|
||||
_tokens.MoveNext();
|
||||
|
||||
var expInPars = Parse();
|
||||
|
||||
if (!(_tokens.Current is ClosedParenthesisToken))
|
||||
throw new Exception("Expecting Closing Parenthesis");
|
||||
|
||||
_tokens.MoveNext();
|
||||
|
||||
return expInPars;
|
||||
}
|
||||
if (_tokens.Current is ClosedParenthesisToken)
|
||||
throw new Exception("Unexpected Closed Parenthesis");
|
||||
|
||||
// since its not a BooleanConstant or Expression in parenthesis, it must be a expression again
|
||||
var val = Parse();
|
||||
return val;
|
||||
}
|
||||
switch (potentialKeyword)
|
||||
{
|
||||
case "true":
|
||||
return new TrueToken();
|
||||
case "false":
|
||||
return new FalseToken();
|
||||
case "and":
|
||||
return new AndToken();
|
||||
case "or":
|
||||
return new OrToken();
|
||||
default:
|
||||
throw new Exception("Expected keyword (True, False, and, or) but found " + potentialKeyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class Parser
|
||||
{
|
||||
private readonly IEnumerator<Token> _tokens;
|
||||
|
||||
public Parser(IEnumerable<Token> tokens)
|
||||
{
|
||||
_tokens = tokens.GetEnumerator();
|
||||
_tokens.MoveNext();
|
||||
}
|
||||
|
||||
public bool Parse()
|
||||
{
|
||||
while (_tokens.Current != null)
|
||||
{
|
||||
var isNegated = _tokens.Current is NegationToken;
|
||||
if (isNegated)
|
||||
_tokens.MoveNext();
|
||||
|
||||
var boolean = ParseBoolean();
|
||||
if (isNegated)
|
||||
boolean = !boolean;
|
||||
|
||||
while (_tokens.Current is OperandToken)
|
||||
{
|
||||
var operand = _tokens.Current;
|
||||
if (!_tokens.MoveNext())
|
||||
{
|
||||
throw new Exception("Missing expression after operand");
|
||||
}
|
||||
var nextBoolean = ParseBoolean();
|
||||
|
||||
if (operand is AndToken)
|
||||
boolean = boolean && nextBoolean;
|
||||
else
|
||||
boolean = boolean || nextBoolean;
|
||||
}
|
||||
return boolean;
|
||||
}
|
||||
throw new Exception("Empty expression");
|
||||
}
|
||||
|
||||
private bool ParseBoolean()
|
||||
{
|
||||
if (_tokens.Current is BooleanValueToken)
|
||||
{
|
||||
var current = _tokens.Current;
|
||||
_tokens.MoveNext();
|
||||
|
||||
if (current is TrueToken)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
if (_tokens.Current is OpenParenthesisToken)
|
||||
{
|
||||
_tokens.MoveNext();
|
||||
|
||||
var expInPars = Parse();
|
||||
|
||||
if (!(_tokens.Current is ClosedParenthesisToken))
|
||||
throw new Exception("Expecting Closing Parenthesis");
|
||||
|
||||
_tokens.MoveNext();
|
||||
|
||||
return expInPars;
|
||||
}
|
||||
if (_tokens.Current is ClosedParenthesisToken)
|
||||
throw new Exception("Unexpected Closed Parenthesis");
|
||||
|
||||
// since its not a BooleanConstant or Expression in parenthesis, it must be a expression again
|
||||
var val = Parse();
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StrategyHelper
|
||||
{
|
||||
|
@ -234,29 +224,33 @@ namespace Core.ProfitTrailer
|
|||
{
|
||||
result = "";
|
||||
}
|
||||
|
||||
// strategy labels that are variable, so can't be caught by the switch statement
|
||||
// strategy labels that are variable value
|
||||
if (result.Contains("REBUY"))
|
||||
{
|
||||
time = strategyName.Remove(0,14);
|
||||
time = strategyName.Remove(0, 14);
|
||||
result = "REBUY " + time;
|
||||
}
|
||||
if (result.Contains("CHANGE PERC"))
|
||||
{
|
||||
result = "CHANGE";
|
||||
}
|
||||
if (result.Contains("LEVERAGE"))
|
||||
if (result.Contains("CROSSED"))
|
||||
{
|
||||
leverage = strategyName.Remove(0,10);
|
||||
leverage = leverage.Remove(leverage.Length -1, 1);
|
||||
result = leverage + " X";
|
||||
leverage = strategyName.Remove(0, 9);
|
||||
leverage = leverage.Remove(leverage.Length - 1, 1);
|
||||
result = "CROSS " + leverage + "X";
|
||||
}
|
||||
|
||||
// buy/sell strategies beginning with PT 2.3.3 contain the stragegy designation letter followed by a colon and space.
|
||||
if (result.Contains("ISOLATED"))
|
||||
{
|
||||
leverage = strategyName.Remove(0, 10);
|
||||
leverage = leverage.Remove(leverage.Length - 1, 1);
|
||||
result = "ISOL " + leverage + "X";
|
||||
}
|
||||
// buy/sell strategies beginning with PT 2.3.3 contain the strategy designation letter followed by a colon and space.
|
||||
// remove the letter and colon, change to shortcut, then reapply the letter and colon
|
||||
if (strategyName.Contains(":"))
|
||||
{
|
||||
int strategyLength = strategyName.Length-3;
|
||||
int strategyLength = strategyName.Length - 3;
|
||||
strategyLetter = strategyName.Remove(3, strategyLength);
|
||||
strategyNameOnly = strategyName.Remove(0, 3);
|
||||
}
|
||||
|
@ -275,40 +269,40 @@ namespace Core.ProfitTrailer
|
|||
result = String.Concat(strategyLetter, "LOSS");
|
||||
break;
|
||||
case "smagain":
|
||||
result = String.Concat(strategyLetter, "SMAG");
|
||||
result = String.Concat(strategyLetter, "SMA-G");
|
||||
break;
|
||||
case "emagain":
|
||||
result = String.Concat(strategyLetter, "EMAG");
|
||||
result = String.Concat(strategyLetter, "EMA-G");
|
||||
break;
|
||||
case "hmagain":
|
||||
result = String.Concat(strategyLetter, "HMAG");
|
||||
result = String.Concat(strategyLetter, "HMA-G");
|
||||
break;
|
||||
case "dmagain":
|
||||
result = String.Concat(strategyLetter, "DMAG");
|
||||
result = String.Concat(strategyLetter, "DMA-G");
|
||||
break;
|
||||
case "smaspread":
|
||||
result = String.Concat(strategyLetter, "SMAS");
|
||||
result = String.Concat(strategyLetter, "SMA-S");
|
||||
break;
|
||||
case "emaspread":
|
||||
result = String.Concat(strategyLetter, "EMAS");
|
||||
result = String.Concat(strategyLetter, "EMA-S");
|
||||
break;
|
||||
case "hmaspread":
|
||||
result = String.Concat(strategyLetter, "HMAS");
|
||||
result = String.Concat(strategyLetter, "HMA-S");
|
||||
break;
|
||||
case "dmaspread":
|
||||
result = String.Concat(strategyLetter, "DMAS");
|
||||
result = String.Concat(strategyLetter, "DMA-S");
|
||||
break;
|
||||
case "smacross":
|
||||
result = String.Concat(strategyLetter, "SMAC");
|
||||
result = String.Concat(strategyLetter, "SMA-C");
|
||||
break;
|
||||
case "emacross":
|
||||
result = String.Concat(strategyLetter, "EMAC");
|
||||
result = String.Concat(strategyLetter, "EMA-C");
|
||||
break;
|
||||
case "hmacross":
|
||||
result = String.Concat(strategyLetter, "HMAC");
|
||||
result = String.Concat(strategyLetter, "HMA-C");
|
||||
break;
|
||||
case "dmacross":
|
||||
result = String.Concat(strategyLetter, "DMAC");
|
||||
result = String.Concat(strategyLetter, "DMA-C");
|
||||
break;
|
||||
case "rsi":
|
||||
result = String.Concat(strategyLetter, "RSI");
|
||||
|
@ -320,13 +314,13 @@ namespace Core.ProfitTrailer
|
|||
result = String.Concat(strategyLetter, "SRSI");
|
||||
break;
|
||||
case "stochrsik":
|
||||
result = String.Concat(strategyLetter, "SRSIK");
|
||||
result = String.Concat(strategyLetter, "SRSI-K");
|
||||
break;
|
||||
case "stochrsid":
|
||||
result = String.Concat(strategyLetter, "SRSID");
|
||||
result = String.Concat(strategyLetter, "SRSI-D");
|
||||
break;
|
||||
case "stochrsicross":
|
||||
result = String.Concat(strategyLetter, "SRSIC");
|
||||
result = String.Concat(strategyLetter, "SRSI-C");
|
||||
break;
|
||||
case "macd":
|
||||
result = String.Concat(strategyLetter, "MACD");
|
||||
|
@ -365,19 +359,19 @@ namespace Core.ProfitTrailer
|
|||
result = String.Concat(strategyLetter, "FIXED");
|
||||
break;
|
||||
case "lowatrband":
|
||||
result = String.Concat(strategyLetter, "LATR");
|
||||
result = String.Concat(strategyLetter, "L-ATR");
|
||||
break;
|
||||
case "highatrband":
|
||||
result = String.Concat(strategyLetter, "HATR");
|
||||
result = String.Concat(strategyLetter, "H-ATR");
|
||||
break;
|
||||
case "atrpercentage":
|
||||
result = String.Concat(strategyLetter, "ATRPCT");
|
||||
result = String.Concat(strategyLetter, "ATR-PCT");
|
||||
break;
|
||||
case "vwappercentage":
|
||||
result = String.Concat(strategyLetter, "VWAP");
|
||||
break;
|
||||
case "mvwappercentage":
|
||||
result = String.Concat(strategyLetter, "MVWAP");
|
||||
result = String.Concat(strategyLetter, "M-VWAP");
|
||||
break;
|
||||
case "btcdominance":
|
||||
result = String.Concat(strategyLetter, "BTCDOM");
|
||||
|
@ -430,10 +424,21 @@ namespace Core.ProfitTrailer
|
|||
case "no dca buy logic":
|
||||
result = String.Concat(strategyLetter, "NODCA");
|
||||
break;
|
||||
case "combimagain":
|
||||
result = String.Concat(strategyLetter, "COMBI-G");
|
||||
break;
|
||||
case "combimaspread":
|
||||
result = String.Concat(strategyLetter, "COMBI-S");
|
||||
break;
|
||||
case "combimacross":
|
||||
result = String.Concat(strategyLetter, "COMBI-C");
|
||||
break;
|
||||
case "macdpercentage":
|
||||
result = String.Concat(strategyLetter, "MACDPERC");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (onlyValidStrategies)
|
||||
{
|
||||
if (strategyName.IndexOf("SOM") > -1 || strategyName.IndexOf("MAX") > -1 || strategyName.IndexOf("MIN") > -1 || strategyName.IndexOf("PRICE") > -1 || strategyName.IndexOf("BLACK") > -1 || strategyName.IndexOf("INSUFFICIENT") > -1 || strategyName.IndexOf("COST") > -1)
|
||||
|
@ -441,7 +446,6 @@ namespace Core.ProfitTrailer
|
|||
result = "";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -453,14 +457,11 @@ namespace Core.ProfitTrailer
|
|||
public static bool IsValidStrategy(string strategyName, bool checkForAnyInvalid)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// buy/sell strategies beginning with PT 2.3.3 contain the letter followed by a colon and space.
|
||||
if (strategyName.Contains(":"))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
// Prior to PT 2.3.3
|
||||
if (!checkForAnyInvalid)
|
||||
{
|
||||
switch (strategyName.ToLower())
|
||||
|
@ -507,6 +508,10 @@ namespace Core.ProfitTrailer
|
|||
case "vwappercentage":
|
||||
case "mvwappercentage":
|
||||
case "btcdominance":
|
||||
case "combimagain":
|
||||
case "combimaspread":
|
||||
case "combimacross":
|
||||
case "macdpercentage":
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
|
@ -529,14 +534,11 @@ namespace Core.ProfitTrailer
|
|||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int GetStrategyValueDecimals(string strategyName)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
switch (strategyName.ToLower())
|
||||
{
|
||||
case "lowbb":
|
||||
|
@ -575,45 +577,76 @@ namespace Core.ProfitTrailer
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetStrategyText(Summary summary, List<Strategy> strategies, string strategyText, bool isTrue, bool isTrailingBuyActive)
|
||||
{
|
||||
{
|
||||
bool isValidStrategy = false;
|
||||
Regex regx = new Regex(@"[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", RegexOptions.Compiled);
|
||||
|
||||
if (strategies.Count > 0)
|
||||
{
|
||||
foreach (Strategy strategy in strategies)
|
||||
{
|
||||
string textClass = (strategy.IsTrue) ? "label-success" : "label-danger";
|
||||
|
||||
isValidStrategy = StrategyHelper.IsValidStrategy(strategy.Name);
|
||||
|
||||
if (!isValidStrategy )
|
||||
if (!isValidStrategy)
|
||||
{
|
||||
// Parse Formulas
|
||||
if (strategy.Name.Contains("FORMULA") && !strategy.Name.Contains("STATS"))
|
||||
|
||||
if (strategy.Name.Contains("TRIGGERED"))
|
||||
// remove levels already triggered, to show only currently waiting trigger
|
||||
{
|
||||
string expression = strategy.Name.Remove(0, 10);
|
||||
expression = expression.Replace("<span class=\"tdgreen\">","true").Replace("<span class=\"red\">","false").Replace("</span>","").Replace("&&","and").Replace("||","or");
|
||||
expression = Regex.Replace(expression, @"[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", String.Empty);
|
||||
var tokens = new Tokenizer(expression).Tokenize();
|
||||
var parser = new Parser(tokens);
|
||||
if (parser.Parse()) {
|
||||
strategyText += "<span class=\"label label-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
||||
strategyText += "";
|
||||
}
|
||||
else if (strategy.Name.Contains("STATS"))
|
||||
// avoid parsing advanced buy stats
|
||||
{
|
||||
strategy.Name = "";
|
||||
}
|
||||
else if (strategy.Name.Contains("FORMULA"))
|
||||
// Parse Various PT Formulas
|
||||
{
|
||||
if (strategy.Name.Contains("LEVEL"))
|
||||
// level X
|
||||
{
|
||||
string level = strategy.Name.Substring(5, 2);
|
||||
string expression = strategy.Name.Remove(0, 17);
|
||||
expression = expression.Replace("<span class=\"tdgreen\">", "true").Replace("<span class=\"red\">", "false").Replace("</span>", "").Replace("&&", "and").Replace("||", "or");
|
||||
expression = regx.Replace(expression, String.Empty);
|
||||
var tokens = new Tokenizer(expression).Tokenize();
|
||||
var parser = new Parser(tokens);
|
||||
if (parser.Parse())
|
||||
{
|
||||
strategyText += "<span class=\"label label-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"LEVEL FORMULA\">L " + level + "</span> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
strategyText += "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"LEVEL FORMULA\">L " + level + "</span> ";
|
||||
}
|
||||
}
|
||||
else
|
||||
// standard formula
|
||||
{
|
||||
strategyText += "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
||||
string expression = strategy.Name.Remove(0, 10);
|
||||
expression = expression.Replace("<span class=\"tdgreen\">", "true").Replace("<span class=\"red\">", "false").Replace("</span>", "").Replace("&&", "and").Replace("||", "or");
|
||||
expression = regx.Replace(expression, String.Empty);
|
||||
var tokens = new Tokenizer(expression).Tokenize();
|
||||
var parser = new Parser(tokens);
|
||||
if (parser.Parse())
|
||||
{
|
||||
strategyText += "<span class=\"label label-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">FORM</span> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
strategyText += "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">FORM</span> ";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
strategyText += "<span class=\"label label-warning\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategy.Name + "\">" + StrategyHelper.GetStrategyShortcut(strategy.Name, false) + "</span> ";
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -639,14 +672,11 @@ namespace Core.ProfitTrailer
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
isValidStrategy = StrategyHelper.IsValidStrategy(strategyText);
|
||||
|
||||
if (isValidStrategy)
|
||||
{
|
||||
strategyText = "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategyText + "\">" + StrategyHelper.GetStrategyShortcut(strategyText, true) + "</span>";
|
||||
}
|
||||
|
||||
else if (strategyText.Equals("") && isValidStrategy == false)
|
||||
{
|
||||
strategyText = "<span class=\"label label-muted\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Not Applicable: Not using DCA!\"></span>";
|
||||
|
@ -657,10 +687,8 @@ namespace Core.ProfitTrailer
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strategyText;
|
||||
}
|
||||
|
||||
public static string GetCurrentValueText(List<Strategy> strategies, string strategyText, double bbValue, double simpleValue, bool includeShortcut)
|
||||
{
|
||||
string result = "";
|
||||
|
@ -721,14 +749,12 @@ namespace Core.ProfitTrailer
|
|||
result = simpleValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetTriggerValueText(Summary summary, List<Strategy> strategies, string strategyText, double bbValue, double simpleValue, int buyLevel, bool includeShortcut)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (strategies.Count > 0)
|
||||
{
|
||||
foreach (Strategy strategy in strategies)
|
||||
|
@ -743,12 +769,10 @@ namespace Core.ProfitTrailer
|
|||
{
|
||||
decimalFormat += "0";
|
||||
}
|
||||
|
||||
if (includeShortcut)
|
||||
{
|
||||
result += "<span class=\"text-muted\">" + StrategyHelper.GetStrategyShortcut(strategy.Name, true) + "</span> ";
|
||||
}
|
||||
|
||||
if (StrategyHelper.GetStrategyShortcut(strategy.Name, true).IndexOf("and", StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||
{
|
||||
result += strategy.TriggerValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
|
@ -792,7 +816,6 @@ namespace Core.ProfitTrailer
|
|||
result = simpleValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,16 +10,12 @@
|
|||
<None Remove="wwwroot\assets\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="wwwroot\assets\css\custom.css" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\img\qr-btc.png" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\img\qr-eth.png" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\img\qr-ltc.png" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\img\qr-neo.png" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\js\custom.js" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\js\analyzer-settings.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="wwwroot\assets\js\dca.js" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\img\**" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\css\**" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\fonts\**" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\pages\**" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\plugins\**" CopyToOutputDirectory="Always" />
|
||||
<Content Include="wwwroot\assets\js\**" CopyToOutputDirectory="Always" />
|
||||
<None Include="nlog.config" CopyToOutputDirectory="Always" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -8,8 +8,20 @@
|
|||
<style type="text/css" media="screen">
|
||||
|
||||
#editor {
|
||||
height: 500px;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@media (min-height: 1000px) {
|
||||
#editor {
|
||||
height: 750px;
|
||||
}
|
||||
}
|
||||
|
||||
@@media (min-height: 1250px) {
|
||||
#editor {
|
||||
height: 1000px;
|
||||
}
|
||||
}
|
||||
|
||||
#preset-file {
|
||||
|
@ -58,7 +70,7 @@
|
|||
<form class="form-horizontal" method="post">
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modalEditPresetFile" tabindex="-1" role="dialog" aria-labelledby="modalEditPresetFileTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalEditPresetFileTitle"></h5>
|
||||
|
@ -84,10 +96,12 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
// Setup UI
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
$('.btn-edit-presetfile').click(function () {
|
||||
$('.btn-edit-presetfile').click(function () {
|
||||
// Setup UI
|
||||
var settingName = $(this).data('settingname');
|
||||
var dataTarget = $(this).data('datatarget');
|
||||
|
||||
|
@ -103,6 +117,11 @@
|
|||
} else if (responseText == 'returntologin') {
|
||||
window.location.replace("@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)Login");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set ACE editor language mode.
|
||||
window.editor.session.setMode("ace/mode/yaml");
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Collections.Generic;
|
||||
using Core.Main;
|
||||
using Core.Helper;
|
||||
using Core.Main.DataObjects.PTMagicData;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Monitor.Pages
|
||||
{
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
<thead>
|
||||
<tr>
|
||||
@{
|
||||
double currentBalance = Model.PTData.GetCurrentBalance();
|
||||
string currentBalanceString = currentBalance.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||
if (currentBalance > 100) {
|
||||
currentBalanceString = Math.Round(currentBalance, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||
if (Model.totalCurrentValue > 100)
|
||||
{
|
||||
totalCurrentValueString = Math.Round(Model.totalCurrentValue, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
}
|
||||
}
|
||||
<th class="m-t-0 header-title text-left">Account Value: <text class="text-autocolor"> @currentBalanceString @Model.Summary.MainMarket </text> <small> <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="This is based on your sales history, entries on the Transactions page and any currently held positions."></i></small></th>
|
||||
<th class="m-t-0 header-title text-left">Total 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.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>
|
||||
</thead>
|
||||
|
@ -59,16 +59,21 @@
|
|||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
|
||||
<h4 class="m-t-0 header-title">Sales Analysis</h4>
|
||||
|
||||
@{
|
||||
double totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
||||
double totalProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
||||
}
|
||||
double totalProfitFiat = Math.Round(totalProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double percentGain = Math.Round(totalProfit / Model.PTMagicConfiguration.GeneralSettings.Application.StartBalance * 100, 2);
|
||||
double avgDailyGain = Model.DailyGains.Values.Average(dg => dg);
|
||||
double avgMonthlyGain = Model.MonthlyGains.Values.Average(dg => dg);
|
||||
|
||||
string percentGainText = percentGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
||||
if (Model.PTData.TransactionData.Transactions.Count > 0) {
|
||||
percentGainText = "<i class=\"fa fa-info-circle text-muted\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"You have added at least one manual transaction, so the total gain percentage cannot be calculated.\"></i>";
|
||||
|
@ -123,9 +128,7 @@
|
|||
double estimatedBalance6Months = Math.Round(currentTotalBalance * Math.Pow((1 + (avgDailyGain / 100)), 180.0), 8);
|
||||
double estimatedBalance1Year = Math.Round(currentTotalBalance * 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>
|
||||
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -188,7 +191,6 @@
|
|||
<div class="col-md-6">
|
||||
<div class="card-box">
|
||||
<h4 class="m-t-0 header-title">Last @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDailySummaries days</h4>
|
||||
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -202,7 +204,15 @@
|
|||
<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);
|
||||
double salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
||||
double salesDateProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
||||
}
|
||||
double salesDateProfitFiat = Math.Round(salesDateProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double salesDateStartBalance = Model.PTData.GetSnapshotBalance(salesDate);
|
||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
||||
|
@ -241,11 +251,18 @@
|
|||
}
|
||||
@for (DateTime salesMonthDate = salesMonthStartDate.Date; salesMonthDate >= Model.DateTimeNow.DateTime.AddMonths(-Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxMonthlySummaries) && salesMonthDate >= minSellLogMonthDate; salesMonthDate = salesMonthDate.AddMonths(-1)) {
|
||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> salesMonthSales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date.Month == salesMonthDate.Month && sl.SoldDate.Date.Year == salesMonthDate.Year);
|
||||
double salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
||||
double salesDateProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
||||
}
|
||||
double salesDateProfitFiat = Math.Round(salesDateProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double salesDateStartBalance = Model.PTData.GetSnapshotBalance(salesMonthDate);
|
||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
||||
|
||||
double salesDateAVGDailyGain = 0;
|
||||
double monthDailyProfit = 0;
|
||||
int days = 0;
|
||||
|
@ -254,7 +271,15 @@
|
|||
if (monthDay <= Model.DateTimeNow) {
|
||||
days++;
|
||||
List<Core.Main.DataObjects.PTMagicData.SellLogData> monthDaySales = Model.PTData.SellLog.FindAll(sl => sl.SoldDate.Date == monthDay.Date);
|
||||
double monthDayProfit = monthDaySales.Sum(sl => sl.Profit);
|
||||
double monthDayProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
monthDayProfit = monthDaySales.Sum(sl => sl.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
monthDayProfit = monthDaySales.Sum(sl => sl.Profit);
|
||||
}
|
||||
double monthDayStartBalance = Model.PTData.GetSnapshotBalance(monthDay);
|
||||
monthDailyProfit += Math.Round(monthDayProfit / monthDayStartBalance * 100, 2);
|
||||
}
|
||||
|
@ -278,9 +303,7 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card-box">
|
||||
|
||||
<h4 class="m-t-0 header-title"><b>Top @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets Sales Market Analysis</b></h4>
|
||||
|
||||
<table class="tablesaw table m-b-0" data-tablesaw-sortable data-tablesaw-sortable-switch>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -296,6 +319,10 @@
|
|||
<tbody>
|
||||
@{
|
||||
var topMarkets = Model.PTData.SellLog.GroupBy(m => m.Market).Select(mg => mg.Sum(m => m.Profit));
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
topMarkets = Model.PTData.SellLog.GroupBy(m => m.Market).Select(mg => mg.Sum(m => m.Profit) * (-1));
|
||||
}
|
||||
int marketRank = 0;
|
||||
}
|
||||
@foreach (KeyValuePair<string, double> marketData in Model.TopMarkets) {
|
||||
|
@ -362,7 +389,6 @@
|
|||
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;
|
||||
});
|
||||
|
||||
|
@ -377,7 +403,6 @@
|
|||
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;
|
||||
});
|
||||
|
||||
|
@ -392,7 +417,6 @@
|
|||
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;
|
||||
});
|
||||
|
||||
|
|
|
@ -20,14 +20,14 @@ namespace Monitor.Pages
|
|||
public Dictionary<DateTime, double> DailyGains = new Dictionary<DateTime, double>();
|
||||
public Dictionary<DateTime, double> MonthlyGains = new Dictionary<DateTime, double>();
|
||||
public DateTimeOffset DateTimeNow = Constants.confMinDate;
|
||||
|
||||
public double totalCurrentValue = 0;
|
||||
public void OnGet()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
BindData();
|
||||
BuildTCV();
|
||||
}
|
||||
|
||||
private void BindData()
|
||||
{
|
||||
PTData = this.PtDataObject;
|
||||
|
@ -39,20 +39,25 @@ namespace Monitor.Pages
|
|||
BuildTopMarkets();
|
||||
BuildSalesChartData();
|
||||
}
|
||||
|
||||
private void BuildTopMarkets()
|
||||
{
|
||||
var markets = PTData.SellLog.GroupBy(m => m.Market);
|
||||
Dictionary<string, double> topMarketsDic = new Dictionary<string, double>();
|
||||
foreach (var market in markets)
|
||||
{
|
||||
double totalProfit = PTData.SellLog.FindAll(m => m.Market == market.Key).Sum(m => m.Profit);
|
||||
|
||||
double totalProfit = 0;
|
||||
if (PTData.Properties.Shorting)
|
||||
{
|
||||
totalProfit = PTData.SellLog.FindAll(m => m.Market == market.Key).Sum(m => m.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
totalProfit = PTData.SellLog.FindAll(m => m.Market == market.Key).Sum(m => m.Profit);
|
||||
}
|
||||
topMarketsDic.Add(market.Key, totalProfit);
|
||||
}
|
||||
TopMarkets = new SortedDictionary<string, double>(topMarketsDic).OrderByDescending(m => m.Value).Take(PTMagicConfiguration.GeneralSettings.Monitor.MaxTopMarkets);
|
||||
}
|
||||
|
||||
private void BuildSalesChartData()
|
||||
{
|
||||
if (PTData.SellLog.Count > 0)
|
||||
|
@ -68,26 +73,29 @@ namespace Monitor.Pages
|
|||
double balance = 0.0;
|
||||
for (DateTime salesDate = graphStartDate; salesDate <= DateTimeNow.DateTime.Date; salesDate = salesDate.AddDays(1))
|
||||
{
|
||||
|
||||
if (tradeDayIndex > 0)
|
||||
{
|
||||
tradesPerDayJSON += ",\n";
|
||||
profitPerDayJSON += ",\n";
|
||||
balancePerDayJSON += ",\n";
|
||||
}
|
||||
|
||||
double profit = 0;
|
||||
int trades = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate.Date).Count;
|
||||
double profit = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate.Date).Sum(t => t.Profit);
|
||||
if (PTData.Properties.Shorting)
|
||||
{
|
||||
profit = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate.Date).Sum(t => t.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
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',";
|
||||
|
@ -111,29 +119,51 @@ namespace Monitor.Pages
|
|||
BalanceChartDataJSON += "values: [" + balancePerDayJSON + "]";
|
||||
BalanceChartDataJSON += "}";
|
||||
BalanceChartDataJSON += "]";
|
||||
|
||||
|
||||
for (DateTime salesDate = DateTimeNow.DateTime.Date; salesDate >= MinSellLogDate; salesDate = salesDate.AddDays(-1))
|
||||
{
|
||||
List<SellLogData> salesDateSales = PTData.SellLog.FindAll(sl => sl.SoldDate.Date == salesDate);
|
||||
double salesDateProfit = salesDateSales.Sum(sl => sl.Profit);
|
||||
double salesDateProfit;
|
||||
if (PTData.Properties.Shorting)
|
||||
{
|
||||
salesDateProfit = salesDateSales.Sum(sl => sl.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
double salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
||||
double salesDateProfit;
|
||||
if (PTData.Properties.Shorting)
|
||||
{
|
||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
salesDateProfit = salesMonthSales.Sum(sl => sl.Profit);
|
||||
}
|
||||
double salesDateStartBalance = PTData.GetSnapshotBalance(salesMonthDate);
|
||||
double salesDateGain = Math.Round(salesDateProfit / salesDateStartBalance * 100, 2);
|
||||
|
||||
MonthlyGains.Add(salesMonthDate, salesDateGain);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void BuildTCV()
|
||||
{
|
||||
double AvailableBalance = PTData.GetCurrentBalance();
|
||||
foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog)
|
||||
{
|
||||
totalCurrentValue = totalCurrentValue + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) / dcaLogEntry.Leverage);
|
||||
}
|
||||
totalCurrentValue = totalCurrentValue + AvailableBalance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,8 +241,9 @@
|
|||
<label class="col-md-4 col-form-label">Link Platform <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The platform to which the pair name will link if you click on it."></i></label>
|
||||
<div class="col-md-8">
|
||||
<select name="Monitor_LinkPlatform" class="form-control">
|
||||
<option selected="@(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform.Equals("TradingView", StringComparison.InvariantCultureIgnoreCase))">TradingView</option>
|
||||
<option selected="@(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform.Equals("Exchange", StringComparison.InvariantCultureIgnoreCase))">Exchange</option>
|
||||
<option selected="@(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform.Equals("TradingView", StringComparison.InvariantCultureIgnoreCase))">TradingView</option>
|
||||
<option selected="@(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform.Equals("TradingViewFutures", StringComparison.InvariantCultureIgnoreCase))">TradingViewFutures</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -209,5 +209,6 @@
|
|||
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/js/jquery.core.js?v=@Html.Raw(Model.CurrentBotVersion)"></script>
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/js/jquery.app.js?v=@Html.Raw(Model.CurrentBotVersion)"></script>
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/js/circlos.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -125,9 +125,9 @@
|
|||
<tr>
|
||||
<td>DCA Buy Strategies</td>
|
||||
@if (buyDisabled) {
|
||||
<td class="text-right text-nowrap">@Html.Raw(buyStrategyText)</td>
|
||||
<td class="text-right text">@Html.Raw(buyStrategyText)</td>
|
||||
} else {
|
||||
<td class="text-right text-nowrap">@Html.Raw(buyStrategyText)</td>
|
||||
<td class="text-right text">@Html.Raw(buyStrategyText)</td>
|
||||
}
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -110,9 +110,9 @@
|
|||
|
||||
// Buy strats
|
||||
@if (buyDisabled) {
|
||||
<td class="text-nowrap">@Html.Raw(buyStrategyText)</td>
|
||||
<td class="text">@Html.Raw(buyStrategyText)</td>
|
||||
} else {
|
||||
<td class="text-nowrap">@Html.Raw(buyStrategyText)</td>
|
||||
<td class="text">@Html.Raw(buyStrategyText)</td>
|
||||
}
|
||||
|
||||
// BS Value
|
||||
|
@ -144,7 +144,7 @@
|
|||
}
|
||||
|
||||
// Sell Strats
|
||||
<td class="text-nowrap">@Html.Raw(sellStrategyText)</td>
|
||||
<td class="text">@Html.Raw(sellStrategyText)</td>
|
||||
|
||||
// SSV
|
||||
<td class="text-right text-nowrap">@Html.Raw(currentSellValueText)</td>
|
||||
|
|
|
@ -10,33 +10,46 @@
|
|||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="col-md-4 px-1">
|
||||
<div class="card-box px-2" style="height:305px;">
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
||||
@if (!Model.TrendChartDataJSON.Equals("")) {
|
||||
<div class="trend-chart">
|
||||
<svg style="height:300px;width:100%"></svg>
|
||||
<svg style="height: 300px;width: 100%;"></svg>
|
||||
</div>
|
||||
} else {
|
||||
<p>Unable to load graph, no market trend data found.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2 px-1">
|
||||
<div class="card-box px-2" style="height:305px;">
|
||||
<div class="col-md-3 px-1">
|
||||
<div class="card-box px-3" style="height:305px;">
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
||||
@{
|
||||
double currentBalance = Model.PTData.GetCurrentBalance();
|
||||
string currentBalanceString = currentBalance.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||
if (currentBalance > 100) {
|
||||
currentBalanceString = Math.Round(currentBalance, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
string totalCurrentValueString = Model.totalCurrentValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
||||
if (Model.totalCurrentValue > 100) {
|
||||
totalCurrentValueString = Math.Round(Model.totalCurrentValue, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
||||
}
|
||||
}
|
||||
<div class="text-center"><small>TCV: <text class="text-autocolor"> @currentBalanceString @Model.Summary.MainMarket </text> </small></div>
|
||||
<div id="AssetDistribution">
|
||||
<svg style="height:290px;width:100%"></svg>
|
||||
}
|
||||
<div id="AssetDistribution" class="container">
|
||||
<div class="text-center">
|
||||
<small>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Starting balance from PTM settings">Start: <text class="text-autocolor"> @Model.PTMagicConfiguration.GeneralSettings.Application.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>
|
||||
</small>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span data-toggle="tooltip" data-placement="top" title="Total current account value">TCV: <text class="text-autocolor"> @totalCurrentValueString @Model.Summary.MainMarket </text> </span>
|
||||
</div>
|
||||
<div class="row px1">
|
||||
<svg style="height:260px;width:100%"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5 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="card-box px-2" style="height:305px;">
|
||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||
<div class="profit-chart">
|
||||
|
@ -48,13 +61,13 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 px-1">
|
||||
<div class="card-box px-2">
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b><small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4>
|
||||
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
||||
<br>
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b>
|
||||
<small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -93,33 +106,77 @@
|
|||
|
||||
<div class="col-md-6 px-1">
|
||||
<div class="card-box px-2">
|
||||
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
|
||||
<br>
|
||||
<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>
|
||||
@{
|
||||
double totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
||||
|
||||
double totalProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
totalProfit = Model.PTData.SellLog.Sum(s => s.Profit);
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
todaysProfit = Model.PTData.SellLogToday.Sum(s => s.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
todaysProfit = Model.PTData.SellLogToday.Sum(s => s.Profit);
|
||||
}
|
||||
double todaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime);
|
||||
double todaysProfit = Model.PTData.SellLogToday.Sum(s => s.Profit);
|
||||
double todaysProfitFiat = Math.Round(todaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double todaysPercentGain = Math.Round(todaysProfit / todaysStartBalance * 100, 2);
|
||||
|
||||
double yesterdaysProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
yesterdaysProfit = Model.PTData.SellLogYesterday.Sum(s => s.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
yesterdaysProfit = Model.PTData.SellLogYesterday.Sum(s => s.Profit);
|
||||
}
|
||||
double yesterdaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-1));
|
||||
double yesterdaysProfit = Model.PTData.SellLogYesterday.Sum(s => s.Profit);
|
||||
double yesterdaysProfitFiat = Math.Round(yesterdaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double yesterdaysPercentGain = Math.Round(yesterdaysProfit / yesterdaysStartBalance * 100, 2);
|
||||
|
||||
double last7DaysProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
last7DaysProfit = Model.PTData.SellLogLast7Days.Sum(s => s.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
last7DaysProfit = Model.PTData.SellLogLast7Days.Sum(s => s.Profit);
|
||||
}
|
||||
double last7DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-7));
|
||||
double last7DaysProfit = Model.PTData.SellLogLast7Days.Sum(s => s.Profit);
|
||||
double last7DaysProfitFiat = Math.Round(last7DaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double last7DaysPercentGain = Math.Round(last7DaysProfit / last7DaysStartBalance * 100, 2);
|
||||
|
||||
double last30DaysProfit = 0;
|
||||
if (Model.PTData.Properties.Shorting)
|
||||
{
|
||||
last30DaysProfit = Model.PTData.SellLogLast30Days.Sum(s => s.Profit * (-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
last30DaysProfit = Model.PTData.SellLogLast30Days.Sum(s => s.Profit);
|
||||
}
|
||||
double last30DaysStartBalance = Model.PTData.GetSnapshotBalance(Model.DateTimeNow.DateTime.AddDays(-30));
|
||||
double last30DaysProfit = Model.PTData.SellLogLast30Days.Sum(s => s.Profit);
|
||||
double last30DaysProfitFiat = Math.Round(last30DaysProfit * Model.Summary.MainMarketPrice, 2);
|
||||
double last30DaysPercentGain = Math.Round(last30DaysProfit / last30DaysStartBalance * 100, 2);
|
||||
}
|
||||
|
@ -181,6 +238,7 @@
|
|||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/plugins/tablesaw/js/tablesaw-init.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$(".cdev").circlos();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('.text-autocolor').autocolor(false);
|
||||
|
||||
|
@ -191,17 +249,15 @@
|
|||
.x(function(d) { return d.label })
|
||||
.y(function(d) { return d.value })
|
||||
.showLabels(true) //Display pie labels
|
||||
.labelThreshold(.1) //Configure the minimum slice size for labels to show up
|
||||
.labelThreshold(.1) //Configure the minimum slice size for labels to show up
|
||||
.labelType("percent") //Configure what type of data to show in the label. Can be "key", "value" or "percent"
|
||||
.donut(true) //Turn on Donut mode. Makes pie chart look tasty!
|
||||
.donutRatio(0.3) //Configure how big you want the donut hole size to be.
|
||||
;
|
||||
|
||||
d3.select("#AssetDistribution svg")
|
||||
.datum(@Html.Raw(Model.AssetDistributionData))
|
||||
.transition().duration(350)
|
||||
.call(chart);
|
||||
|
||||
return chart;
|
||||
});
|
||||
</text>
|
||||
|
@ -219,7 +275,6 @@
|
|||
$.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("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
|
@ -235,7 +290,6 @@
|
|||
});
|
||||
</text>
|
||||
}
|
||||
|
||||
@if (!Model.ProfitChartDataJSON.Equals("")) {
|
||||
<text>
|
||||
nv.addGraph(function () {
|
||||
|
@ -247,7 +301,6 @@
|
|||
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>
|
||||
|
|
|
@ -8,8 +8,10 @@ using Core.Main.DataObjects;
|
|||
using Core.Main.DataObjects.PTMagicData;
|
||||
using Core.MarketAnalyzer;
|
||||
|
||||
namespace Monitor.Pages {
|
||||
public class DashboardBottomModel : _Internal.BasePageModelSecureAJAX {
|
||||
namespace Monitor.Pages
|
||||
{
|
||||
public class DashboardBottomModel : _Internal.BasePageModelSecureAJAX
|
||||
{
|
||||
public ProfitTrailerData PTData = null;
|
||||
public List<MarketTrend> MarketTrends { get; set; } = new List<MarketTrend>();
|
||||
public string TrendChartDataJSON = "";
|
||||
|
@ -17,9 +19,9 @@ namespace Monitor.Pages {
|
|||
public string LastGlobalSetting = "Default";
|
||||
public DateTimeOffset DateTimeNow = Constants.confMinDate;
|
||||
public string AssetDistributionData = "";
|
||||
public double currentBalance = 0;
|
||||
public string currentBalanceString = "";
|
||||
public void OnGet() {
|
||||
public double totalCurrentValue = 0;
|
||||
public void OnGet()
|
||||
{
|
||||
// Initialize Config
|
||||
base.Init();
|
||||
|
||||
|
@ -27,7 +29,8 @@ namespace Monitor.Pages {
|
|||
BuildAssetDistributionData();
|
||||
}
|
||||
|
||||
private void BindData() {
|
||||
private void BindData()
|
||||
{
|
||||
PTData = this.PtDataObject;
|
||||
|
||||
// Cleanup temp files
|
||||
|
@ -38,7 +41,8 @@ namespace Monitor.Pages {
|
|||
DateTimeNow = DateTimeOffset.UtcNow.ToOffset(offsetTimeSpan);
|
||||
|
||||
// Get last and current active setting
|
||||
if (!String.IsNullOrEmpty(HttpContext.Session.GetString("LastGlobalSetting"))) {
|
||||
if (!String.IsNullOrEmpty(HttpContext.Session.GetString("LastGlobalSetting")))
|
||||
{
|
||||
LastGlobalSetting = HttpContext.Session.GetString("LastGlobalSetting");
|
||||
}
|
||||
HttpContext.Session.SetString("LastGlobalSetting", Summary.CurrentGlobalSetting.SettingName);
|
||||
|
@ -49,24 +53,32 @@ namespace Monitor.Pages {
|
|||
BuildMarketTrendChartData();
|
||||
BuildProfitChartData();
|
||||
}
|
||||
|
||||
private void BuildMarketTrendChartData() {
|
||||
if (MarketTrends.Count > 0) {
|
||||
private void BuildMarketTrendChartData()
|
||||
{
|
||||
if (MarketTrends.Count > 0)
|
||||
{
|
||||
TrendChartDataJSON = "[";
|
||||
int mtIndex = 0;
|
||||
foreach (MarketTrend mt in MarketTrends) {
|
||||
if (mt.DisplayGraph) {
|
||||
foreach (MarketTrend mt in MarketTrends)
|
||||
{
|
||||
if (mt.DisplayGraph)
|
||||
{
|
||||
string lineColor = "";
|
||||
if (mtIndex < Constants.ChartLineColors.Length) {
|
||||
if (mtIndex < Constants.ChartLineColors.Length)
|
||||
{
|
||||
lineColor = Constants.ChartLineColors[mtIndex];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
lineColor = Constants.ChartLineColors[mtIndex - 20];
|
||||
}
|
||||
|
||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name)) {
|
||||
if (Summary.MarketTrendChanges.ContainsKey(mt.Name))
|
||||
{
|
||||
List<MarketTrendChange> marketTrendChangeSummaries = Summary.MarketTrendChanges[mt.Name];
|
||||
|
||||
if (marketTrendChangeSummaries.Count > 0) {
|
||||
if (marketTrendChangeSummaries.Count > 0)
|
||||
{
|
||||
if (!TrendChartDataJSON.Equals("[")) TrendChartDataJSON += ",";
|
||||
|
||||
TrendChartDataJSON += "{";
|
||||
|
@ -79,9 +91,11 @@ namespace Monitor.Pages {
|
|||
DateTime startDateTime = currentDateTime.AddHours(-PTMagicConfiguration.GeneralSettings.Monitor.GraphMaxTimeframeHours);
|
||||
DateTime endDateTime = currentDateTime;
|
||||
int trendChartTicks = 0;
|
||||
for (DateTime tickTime = startDateTime; tickTime <= endDateTime; tickTime = tickTime.AddMinutes(PTMagicConfiguration.GeneralSettings.Monitor.GraphIntervalMinutes)) {
|
||||
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();
|
||||
if (tickRange.Count > 0) {
|
||||
if (tickRange.Count > 0)
|
||||
{
|
||||
MarketTrendChange mtc = tickRange.First();
|
||||
if (tickTime != startDateTime) TrendChartDataJSON += ",\n";
|
||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
||||
|
@ -92,17 +106,15 @@ namespace Monitor.Pages {
|
|||
}
|
||||
// Add most recent tick
|
||||
List<MarketTrendChange> latestTickRange = marketTrendChangeSummaries.OrderByDescending(m => m.TrendDateTime).ToList();
|
||||
if (latestTickRange.Count > 0) {
|
||||
if (latestTickRange.Count > 0)
|
||||
{
|
||||
MarketTrendChange mtc = latestTickRange.First();
|
||||
if (trendChartTicks > 0) TrendChartDataJSON += ",\n";
|
||||
if (Double.IsInfinity(mtc.TrendChange)) mtc.TrendChange = 0;
|
||||
|
||||
TrendChartDataJSON += "{ x: new Date('" + mtc.TrendDateTime.ToString("yyyy-MM-ddTHH:mm:ss").Replace(".", ":") + "'), y: " + mtc.TrendChange.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
}
|
||||
|
||||
TrendChartDataJSON += "]";
|
||||
TrendChartDataJSON += "}";
|
||||
|
||||
mtIndex++;
|
||||
}
|
||||
}
|
||||
|
@ -112,19 +124,31 @@ namespace Monitor.Pages {
|
|||
}
|
||||
}
|
||||
|
||||
private void BuildProfitChartData() {
|
||||
private void BuildProfitChartData()
|
||||
{
|
||||
int tradeDayIndex = 0;
|
||||
string profitPerDayJSON = "";
|
||||
if (PTData.SellLog.Count > 0) {
|
||||
|
||||
if (PTData.SellLog.Count > 0)
|
||||
{
|
||||
DateTime minSellLogDate = PTData.SellLog.OrderBy(sl => sl.SoldDate).First().SoldDate.Date;
|
||||
DateTime graphStartDate = DateTime.UtcNow.Date.AddDays(-30);
|
||||
if (minSellLogDate > graphStartDate) graphStartDate = minSellLogDate;
|
||||
for (DateTime salesDate = graphStartDate; salesDate <= DateTime.UtcNow.Date; salesDate = salesDate.AddDays(1)) {
|
||||
if (tradeDayIndex > 0) {
|
||||
if (minSellLogDate > graphStartDate)
|
||||
{
|
||||
graphStartDate = minSellLogDate;
|
||||
}
|
||||
for (DateTime salesDate = graphStartDate; salesDate <= DateTime.UtcNow.Date; salesDate = salesDate.AddDays(1))
|
||||
{
|
||||
if (tradeDayIndex > 0)
|
||||
{
|
||||
profitPerDayJSON += ",\n";
|
||||
}
|
||||
int trades = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate).Count;
|
||||
double profit = PTData.SellLog.FindAll(t => t.SoldDate.Date == salesDate).Sum(t => t.Profit);
|
||||
if (PTData.Properties.Shorting)
|
||||
{
|
||||
profit = profit * (-1);
|
||||
}
|
||||
double profitFiat = Math.Round(profit * Summary.MainMarketPrice, 2);
|
||||
profitPerDayJSON += "{x: new Date('" + salesDate.ToString("yyyy-MM-dd") + "'), y: " + profitFiat.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "}";
|
||||
tradeDayIndex++;
|
||||
|
@ -140,13 +164,51 @@ namespace Monitor.Pages {
|
|||
}
|
||||
private void BuildAssetDistributionData()
|
||||
{
|
||||
double PairsBalance = PTData.GetPairsBalance();
|
||||
double DCABalance = PTData.GetDCABalance();
|
||||
double PendingBalance = PTData.GetPendingBalance();
|
||||
double DustBalance = PTData.GetDustBalance();
|
||||
double TotalValue = PTData.GetCurrentBalance();
|
||||
double AvailableBalance = (TotalValue - PairsBalance - DCABalance - PendingBalance - DustBalance);
|
||||
|
||||
// the per PT-Eelroy, the PT API doesn't provide these values when using leverage, so they are calculated here to cover either case.
|
||||
double PairsBalance = 0.0;
|
||||
double DCABalance = 0.0;
|
||||
double PendingBalance = 0.0;
|
||||
double AvailableBalance = PTData.GetCurrentBalance();
|
||||
bool isSellStrategyTrue = false;
|
||||
bool isTrailingSellActive = false;
|
||||
|
||||
foreach (Core.Main.DataObjects.PTMagicData.DCALogData dcaLogEntry in PTData.DCALog)
|
||||
{
|
||||
string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive);
|
||||
|
||||
// Aggregate totals
|
||||
if (dcaLogEntry.Leverage == 0)
|
||||
{
|
||||
if (sellStrategyText.Contains("PENDING"))
|
||||
{
|
||||
PendingBalance = PendingBalance + (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice);
|
||||
}
|
||||
else if (dcaLogEntry.BuyStrategies.Count > 0)
|
||||
{
|
||||
DCABalance = DCABalance + (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice);
|
||||
}
|
||||
else
|
||||
{
|
||||
PairsBalance = PairsBalance + (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sellStrategyText.Contains("PENDING"))
|
||||
{
|
||||
PendingBalance = PendingBalance + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) / dcaLogEntry.Leverage);
|
||||
}
|
||||
else if (dcaLogEntry.BuyStrategies.Count > 0)
|
||||
{
|
||||
DCABalance = DCABalance + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) / dcaLogEntry.Leverage);
|
||||
}
|
||||
else
|
||||
{
|
||||
PairsBalance = PairsBalance + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) / dcaLogEntry.Leverage);
|
||||
}
|
||||
}
|
||||
}
|
||||
totalCurrentValue = PendingBalance + DCABalance + PairsBalance + AvailableBalance;
|
||||
AssetDistributionData = "[";
|
||||
AssetDistributionData += "{label: 'Pairs',color: '#82E0AA',value: '" + PairsBalance.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "'},";
|
||||
AssetDistributionData += "{label: 'DCA',color: '#D98880',value: '" + DCABalance.ToString("0.00", new System.Globalization.CultureInfo("en-US")) + "'},";
|
||||
|
|
|
@ -8,66 +8,68 @@
|
|||
<div class="col-md-5 px-1">
|
||||
<div class="card-box px-2">
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Possible Buys (@Model.PTData.BuyLog.Count)</b><small id="buylist-refresh-icon"></small><small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)BuyAnalyzer">more</a></small></h4>
|
||||
@if (Model.PTData.BuyLog.Count == 0) {
|
||||
|
||||
@if (Model.PTData.BuyLog.Count == 0)
|
||||
{
|
||||
<p>Your Profit Trailer did not find anything worth buying so far.</p>
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table table-sm m-b-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Market</th>
|
||||
<th>24H Trend</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="24 Hour price trend">24H</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="24 Hour trading volume">Volume</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Current ask price for this market">Ask</th>
|
||||
<th>Buy Strategies</th>
|
||||
<th class="text-right" data-toggle="tooltip" data-placement="top" title="Current ask price for this market">Ask Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (Core.Main.DataObjects.PTMagicData.BuyLogData buyLogEntry in Model.PTData.BuyLog.OrderBy(b => b.IsSom).
|
||||
ThenByDescending(b => b.IsTrailing).
|
||||
ThenByDescending(b => b.IsTrue).
|
||||
ThenByDescending(b => b.TrueStrategyCount).
|
||||
|
||||
ThenByDescending(b => b.PercChange).
|
||||
Take(Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDashboardBuyEntries)) {
|
||||
|
||||
Core.Main.DataObjects.PTMagicData.MarketPairSummary mps = null;
|
||||
if (Model.Summary.MarketSummary.ContainsKey(buyLogEntry.Market)) {
|
||||
mps = Model.Summary.MarketSummary[buyLogEntry.Market];
|
||||
}
|
||||
|
||||
bool isTrailingBuyActive = buyLogEntry.IsTrailing;
|
||||
if (buyLogEntry.BuyStrategies.Count > 0) {
|
||||
isTrailingBuyActive = (buyLogEntry.BuyStrategies.FindAll(bs => bs.IsTrailing).Count > 0);
|
||||
}
|
||||
|
||||
bool isBuyStrategyTrue = buyLogEntry.IsTrue;
|
||||
if (buyLogEntry.BuyStrategies.Count > 0) {
|
||||
isBuyStrategyTrue = (buyLogEntry.BuyStrategies.FindAll(bs => !bs.IsTrue).Count == 0);
|
||||
}
|
||||
|
||||
bool buyDisabled = false;
|
||||
string buyStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Model.Summary, buyLogEntry.BuyStrategies, buyLogEntry.BuyStrategy, isBuyStrategyTrue, isTrailingBuyActive);
|
||||
if (!Core.ProfitTrailer.StrategyHelper.IsValidStrategy(buyStrategyText, true)) {
|
||||
buyDisabled = true;
|
||||
}
|
||||
|
||||
<tr>
|
||||
@if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0) {
|
||||
<th class="align-top"><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, buyLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@buyLogEntry.Market</a></th>
|
||||
} else {
|
||||
<th class="align-top"><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, buyLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@buyLogEntry.Market</a> <i class="fa fa-exclamation-triangle text-highlight" data-toggle="tooltip" data-placement="top" data-html="true" title="@await Component.InvokeAsync("PairIcon", mps)" data-template="<div class='tooltip' role='tooltip'><div class='tooltip-arrow'></div><div class='tooltip-inner pair-tooltip'></div></div>"></i></th>
|
||||
}
|
||||
<td class="text-autocolor">@string.Format("{0}%", (buyLogEntry.PercChange * 100).ToString("#,#0.00"))</td>
|
||||
@if (buyDisabled) {
|
||||
<td>@Html.Raw(buyStrategyText)</td>
|
||||
} else {
|
||||
<td>@Html.Raw(buyStrategyText)</td>
|
||||
}
|
||||
<td class="text-right">@buyLogEntry.CurrentPrice.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
</tr>
|
||||
@foreach (Core.Main.DataObjects.PTMagicData.BuyLogData buyLogEntry in Model.PTData.BuyLog.OrderBy(b => b.IsSom).
|
||||
ThenByDescending(b => b.IsTrailing).
|
||||
ThenByDescending(b => b.IsTrue).
|
||||
ThenByDescending(b => b.TrueStrategyCount).
|
||||
ThenByDescending(b => b.PercChange).
|
||||
Take(Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDashboardBuyEntries)) {
|
||||
Core.Main.DataObjects.PTMagicData.MarketPairSummary mps = null;
|
||||
if (Model.Summary.MarketSummary.ContainsKey(buyLogEntry.Market))
|
||||
{
|
||||
mps = Model.Summary.MarketSummary[buyLogEntry.Market];
|
||||
}
|
||||
|
||||
bool isTrailingBuyActive = buyLogEntry.IsTrailing;
|
||||
if (buyLogEntry.BuyStrategies.Count > 0) {
|
||||
isTrailingBuyActive = (buyLogEntry.BuyStrategies.FindAll(bs => bs.IsTrailing).Count > 0);
|
||||
}
|
||||
|
||||
bool isBuyStrategyTrue = buyLogEntry.IsTrue;
|
||||
if (buyLogEntry.BuyStrategies.Count > 0) {
|
||||
isBuyStrategyTrue = (buyLogEntry.BuyStrategies.FindAll(bs => !bs.IsTrue).Count == 0);
|
||||
}
|
||||
|
||||
bool buyDisabled = false;
|
||||
string buyStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Model.Summary, buyLogEntry.BuyStrategies, buyLogEntry.BuyStrategy, isBuyStrategyTrue, isTrailingBuyActive);
|
||||
if (!Core.ProfitTrailer.StrategyHelper.IsValidStrategy(buyStrategyText, true)) {
|
||||
buyDisabled = true;
|
||||
}
|
||||
|
||||
<tr>
|
||||
@if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0) {
|
||||
<th class="align-top"><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, buyLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@buyLogEntry.Market</a></th>
|
||||
} else {
|
||||
<th class="align-top"><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, buyLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@buyLogEntry.Market</a> <i class="fa fa-exclamation-triangle text-highlight" data-toggle="tooltip" data-placement="top" data-html="true" title="@await Component.InvokeAsync("PairIcon", mps)" data-template="<div class='tooltip' role='tooltip'><div class='tooltip-arrow'></div><div class='tooltip-inner pair-tooltip'></div></div>"></i></th>
|
||||
}
|
||||
<td class="text-autocolor">@string.Format("{0}%", (buyLogEntry.PercChange * 100).ToString("#,#0.00"))</td>
|
||||
<td class="text">@string.Format("{0}", (buyLogEntry.Volume24h).ToString())</td>
|
||||
<td class="text-left">@buyLogEntry.CurrentPrice.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"))</td>
|
||||
|
||||
@if (buyDisabled) {
|
||||
<td>@Html.Raw(buyStrategyText)</td>
|
||||
} else {
|
||||
<td>@Html.Raw(buyStrategyText)</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -82,22 +84,23 @@
|
|||
<div class="card-box px-2">
|
||||
<h4 class="m-t-0 m-b-20 header-title"><b>Pairs / DCA / Pending (@Model.PTData.DCALog.Count)</b><small id="baglist-refresh-icon"></small><small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)BagAnalyzer">more</a></small></h4>
|
||||
|
||||
@if (Model.PTData.DCALog.Count == 0) {
|
||||
|
||||
@if (Model.PTData.DCALog.Count == 0)
|
||||
{
|
||||
<p>Profit Trailer is not reporting any holdings on your exchange.</p>
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm m-b-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Market</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Market trend last 24 hours">24H Trend</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="24 Hour Trend">24H</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Total Buy Cost">Cost</th>
|
||||
<th></th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Active buy strategies">DCA Buy Strats</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Active sell strategies">Sell Strats</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Active buy strategies">DCA</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Active sell strategies">Sell</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Target profit to sell">Target</th>
|
||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Current Profit">Profit</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
@ -131,77 +134,101 @@
|
|||
}
|
||||
|
||||
bool isSellStrategyTrue = false;
|
||||
if (dcaLogEntry.BuyStrategies.Count > 0) {
|
||||
if (dcaLogEntry.SellStrategies.Count > 0) {
|
||||
isSellStrategyTrue = (dcaLogEntry.SellStrategies.FindAll(ss => !ss.IsTrue).Count == 0);
|
||||
}
|
||||
|
||||
bool buyDisabled = false;
|
||||
string leverage = "";
|
||||
double leverageValue = 1;
|
||||
string buyStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Model.Summary, dcaLogEntry.BuyStrategies, dcaLogEntry.BuyStrategy, isBuyStrategyTrue, isTrailingBuyActive);
|
||||
if (!Core.ProfitTrailer.StrategyHelper.IsValidStrategy(buyStrategyText, true)) {
|
||||
|
||||
if (!Core.ProfitTrailer.StrategyHelper.IsValidStrategy(buyStrategyText, true))
|
||||
{
|
||||
buyDisabled = true;
|
||||
}
|
||||
|
||||
string sellStrategyText = Core.ProfitTrailer.StrategyHelper.GetStrategyText(Model.Summary, dcaLogEntry.SellStrategies, dcaLogEntry.SellStrategy, isSellStrategyTrue, isTrailingSellActive);
|
||||
|
||||
|
||||
// Check for when PT loses the value of a pair
|
||||
bool lostValue = false;
|
||||
lostValue = (dcaLogEntry.TotalCost == 0.0) || (dcaLogEntry.AverageBuyPrice == 0.0);
|
||||
|
||||
// Aggregate totals
|
||||
Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost;
|
||||
double ExchangeFee = 0;
|
||||
|
||||
double exchangeFee = 0;
|
||||
switch (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.ToLower())
|
||||
{
|
||||
case "binance":
|
||||
ExchangeFee = 0.002;
|
||||
exchangeFee = 0.002;
|
||||
break;
|
||||
case "binanceus":
|
||||
ExchangeFee = 0.002;
|
||||
exchangeFee = 0.002;
|
||||
break;
|
||||
case "binancefutures":
|
||||
ExchangeFee = 0.002;
|
||||
exchangeFee = 0.002;
|
||||
break;
|
||||
case "bittrex":
|
||||
ExchangeFee = 0.0025;
|
||||
exchangeFee = 0.0025;
|
||||
break;
|
||||
case "poloniex":
|
||||
ExchangeFee = 0.0025;
|
||||
exchangeFee = 0.0025;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * ExchangeFee;
|
||||
Model.TotalBagValue = Model.TotalBagValue + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) - TradingFee);
|
||||
|
||||
// Aggregate totals
|
||||
double tradingFee = (exchangeFee * dcaLogEntry.TotalCost) * 2;
|
||||
double bagGain = (dcaLogEntry.ProfitPercent / 100) * dcaLogEntry.TotalCost * leverageValue;
|
||||
Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost;
|
||||
Model.TotalBagGain = Model.TotalBagGain + bagGain;
|
||||
|
||||
// Render the row
|
||||
<tr @(lostValue ? "class=errorRow" : "") >
|
||||
@if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0) {
|
||||
@if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0)
|
||||
{
|
||||
<th class="align-top"><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, dcaLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@dcaLogEntry.Market</a></th>
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
<th class="align-top"><a href="@Core.Helper.SystemHelper.GetMarketLink(Model.PTMagicConfiguration.GeneralSettings.Monitor.LinkPlatform,Model.PTMagicConfiguration.GeneralSettings.Application.Exchange, dcaLogEntry.Market, Model.Summary.MainMarket)" target="_blank">@dcaLogEntry.Market</a> <i class="fa fa-exclamation-triangle text-highlight" data-toggle="tooltip" data-placement="top" data-html="true" title="@await Component.InvokeAsync("PairIcon", mps)" data-template="<div class='tooltip' role='tooltip'><div class='tooltip-arrow'></div><div class='tooltip-inner pair-tooltip'></div></div>"></i></th>
|
||||
}
|
||||
|
||||
<td class="text-autocolor">@Html.Raw((dcaLogEntry.PercChange * 100).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))%</td>
|
||||
|
||||
<td class="text-left">@Html.Raw(dcaLogEntry.TotalCost.ToString("#,#0.000000", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
|
||||
<td class="text-right">
|
||||
@if (dcaEnabled) {
|
||||
@if (dcaLogEntry.BoughtTimes > 0) {
|
||||
@if (dcaEnabled)
|
||||
{
|
||||
@if (dcaLogEntry.BoughtTimes > 0)
|
||||
{
|
||||
@dcaLogEntry.BoughtTimes;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
<span data-toggle="tooltip" data-placement="top" title="DCA is disabled"><i class="fa fa-ban text-highlight"></i></span>
|
||||
}
|
||||
</td>
|
||||
|
||||
<td>@Html.Raw(buyStrategyText)</td>
|
||||
|
||||
<td>@Html.Raw(sellStrategyText)</td>
|
||||
|
||||
@if(!@lostValue)
|
||||
|
||||
@if (sellStrategyText.Contains("CROSSED"))
|
||||
// if leverage, recalculate profit target
|
||||
{
|
||||
string leverageText = sellStrategyText.Remove(0, sellStrategyText.IndexOf("CROSSED")+9);
|
||||
leverage = leverageText.Remove(leverageText.IndexOf(".0)"), leverageText.Length - leverageText.IndexOf(".0)"));
|
||||
leverageValue = double.Parse(leverage);
|
||||
}
|
||||
@if (sellStrategyText.Contains("ISOLATED"))
|
||||
{
|
||||
string leverageText = sellStrategyText.Remove(0, sellStrategyText.IndexOf("ISOLATED")+10);
|
||||
leverage = leverageText.Remove(leverageText.IndexOf(".0)"), leverageText.Length - leverageText.IndexOf(".0)"));
|
||||
leverageValue = double.Parse(leverage);
|
||||
}
|
||||
@if (leverageValue == 1)
|
||||
{
|
||||
<td class="@Html.Raw((dcaLogEntry.TargetGainValue.HasValue && (dcaLogEntry.ProfitPercent > dcaLogEntry.TargetGainValue.Value)) ? "text-success" : "text-danger")">@Html.Raw(dcaLogEntry.TargetGainValue.HasValue ? dcaLogEntry.TargetGainValue.Value.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%" : " ")</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
double leverageTargetGain = leverageValue * dcaLogEntry.TargetGainValue.Value;
|
||||
<td class="@Html.Raw((dcaLogEntry.TargetGainValue.HasValue && (dcaLogEntry.ProfitPercent > dcaLogEntry.TargetGainValue.Value)) ? "text-success" : "text-danger")">@Html.Raw(dcaLogEntry.TargetGainValue.HasValue ? leverageTargetGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%" : " ")</td>
|
||||
}
|
||||
@if (!@lostValue)
|
||||
{
|
||||
<td class="text-autocolor">@dcaLogEntry.ProfitPercent.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||
}
|
||||
|
@ -209,20 +236,20 @@
|
|||
{
|
||||
<td class="text-left">No Value!</td>
|
||||
}
|
||||
|
||||
<td class="text-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)_get/BagDetails/?m=@dcaLogEntry.Market" data-remote="false" data-toggle="modal" data-target="#dca-chart"><i class="fa fa-plus-circle"></i></a></td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<td>Totals:</td><td></td>
|
||||
<td>Totals:</td>
|
||||
<td></td>
|
||||
<td>@Html.Raw(Model.TotalBagCost.ToString("#,#0.000000", new System.Globalization.CultureInfo("en-US")))</td>
|
||||
<td></td><td></td><td></td>
|
||||
<td class="text-autocolor">@Html.Raw((((Model.TotalBagValue - Model.TotalBagCost) / Model.TotalBagCost) * 100).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))%</td>
|
||||
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-autocolor">@Html.Raw((((Model.TotalBagGain) / Model.TotalBagCost) * 100).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))%</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if (Model.PTData.DCALog.Count > Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDashboardBagEntries) {
|
||||
<p class="text-right"><small><i class="fa fa-info-circle"></i> @Model.PTMagicConfiguration.GeneralSettings.Monitor.MaxDashboardBagEntries of @Model.PTData.DCALog.Count items listed - <a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)BagAnalyzer">View all items</a></small></p>
|
||||
}
|
||||
|
@ -232,11 +259,9 @@
|
|||
</div>
|
||||
|
||||
<script src="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)assets/js/jquery.nicescroll.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
'use strict';
|
||||
|
||||
$("#dca-chart").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);
|
||||
|
@ -245,7 +270,5 @@
|
|||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
||||
</script>
|
|
@ -6,16 +6,15 @@ namespace Monitor.Pages {
|
|||
public class DashboardTopModel : _Internal.BasePageModelSecureAJAX {
|
||||
public ProfitTrailerData PTData = null;
|
||||
public DateTimeOffset DateTimeNow = Constants.confMinDate;
|
||||
|
||||
public void OnGet() {
|
||||
// Initialize Config
|
||||
base.Init();
|
||||
|
||||
BindData();
|
||||
}
|
||||
|
||||
public double TotalBagCost = 0;
|
||||
public double TotalBagValue = 0;
|
||||
public double TotalBagGain = 0;
|
||||
private void BindData() {
|
||||
PTData = this.PtDataObject;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
indent_size: 2
|
||||
};
|
||||
editor.setTheme("ace/theme/ptmagic");
|
||||
editor.getSession().setMode("ace/mode/java");
|
||||
editor.getSession().setMode("ace/mode/yaml");
|
||||
editor.getSession().setValue(txtArea.val());
|
||||
editor.getSession().on('change', function () {
|
||||
txtArea.val(editor.getSession().getValue());
|
||||
|
|
|
@ -173,6 +173,10 @@ a:active {
|
|||
stroke-opacity: 1 !important;
|
||||
}
|
||||
|
||||
.trend-chart
|
||||
{
|
||||
clear: none;
|
||||
}
|
||||
|
||||
/* Custom menu styles */
|
||||
#topnav .navigation-menu {
|
||||
|
@ -211,4 +215,69 @@ a:active {
|
|||
|
||||
#topnav .has-submenu.active>a {
|
||||
color: #50cefc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Circolus */
|
||||
.cdev {
|
||||
position: absolute;
|
||||
height : 30px;
|
||||
width : 30px;
|
||||
top: 5px;
|
||||
left: 0;
|
||||
margin : 0 0 0 10px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.cdev div {
|
||||
position : absolute;
|
||||
height : 30px;
|
||||
width : 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.cdev div span {
|
||||
position : absolute;
|
||||
font-family : Arial;
|
||||
font-size : 5px;
|
||||
line-height : 7px;
|
||||
height : 20px;
|
||||
width : 20px;
|
||||
left : 5px;
|
||||
top : 5px;
|
||||
text-align : center;
|
||||
border-radius : 50%;
|
||||
background-color: #36404a;
|
||||
color: #36404a;
|
||||
}
|
||||
|
||||
.cdev .background {
|
||||
background-color: #b3cef6;
|
||||
}
|
||||
|
||||
.cdev .rotate {
|
||||
clip : rect(0 15px 30px 0);
|
||||
background-color: #4b86db;
|
||||
}
|
||||
|
||||
.cdev .left {
|
||||
clip : rect(0 15px 30px 0);
|
||||
opacity : 1;
|
||||
background-color: #b3cef6;
|
||||
}
|
||||
|
||||
.cdev .right {
|
||||
clip : rect(0 15px 30px 0);
|
||||
transform : rotate(180deg);
|
||||
opacity : 0;
|
||||
background-color: #4b86db;
|
||||
}
|
||||
|
||||
@keyframes toggle {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
jQuery-Circle-Plugin v0.1 by Jamal hassouni
|
||||
https://github.com/jamalhassouni
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
// circle animation pluqins by jamal hassouni
|
||||
$.fn.circlos = function () {
|
||||
// deafualt options
|
||||
var DEFAULTS = {
|
||||
backgroundColor: '#b3cef6', // default background color
|
||||
progressColor: '#4b86db', // default progress color
|
||||
percent: 75, // default percent value
|
||||
duration: 2000 // default duration value
|
||||
};
|
||||
|
||||
$(this).each(function () {
|
||||
var $target = $(this);
|
||||
// options of circle
|
||||
var options = {
|
||||
// if isset value of background if not use the default value of background color
|
||||
backgroundColor: $target.data('color') ? $target.data('color').split(',')[0] : DEFAULTS.backgroundColor,
|
||||
// if isset value of progress if not use the default value of progress color
|
||||
progressColor: $target.data('color') ? $target.data('color').split(',')[1] : DEFAULTS.progressColor,
|
||||
// if isset value of percent if not use the default value of percent
|
||||
percent: $target.data('percent') ? $target.data('percent') : DEFAULTS.percent,
|
||||
// if isset value of duration if not use the default value of duration
|
||||
duration: $target.data('duration') ? $target.data('duration') : DEFAULTS.duration
|
||||
};
|
||||
console.log(options);
|
||||
// add divs for structure
|
||||
$target.append('<div class="background"></div><div class="rotate"></div><div class="left"></div><div class="right"></div><div class=""><span>' + options.percent + '%</span></div>');
|
||||
// change style of the circle with the options values
|
||||
$target.find('.background').css('background-color', options.backgroundColor);
|
||||
$target.find('.left').css('background-color', options.backgroundColor);
|
||||
$target.find('.rotate').css('background-color', options.progressColor);
|
||||
$target.find('.right').css('background-color', options.progressColor);
|
||||
|
||||
var $rotate = $target.find('.rotate');
|
||||
setTimeout(function () {
|
||||
$rotate.css({
|
||||
'transition': 'transform ' + options.duration + 'ms linear',
|
||||
'transform': 'rotate(' + options.percent * 3.6 + 'deg)'
|
||||
});
|
||||
},1);
|
||||
|
||||
if (options.percent > 50) {
|
||||
// add animation for the right class and left class
|
||||
var animationRight = 'toggle ' + (options.duration / options.percent * 50) + 'ms step-end';
|
||||
var animationLeft = 'toggle ' + (options.duration / options.percent * 50) + 'ms step-start';
|
||||
$target.find('.right').css({
|
||||
animation: animationRight,
|
||||
opacity: 1
|
||||
});
|
||||
$target.find('.left').css({
|
||||
animation: animationLeft,
|
||||
opacity: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})(jQuery);
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,9 @@
|
|||
define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"list.markup",regex:/^(?:-{3}|\.{3})\s*(?=#|$)/},{token:"list.markup",regex:/^\s*[\-?](?:$|\s)/},{token:"constant",regex:"!![\\w//]+"},{token:"constant.language",regex:"[&\\*][a-zA-Z0-9-_]+"},{token:["meta.tag","keyword"],regex:/^(\s*\w.*?)(:(?=\s|$))/},{token:["meta.tag","keyword"],regex:/(\w+?)(\s*:(?=\s|$))/},{token:"keyword.operator",regex:"<<\\w*:\\w*"},{token:"keyword.operator",regex:"-\\s*(?=[{])"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:/[|>][-+\d\s]*$/,onMatch:function(e,t,n,r){var i=/^\s*/.exec(r)[0];return n.length<1?n.push(this.next):n[0]="mlString",n.length<2?n.push(i.length):n[1]=i.length,this.token},next:"mlString"},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"constant.numeric",regex:/(\b|[+\-\.])[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)(?=[^\d-\w]|$)/},{token:"constant.numeric",regex:/[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/},{token:"constant.language.boolean",regex:"\\b(?:true|false|TRUE|FALSE|True|False|yes|no)\\b"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:/[^\s,:\[\]\{\}]+/}],mlString:[{token:"indent",regex:/^\s*$/},{token:"indent",regex:/^\s*/,onMatch:function(e,t,n){var r=n[1];return r>=e.length?(this.next="start",n.splice(0)):this.next="mlString",this.token},next:"mlString"},{token:"string",regex:".+"}]},this.normalizeRules()};r.inherits(s,i),t.YamlHighlightRules=s}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),define("ace/mode/yaml",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/yaml_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./yaml_highlight_rules").YamlHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/coffee").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u,this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart=["#","//"],this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/yaml"}.call(a.prototype),t.Mode=a});
|
||||
(function() {
|
||||
window.require(["ace/mode/yaml"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -1,9 +1,43 @@
|
|||
define("ace/theme/ptmagic",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!0,t.cssClass="ace-ptmagic",t.cssText=".ace-ptmagic .ace_gutter {background: #414d59;color: #8F938F}.ace-ptmagic .ace_constant.ace_language.ace_boolean {color: #CCCCCC}.ace-ptmagic .ace_print-margin {width: 1px;background: #414d59}.ace-ptmagic {background-color: #414d59;color: #8F938F}.ace-ptmagic .ace_cursor {color: #A7A7A7}.ace-ptmagic .ace_marker-layer .ace_selection {background: rgba(221, 240, 255, 0.20)}.ace-ptmagic.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #414d59;}.ace-ptmagic .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-ptmagic .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(255, 255, 255, 0.25)}.ace-ptmagic .ace_marker-layer .ace_active-line {background: rgba(255, 255, 255, 0.031)}.ace-ptmagic .ace_gutter-active-line {background-color: rgba(255, 255, 255, 0.031)}.ace-ptmagic .ace_marker-layer .ace_selected-word {border: 1px solid rgba(221, 240, 255, 0.20)}.ace-ptmagic .ace_invisible {color: rgba(255, 255, 255, 0.25)}.ace-ptmagic .ace_keyword,.ace-ptmagic .ace_meta {color: #757aD8}.ace-ptmagic .ace_constant,.ace-ptmagic .ace_constant.ace_character,.ace-ptmagic .ace_constant.ace_character.ace_escape,.ace-ptmagic .ace_constant.ace_other {color: #4FB7C5}.ace-ptmagic .ace_keyword.ace_operator {color: #797878}.ace-ptmagic .ace_constant.ace_character {color: #AFA472}.ace-ptmagic .ace_constant.ace_language {color: #DE8E30}.ace-ptmagic .ace_constant.ace_numeric {color: #CCCCCC}.ace-ptmagic .ace_invalid,.ace-ptmagic .ace_invalid.ace_illegal {color: #F8F8F8;background-color: rgba(86, 45, 86, 0.75)}.ace-ptmagic .ace_invalid.ace_deprecated {text-decoration: underline;font-style: italic;color: #D2A8A1}.ace-ptmagic .ace_fold {background-color: #757aD8;border-color: #8F938F}.ace-ptmagic .ace_support.ace_function {color: #AEB2F8}.ace-ptmagic .ace_string {color: #66A968}.ace-ptmagic .ace_string.ace_regexp {color: #E9C062}.ace-ptmagic .ace_comment {color: #A6C6FF}.ace-ptmagic .ace_variable {color: #BEBF55}.ace-ptmagic .ace_variable.ace_language {color: #C1C144}.ace-ptmagic .ace_xml-pe {color: #494949}.ace-ptmagic .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYIiPj/8PAARgAh2NTMh8AAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)});
|
||||
(function() {
|
||||
window.require(["ace/theme/ptmagic"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
define("ace/theme/ptmagic", ["require", "exports", "module", "ace/lib/dom"],
|
||||
function (e, t, n) {
|
||||
t.isDark = !0,
|
||||
t.cssClass = "ace-ptmagic",
|
||||
t.cssText = "\
|
||||
.ace-ptmagic .ace_gutter {background: #566776;color: #dddddd}\
|
||||
.ace-ptmagic .ace_constant.ace_language.ace_boolean {color: #CCCCCC}\
|
||||
.ace-ptmagic .ace_print-margin {width: 1px;background: #414d59}\
|
||||
.ace-ptmagic {background-color: #414d59;color: #8F938F}\
|
||||
.ace-ptmagic .ace_cursor {color: #A7A7A7}\
|
||||
.ace-ptmagic .ace_marker-layer .ace_selection {background: rgba(221, 240, 255, 0.20)}\
|
||||
.ace-ptmagic.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #414d59;}\
|
||||
.ace-ptmagic .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}\
|
||||
.ace-ptmagic .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(255, 255, 255, 0.25)}\
|
||||
.ace-ptmagic .ace_marker-layer .ace_active-line {background: rgba(255, 255, 255, 0.031)}\
|
||||
.ace-ptmagic .ace_gutter-active-line {background-color: rgba(255, 255, 255, 0.031)}\
|
||||
.ace-ptmagic .ace_marker-layer .ace_selected-word {border: 1px solid rgba(221, 240, 255, 0.20)}\
|
||||
.ace-ptmagic .ace_invisible {color: rgba(255, 255, 255, 0.25)}\
|
||||
.ace-ptmagic .ace_keyword,.ace-ptmagic .ace_meta {color: #757aD8}\
|
||||
.ace-ptmagic .ace_constant,.ace-ptmagic .ace_constant.ace_character,.ace-ptmagic .ace_constant.ace_character.ace_escape,.ace-ptmagic .ace_constant.ace_other {color: #4FB7C5}\
|
||||
.ace-ptmagic .ace_keyword.ace_operator {color: #797878}\.ace-ptmagic .ace_constant.ace_character {color: #AFA472}\
|
||||
.ace-ptmagic .ace_constant.ace_language {color: #DE8E30}\.ace-ptmagic .ace_constant.ace_numeric {color: #CCCCCC}\
|
||||
.ace-ptmagic .ace_invalid,.ace-ptmagic .ace_invalid.ace_illegal {color: #F8F8F8;background-color: rgba(86, 45, 86, 0.75)}\
|
||||
.ace-ptmagic .ace_invalid.ace_deprecated {text-decoration: underline;font-style: italic;color: #D2A8A1}\
|
||||
.ace-ptmagic .ace_fold {background-color: #757aD8;border-color: #8F938F}\
|
||||
.ace-ptmagic .ace_support.ace_function {color: #AEB2F8}\
|
||||
.ace-ptmagic .ace_string {color: #66A968}\
|
||||
.ace-ptmagic .ace_string.ace_regexp {color: #E9C062}\
|
||||
.ace-ptmagic .ace_comment {color: #33b5e5}\
|
||||
.ace-ptmagic .ace_variable {color: #BEBF55}\
|
||||
.ace-ptmagic .ace_variable.ace_language {color: #C1C144}\
|
||||
.ace-ptmagic .ace_xml-pe {color: #494949}\
|
||||
.ace-ptmagic .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYIiPj/8PAARgAh2NTMh8AAAAAElFTkSuQmCC) right repeat-y}";
|
||||
|
||||
var r = e("../lib/dom"); r.importCssString(t.cssText, t.cssClass)
|
||||
});
|
||||
(function () {
|
||||
window.require(["ace/theme/ptmagic"], function (m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -6,7 +6,7 @@ using Core.Helper;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
||||
[assembly: AssemblyVersion("2.4.3")]
|
||||
[assembly: AssemblyVersion("2.4.4")]
|
||||
[assembly: AssemblyProduct("PT Magic")]
|
||||
|
||||
namespace PTMagic
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
PT API properties (unavailable via swagger UI)
|
||||
--------------------------------------------
|
||||
|
||||
{"sellOnlyMode":false
|
||||
"role":"A"
|
||||
"enableConfig":true
|
||||
"enableShutdown":true
|
||||
"passwordSet":true
|
||||
"language":"ENUS"
|
||||
"currency":"USD"
|
||||
"skin":"dark"
|
||||
"testMode":false
|
||||
"shorting":true
|
||||
"margin":false
|
||||
"testnet":false
|
||||
"activeConfig":"MyConfig1"
|
||||
"availableConfigs":"[\"MyConfig1\"
|
||||
\"MyConfig2\"
|
||||
\"MyConfig3\"
|
||||
\"MyConfig4\"
|
||||
\"MyConfig5\"]"
|
||||
"availableSignalProviders":"[]"
|
||||
"publicConfigs":"[\"public-ProfitTrailer_Three_Amigos-V4\"
|
||||
\"public-ProfitTrailer_Conners2RSI-V2\"
|
||||
\"public-ProfitTrailer_Fibonacci_Day_Trader-V1\"
|
||||
\"public-ProfitTrailer_Signals_Template-V2\"
|
||||
\"public-AwesomeSignals_Starter-V1\"
|
||||
\"public-ProfitTrailer_Nifty_Fifty-V1\"
|
||||
\"public-CryptosetSignal_ADVconfig-V5\"
|
||||
\"public-ProfitTrailer_Trade_Panther-V1\"
|
||||
\"public-Collective_Signals_Template-V4\"
|
||||
\"public-ProfitTrailer_Fibonacci_Swing_Trader-V2\"
|
||||
\"public-ProfitTrailer_RocketMan-V2\"
|
||||
\"public-ProfitTrailer_OldFaithful-V6\"
|
||||
\"public-ProfitTrailer_FrankenStrategy-V8\"
|
||||
\"public-ProfitTrailer_Jobbing_The_Market-V5\"
|
||||
\"public-ProfitTrailer_Golden_Cross-V3\"
|
||||
\"public-ProfitTrailer_Spanish_Cross-V5\"
|
||||
\"public-ProfitTrailer_Monte_Carlo-V8\"
|
||||
\"public-ProfitTrailer_Bride_of_FrankenStrategy-V5\"
|
||||
\"public-ProfitTrailer_Base_Settings-V3\"
|
||||
\"public-ProfitTrailer_DoubleCross-V8\"
|
||||
\"public-ProfitTrailer_ElToro-V7\"
|
||||
\"public-ProfitTrailer_ElDorado-V8\"]"
|
||||
"myPublicConfigs":"[]"
|
||||
"myProducts":"[]"
|
||||
"isAllowedToPublish":false
|
||||
"maxConfigsAllowed":13
|
||||
"licenseType":"PRO"
|
||||
"upTime":"2020-07-17T15:30:44.140"
|
||||
"port":8095
|
||||
"sslEnabled":false
|
||||
"displayAdvancedStats":true
|
||||
"displayFullVersion":true
|
||||
"displayButtons":true
|
||||
"isMarketOrderSupported":true
|
||||
"isLeverageExchange":true
|
||||
"hasTestNet":false
|
||||
"isPTFeederEnabled":false
|
||||
"baseUrl":"http://x.x.x.x:xxxx"}
|
Loading…
Reference in New Issue