Target profit column introduced in the dashboard
This commit is contained in:
parent
5a0db4d766
commit
a5faee8603
|
@ -456,6 +456,7 @@ namespace Core.Main.DataObjects.PTMagicData
|
||||||
public double AverageBuyPrice { get; set; }
|
public double AverageBuyPrice { get; set; }
|
||||||
public double TotalCost { get; set; }
|
public double TotalCost { get; set; }
|
||||||
public double CurrentValue { get; set; }
|
public double CurrentValue { get; set; }
|
||||||
|
public double? TargetGainValue { get; set; }
|
||||||
public double Amount { get; set; }
|
public double Amount { get; set; }
|
||||||
public double CurrentPrice { get; set; }
|
public double CurrentPrice { get; set; }
|
||||||
public double SellTrigger { get; set; }
|
public double SellTrigger { get; set; }
|
||||||
|
|
|
@ -338,69 +338,91 @@ namespace Core.Main.DataObjects
|
||||||
|
|
||||||
private void BuildDCALogData(dynamic rawDCALogData, dynamic rawPairsLogData, dynamic rawPendingLogData, dynamic rawWatchModeLogData)
|
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 dcaLogData = new DCALogData();
|
||||||
dcaLogData.Amount = rdld.totalAmount;
|
dcaLogData.Amount = pair.totalAmount;
|
||||||
dcaLogData.BoughtTimes = rdld.boughtTimes;
|
dcaLogData.BoughtTimes = pair.boughtTimes;
|
||||||
dcaLogData.Market = rdld.market;
|
dcaLogData.Market = pair.market;
|
||||||
dcaLogData.ProfitPercent = rdld.profit;
|
dcaLogData.ProfitPercent = pair.profit;
|
||||||
dcaLogData.AverageBuyPrice = rdld.avgPrice;
|
dcaLogData.AverageBuyPrice = pair.avgPrice;
|
||||||
dcaLogData.TotalCost = rdld.totalCost;
|
dcaLogData.TotalCost = pair.totalCost;
|
||||||
dcaLogData.BuyTriggerPercent = rdld.buyProfit;
|
dcaLogData.BuyTriggerPercent = pair.buyProfit;
|
||||||
dcaLogData.CurrentLowBBValue = rdld.bbLow == null ? 0 : rdld.bbLow;
|
dcaLogData.CurrentLowBBValue = pair.bbLow == null ? 0 : pair.bbLow;
|
||||||
dcaLogData.CurrentHighBBValue = rdld.highBb == null ? 0 : rdld.highBb;
|
dcaLogData.CurrentHighBBValue = pair.highBb == null ? 0 : pair.highBb;
|
||||||
dcaLogData.BBTrigger = rdld.bbTrigger == null ? 0 : rdld.bbTrigger;
|
dcaLogData.BBTrigger = pair.bbTrigger == null ? 0 : pair.bbTrigger;
|
||||||
dcaLogData.CurrentPrice = rdld.currentPrice;
|
dcaLogData.CurrentPrice = pair.currentPrice;
|
||||||
dcaLogData.SellTrigger = rdld.triggerValue == null ? 0 : rdld.triggerValue;
|
dcaLogData.SellTrigger = pair.triggerValue == null ? 0 : pair.triggerValue;
|
||||||
dcaLogData.PercChange = rdld.percChange;
|
dcaLogData.PercChange = pair.percChange;
|
||||||
dcaLogData.BuyStrategy = rdld.buyStrategy == null ? "" : rdld.buyStrategy;
|
dcaLogData.BuyStrategy = pair.buyStrategy == null ? "" : pair.buyStrategy;
|
||||||
dcaLogData.SellStrategy = rdld.sellStrategy == null ? "" : rdld.sellStrategy;
|
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;
|
foreach (var bs in pair.buyStrategies)
|
||||||
dcaLogData.IsTrue = ((string)rdld.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rdld.buyStrategies != null)
|
|
||||||
{
|
{
|
||||||
foreach (var bs in rdld.buyStrategies)
|
Strategy buyStrategy = new Strategy();
|
||||||
{
|
buyStrategy.Type = bs.type;
|
||||||
Strategy buyStrategy = new Strategy();
|
buyStrategy.Name = bs.name;
|
||||||
buyStrategy.Type = bs.type;
|
buyStrategy.EntryValue = bs.entryValue;
|
||||||
buyStrategy.Name = bs.name;
|
buyStrategy.EntryValueLimit = bs.entryValueLimit;
|
||||||
buyStrategy.EntryValue = bs.entryValue;
|
buyStrategy.TriggerValue = bs.triggerValue;
|
||||||
buyStrategy.EntryValueLimit = bs.entryValueLimit;
|
buyStrategy.CurrentValue = bs.currentValue;
|
||||||
buyStrategy.TriggerValue = bs.triggerValue;
|
buyStrategy.CurrentValuePercentage = bs.currentValuePercentage;
|
||||||
buyStrategy.CurrentValue = bs.currentValue;
|
buyStrategy.Decimals = bs.decimals;
|
||||||
buyStrategy.CurrentValuePercentage = bs.currentValuePercentage;
|
buyStrategy.IsTrailing = ((string)bs.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||||
buyStrategy.Decimals = bs.decimals;
|
buyStrategy.IsTrue = ((string)bs.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||||
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;
|
||||||
Strategy sellStrategy = new Strategy();
|
sellStrategy.Name = ss.name;
|
||||||
sellStrategy.Type = ss.type;
|
sellStrategy.EntryValue = ss.entryValue;
|
||||||
sellStrategy.Name = ss.name;
|
sellStrategy.EntryValueLimit = ss.entryValueLimit;
|
||||||
sellStrategy.EntryValue = ss.entryValue;
|
sellStrategy.TriggerValue = ss.triggerValue;
|
||||||
sellStrategy.EntryValueLimit = ss.entryValueLimit;
|
sellStrategy.CurrentValue = ss.currentValue;
|
||||||
sellStrategy.TriggerValue = ss.triggerValue;
|
sellStrategy.CurrentValuePercentage = ss.currentValuePercentage;
|
||||||
sellStrategy.CurrentValue = ss.currentValue;
|
sellStrategy.Decimals = ss.decimals;
|
||||||
sellStrategy.CurrentValuePercentage = ss.currentValuePercentage;
|
sellStrategy.IsTrailing = ((string)ss.positive).IndexOf("trailing", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||||
sellStrategy.Decimals = ss.decimals;
|
sellStrategy.IsTrue = ((string)ss.positive).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
|
||||||
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 +430,12 @@ namespace Core.Main.DataObjects
|
||||||
// Calculate current value
|
// Calculate current value
|
||||||
dcaLogData.CurrentValue = dcaLogData.CurrentPrice * dcaLogData.Amount;
|
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);
|
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
|
// 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);
|
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 +452,7 @@ namespace Core.Main.DataObjects
|
||||||
_dcaLog.Add(dcaLogData);
|
_dcaLog.Add(dcaLogData);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var rpld in rawPairsLogData)
|
return pairs;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildBuyLogData(dynamic rawBuyLogData)
|
private void BuildBuyLogData(dynamic rawBuyLogData)
|
||||||
|
|
|
@ -1,222 +1,215 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Security;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Core.Main;
|
using Core.Main;
|
||||||
using Core.Helper;
|
using Core.Helper;
|
||||||
using Core.Main.DataObjects.PTMagicData;
|
using Core.Main.DataObjects.PTMagicData;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Core.ProfitTrailer
|
namespace Core.ProfitTrailer
|
||||||
{
|
{
|
||||||
public class OperandToken : Token
|
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)
|
||||||
{
|
{
|
||||||
}
|
_text = text;
|
||||||
public class OrToken : OperandToken
|
_reader = new StringReader(text);
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AndToken : OperandToken
|
public IEnumerable<Token> Tokenize()
|
||||||
{
|
{
|
||||||
}
|
var tokens = new List<Token>();
|
||||||
|
while (_reader.Peek() != -1)
|
||||||
public class BooleanValueToken : Token
|
{
|
||||||
{
|
while (Char.IsWhiteSpace((char)_reader.Peek()))
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
_text = text;
|
_reader.Read();
|
||||||
_reader = new StringReader(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Token> Tokenize()
|
if (_reader.Peek() == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var c = (char)_reader.Peek();
|
||||||
|
switch (c)
|
||||||
{
|
{
|
||||||
var tokens = new List<Token>();
|
case '!':
|
||||||
while (_reader.Peek() != -1)
|
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()))
|
var token = ParseKeyword();
|
||||||
{
|
tokens.Add(token);
|
||||||
_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);
|
|
||||||
}
|
}
|
||||||
|
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)
|
var potentialKeyword = text.ToString().ToLower();
|
||||||
{
|
|
||||||
_tokens = tokens.GetEnumerator();
|
|
||||||
_tokens.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Parse()
|
switch (potentialKeyword)
|
||||||
{
|
{
|
||||||
while (_tokens.Current != null)
|
case "true":
|
||||||
{
|
return new TrueToken();
|
||||||
var isNegated = _tokens.Current is NegationToken;
|
case "false":
|
||||||
if (isNegated)
|
return new FalseToken();
|
||||||
_tokens.MoveNext();
|
case "and":
|
||||||
|
return new AndToken();
|
||||||
var boolean = ParseBoolean();
|
case "or":
|
||||||
if (isNegated)
|
return new OrToken();
|
||||||
boolean = !boolean;
|
default:
|
||||||
|
throw new Exception("Expected keyword (True, False, and, or) but found " + potentialKeyword);
|
||||||
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 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
|
public static class StrategyHelper
|
||||||
{
|
{
|
||||||
|
@ -238,7 +231,7 @@ namespace Core.ProfitTrailer
|
||||||
// strategy labels that are variable, so can't be caught by the switch statement
|
// strategy labels that are variable, so can't be caught by the switch statement
|
||||||
if (result.Contains("REBUY"))
|
if (result.Contains("REBUY"))
|
||||||
{
|
{
|
||||||
time = strategyName.Remove(0,14);
|
time = strategyName.Remove(0, 14);
|
||||||
result = "REBUY " + time;
|
result = "REBUY " + time;
|
||||||
}
|
}
|
||||||
if (result.Contains("CHANGE PERC"))
|
if (result.Contains("CHANGE PERC"))
|
||||||
|
@ -247,8 +240,8 @@ namespace Core.ProfitTrailer
|
||||||
}
|
}
|
||||||
if (result.Contains("LEVERAGE"))
|
if (result.Contains("LEVERAGE"))
|
||||||
{
|
{
|
||||||
leverage = strategyName.Remove(0,10);
|
leverage = strategyName.Remove(0, 10);
|
||||||
leverage = leverage.Remove(leverage.Length -1, 1);
|
leverage = leverage.Remove(leverage.Length - 1, 1);
|
||||||
result = leverage + " X";
|
result = leverage + " X";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +249,7 @@ namespace Core.ProfitTrailer
|
||||||
// remove the letter and colon, change to shortcut, then reapply the letter and colon
|
// remove the letter and colon, change to shortcut, then reapply the letter and colon
|
||||||
if (strategyName.Contains(":"))
|
if (strategyName.Contains(":"))
|
||||||
{
|
{
|
||||||
int strategyLength = strategyName.Length-3;
|
int strategyLength = strategyName.Length - 3;
|
||||||
strategyLetter = strategyName.Remove(3, strategyLength);
|
strategyLetter = strategyName.Remove(3, strategyLength);
|
||||||
strategyNameOnly = strategyName.Remove(0, 3);
|
strategyNameOnly = strategyName.Remove(0, 3);
|
||||||
}
|
}
|
||||||
|
@ -580,8 +573,9 @@ namespace Core.ProfitTrailer
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetStrategyText(Summary summary, List<Strategy> strategies, string strategyText, bool isTrue, bool isTrailingBuyActive)
|
public static string GetStrategyText(Summary summary, List<Strategy> strategies, string strategyText, bool isTrue, bool isTrailingBuyActive)
|
||||||
{
|
{
|
||||||
bool isValidStrategy = false;
|
bool isValidStrategy = false;
|
||||||
|
Regex regx = new Regex(@"[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", RegexOptions.Compiled);
|
||||||
|
|
||||||
if (strategies.Count > 0)
|
if (strategies.Count > 0)
|
||||||
{
|
{
|
||||||
|
@ -591,24 +585,25 @@ namespace Core.ProfitTrailer
|
||||||
|
|
||||||
isValidStrategy = StrategyHelper.IsValidStrategy(strategy.Name);
|
isValidStrategy = StrategyHelper.IsValidStrategy(strategy.Name);
|
||||||
|
|
||||||
if (!isValidStrategy )
|
if (!isValidStrategy)
|
||||||
{
|
{
|
||||||
// Parse Formulas
|
// Parse Formulas
|
||||||
if (strategy.Name.Contains("FORMULA") && !strategy.Name.Contains("STATS"))
|
if (strategy.Name.Contains("FORMULA") && !strategy.Name.Contains("STATS"))
|
||||||
{
|
{
|
||||||
string expression = strategy.Name.Remove(0, 10);
|
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 = expression.Replace("<span class=\"tdgreen\">", "true").Replace("<span class=\"red\">", "false").Replace("</span>", "").Replace("&&", "and").Replace("||", "or");
|
||||||
expression = Regex.Replace(expression, @"[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", String.Empty);
|
expression = regx.Replace(expression, String.Empty);
|
||||||
var tokens = new Tokenizer(expression).Tokenize();
|
var tokens = new Tokenizer(expression).Tokenize();
|
||||||
var parser = new Parser(tokens);
|
var parser = new Parser(tokens);
|
||||||
if (parser.Parse()) {
|
if (parser.Parse())
|
||||||
|
{
|
||||||
strategyText += "<span class=\"label label-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
strategyText += "<span class=\"label label-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strategyText += "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
strategyText += "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -639,14 +634,14 @@ namespace Core.ProfitTrailer
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
isValidStrategy = StrategyHelper.IsValidStrategy(strategyText);
|
isValidStrategy = StrategyHelper.IsValidStrategy(strategyText);
|
||||||
|
|
||||||
if (isValidStrategy)
|
if (isValidStrategy)
|
||||||
{
|
{
|
||||||
strategyText = "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategyText + "\">" + StrategyHelper.GetStrategyShortcut(strategyText, true) + "</span>";
|
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)
|
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>";
|
strategyText = "<span class=\"label label-muted\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Not Applicable: Not using DCA!\"></span>";
|
||||||
|
|
|
@ -98,6 +98,7 @@
|
||||||
<th></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 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 sell strategies">Sell Strats</th>
|
||||||
|
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Target Profit for sale">Target Profit</th>
|
||||||
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Current Profit">Profit</th>
|
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Current Profit">Profit</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -201,6 +202,8 @@
|
||||||
|
|
||||||
<td>@Html.Raw(sellStrategyText)</td>
|
<td>@Html.Raw(sellStrategyText)</td>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
@if(!@lostValue)
|
@if(!@lostValue)
|
||||||
{
|
{
|
||||||
<td class="text-autocolor">@dcaLogEntry.ProfitPercent.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
<td class="text-autocolor">@dcaLogEntry.ProfitPercent.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>
|
||||||
|
@ -214,9 +217,13 @@
|
||||||
</tr>
|
</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>@Html.Raw(Model.TotalBagCost.ToString("#,#0.000000", new System.Globalization.CultureInfo("en-US")))</td>
|
||||||
<td></td><td></td><td></td>
|
<td></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 class="text-autocolor">@Html.Raw((((Model.TotalBagValue - Model.TotalBagCost) / Model.TotalBagCost) * 100).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))%</td>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -6,7 +6,7 @@ using Core.Helper;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|
||||||
[assembly: AssemblyVersion("2.4.3")]
|
[assembly: AssemblyVersion("2.4.4")]
|
||||||
[assembly: AssemblyProduct("PT Magic")]
|
[assembly: AssemblyProduct("PT Magic")]
|
||||||
|
|
||||||
namespace PTMagic
|
namespace PTMagic
|
||||||
|
|
Loading…
Reference in New Issue