Target profit column introduced in the dashboard

This commit is contained in:
djbadders 2020-03-25 22:55:47 +00:00
parent 5a0db4d766
commit a5faee8603
5 changed files with 289 additions and 439 deletions

View File

@ -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; }

View File

@ -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)

View File

@ -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>";

View File

@ -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")) + "%" : "&nbsp")</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>

View File

@ -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