2018-05-22 10:11:50 +02:00
|
|
|
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;
|
2019-05-05 12:17:32 +02:00
|
|
|
using System.Text.RegularExpressions;
|
2018-05-22 10:11:50 +02:00
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
namespace Core.ProfitTrailer
|
|
|
|
{
|
2019-05-05 12:17:32 +02:00
|
|
|
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;
|
|
|
|
_reader = new StringReader(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
public IEnumerable<Token> Tokenize()
|
|
|
|
{
|
|
|
|
var tokens = new List<Token>();
|
|
|
|
while (_reader.Peek() != -1)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static class StrategyHelper
|
|
|
|
{
|
|
|
|
public static string GetStrategyShortcut(string strategyName, bool onlyValidStrategies)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
string result = strategyName;
|
2019-04-10 06:17:39 +02:00
|
|
|
string time = "";
|
2020-01-01 16:33:31 +01:00
|
|
|
string leverage = "";
|
2019-04-23 14:20:19 +02:00
|
|
|
string strategyLetter = "";
|
|
|
|
string strategyNameOnly = strategyName;
|
2019-04-10 06:17:39 +02:00
|
|
|
|
2019-05-18 11:23:57 +02:00
|
|
|
// PT allows for "advanced_stats" to be turned on in the application settings, to show details of the trailing logic.
|
|
|
|
// This code ensures PTM doesn't generate an unnecessary shortcut for this information
|
|
|
|
if (result.Contains("STATS"))
|
|
|
|
{
|
|
|
|
result = "";
|
|
|
|
}
|
|
|
|
|
2019-04-11 04:20:03 +02:00
|
|
|
// strategy labels that are variable, so can't be caught by the switch statement
|
2019-04-10 06:17:39 +02:00
|
|
|
if (result.Contains("REBUY"))
|
|
|
|
{
|
|
|
|
time = strategyName.Remove(0,14);
|
|
|
|
result = "REBUY " + time;
|
|
|
|
}
|
|
|
|
if (result.Contains("CHANGE PERC"))
|
|
|
|
{
|
|
|
|
result = "CHANGE";
|
|
|
|
}
|
2020-01-01 16:33:31 +01:00
|
|
|
if (result.Contains("LEVERAGE"))
|
|
|
|
{
|
|
|
|
leverage = strategyName.Remove(0,10);
|
|
|
|
leverage = leverage.Remove(leverage.Length -1, 1);
|
|
|
|
result = leverage + " X";
|
|
|
|
}
|
2018-05-22 10:11:50 +02:00
|
|
|
|
2020-03-25 19:02:59 +01:00
|
|
|
// buy/sell strategies beginning with PT 2.3.3 contain the strategy designation letter followed by a colon and space.
|
2019-04-23 14:20:19 +02:00
|
|
|
// remove the letter and colon, change to shortcut, then reapply the letter and colon
|
|
|
|
if (strategyName.Contains(":"))
|
|
|
|
{
|
|
|
|
int strategyLength = strategyName.Length-3;
|
|
|
|
strategyLetter = strategyName.Remove(3, strategyLength);
|
|
|
|
strategyNameOnly = strategyName.Remove(0, 3);
|
|
|
|
}
|
2019-04-23 13:27:12 +02:00
|
|
|
switch (strategyNameOnly.ToLower())
|
2018-12-15 22:07:29 +01:00
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
case "lowbb":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "LBB");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "highbb":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "HBB");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "gain":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "GAIN");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "loss":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "LOSS");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "smagain":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "SMAG");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "emagain":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "EMAG");
|
2019-01-24 13:09:45 +01:00
|
|
|
break;
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmagain":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "HMAG");
|
2019-01-24 13:09:45 +01:00
|
|
|
break;
|
2019-01-24 13:03:19 +01:00
|
|
|
case "dmagain":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "DMAG");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "smaspread":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "SMAS");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "emaspread":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "EMAS");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmaspread":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "HMAS");
|
2019-01-24 13:09:45 +01:00
|
|
|
break;
|
2019-01-24 13:03:19 +01:00
|
|
|
case "dmaspread":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "DMAS");
|
2019-01-24 13:09:45 +01:00
|
|
|
break;
|
2018-05-22 10:11:50 +02:00
|
|
|
case "smacross":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "SMAC");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "emacross":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "EMAC");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmacross":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "HMAC");
|
2019-01-24 13:03:19 +01:00
|
|
|
break;
|
|
|
|
case "dmacross":
|
2019-12-10 11:17:07 +01:00
|
|
|
result = String.Concat(strategyLetter, "DMAC");
|
2019-01-24 13:03:19 +01:00
|
|
|
break;
|
2018-05-22 10:11:50 +02:00
|
|
|
case "rsi":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "RSI");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "stoch":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "STOCH");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "stochrsi":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "SRSI");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
2018-12-01 17:55:12 +01:00
|
|
|
case "stochrsik":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "SRSIK");
|
2018-12-01 17:55:12 +01:00
|
|
|
break;
|
|
|
|
case "stochrsid":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "SRSID");
|
2018-12-01 17:55:12 +01:00
|
|
|
break;
|
|
|
|
case "stochrsicross":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "SRSIC");
|
2018-12-01 17:55:12 +01:00
|
|
|
break;
|
2018-05-22 10:11:50 +02:00
|
|
|
case "macd":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "MACD");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "obv":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "OBV");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "bbwidth":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "BBW");
|
2019-01-24 13:09:45 +01:00
|
|
|
break;
|
2019-01-24 13:03:19 +01:00
|
|
|
case "pdhigh":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "PDH");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "anderson":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "AND");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
2019-11-03 17:17:28 +01:00
|
|
|
case "pdlow":
|
|
|
|
result = String.Concat(strategyLetter, "PDL");
|
|
|
|
break;
|
|
|
|
case "pdclose":
|
|
|
|
result = String.Concat(strategyLetter, "PDC");
|
|
|
|
break;
|
|
|
|
case "signal":
|
|
|
|
result = String.Concat(strategyLetter, "SIG");
|
|
|
|
break;
|
|
|
|
case "changepercentage":
|
|
|
|
result = String.Concat(strategyLetter, "CHGPCT");
|
|
|
|
break;
|
|
|
|
case "profitpercentage":
|
|
|
|
result = String.Concat(strategyLetter, "PPCT");
|
|
|
|
break;
|
|
|
|
case "lastdcabuy":
|
|
|
|
result = String.Concat(strategyLetter, "LASTDCA");
|
|
|
|
break;
|
|
|
|
case "fixedprice":
|
|
|
|
result = String.Concat(strategyLetter, "FIXED");
|
|
|
|
break;
|
|
|
|
case "lowatrband":
|
|
|
|
result = String.Concat(strategyLetter, "LATR");
|
|
|
|
break;
|
|
|
|
case "highatrband":
|
|
|
|
result = String.Concat(strategyLetter, "HATR");
|
|
|
|
break;
|
|
|
|
case "atrpercentage":
|
|
|
|
result = String.Concat(strategyLetter, "ATRPCT");
|
|
|
|
break;
|
|
|
|
case "vwappercentage":
|
|
|
|
result = String.Concat(strategyLetter, "VWAP");
|
|
|
|
break;
|
|
|
|
case "mvwappercentage":
|
|
|
|
result = String.Concat(strategyLetter, "MVWAP");
|
|
|
|
break;
|
|
|
|
case "btcdominance":
|
|
|
|
result = String.Concat(strategyLetter, "BTCDOM");
|
|
|
|
break;
|
2019-10-15 15:05:53 +02:00
|
|
|
case "config som enabled":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "SOM");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "max buy times":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "DCAMAX");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "max pairs":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "PAIRS");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "max spread":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "SPREAD");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "price increase":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "INC");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "min buy volume":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "VOL");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "min buy balance":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "MIN");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "coin age":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "AGE");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "too new":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "NEW");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "blacklisted":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "BLACK");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "insufficient balance":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "BAL");
|
2018-05-22 10:11:50 +02:00
|
|
|
break;
|
|
|
|
case "max cost reached":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "COST");
|
2019-03-21 11:13:15 +01:00
|
|
|
break;
|
2019-03-22 15:23:32 +01:00
|
|
|
case "buy value below dust":
|
2019-04-23 13:27:12 +02:00
|
|
|
result = String.Concat(strategyLetter, "DUST");
|
2019-03-22 15:23:32 +01:00
|
|
|
break;
|
2019-07-06 03:49:28 +02:00
|
|
|
case "sell wall detected":
|
|
|
|
result = String.Concat(strategyLetter, "WALL");
|
|
|
|
break;
|
|
|
|
case "ignoring buy trigger":
|
|
|
|
result = String.Concat(strategyLetter, "TRIG");
|
|
|
|
break;
|
2019-11-09 15:46:35 +01:00
|
|
|
case "no dca buy logic":
|
2019-11-10 02:12:37 +01:00
|
|
|
result = String.Concat(strategyLetter, "NODCA");
|
2019-11-09 15:46:35 +01:00
|
|
|
break;
|
2018-05-22 10:11:50 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (onlyValidStrategies)
|
|
|
|
{
|
2019-01-14 05:41:09 +01:00
|
|
|
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)
|
2018-12-15 22:07:29 +01:00
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static bool IsValidStrategy(string strategyName)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
return StrategyHelper.IsValidStrategy(strategyName, false);
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static bool IsValidStrategy(string strategyName, bool checkForAnyInvalid)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
bool result = false;
|
|
|
|
|
2019-04-23 14:20:19 +02:00
|
|
|
// buy/sell strategies beginning with PT 2.3.3 contain the letter followed by a colon and space.
|
2019-04-23 13:27:12 +02:00
|
|
|
if (strategyName.Contains(":"))
|
2019-04-22 20:50:31 +02:00
|
|
|
{
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
|
2019-04-23 13:27:12 +02:00
|
|
|
// Prior to PT 2.3.3
|
2018-12-15 22:07:29 +01:00
|
|
|
if (!checkForAnyInvalid)
|
|
|
|
{
|
|
|
|
switch (strategyName.ToLower())
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
case "lowbb":
|
|
|
|
case "highbb":
|
|
|
|
case "gain":
|
|
|
|
case "loss":
|
|
|
|
case "smagain":
|
|
|
|
case "emagain":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmagain":
|
|
|
|
case "dmagain":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "smaspread":
|
|
|
|
case "emaspread":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmaspread":
|
|
|
|
case "dmaspread":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "smacross":
|
|
|
|
case "emacross":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmacross":
|
|
|
|
case "dmacross":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "rsi":
|
|
|
|
case "stoch":
|
|
|
|
case "stochrsi":
|
2018-12-01 18:06:14 +01:00
|
|
|
case "stochrsik":
|
|
|
|
case "stochrsid":
|
|
|
|
case "stochrsicross":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "macd":
|
|
|
|
case "obv":
|
|
|
|
case "bbwidth":
|
|
|
|
case "anderson":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "dema":
|
|
|
|
case "hma":
|
|
|
|
case "pdhigh":
|
2019-11-03 17:17:28 +01:00
|
|
|
case "pdlow":
|
|
|
|
case "pdclose":
|
2019-02-15 21:26:37 +01:00
|
|
|
case "signal":
|
2019-11-03 17:17:28 +01:00
|
|
|
case "changepercentage":
|
|
|
|
case "profitpercentage":
|
|
|
|
case "lastdcabuy":
|
|
|
|
case "fixedprice":
|
|
|
|
case "lowatrband":
|
|
|
|
case "highatrband":
|
|
|
|
case "atrpercentage":
|
|
|
|
case "vwappercentage":
|
|
|
|
case "mvwappercentage":
|
|
|
|
case "btcdominance":
|
2018-05-22 10:11:50 +02:00
|
|
|
result = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
if (strategyName.IndexOf("max", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("min", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("som", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("price", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("black", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("new", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("insufficient", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("timeout", StringComparison.InvariantCultureIgnoreCase) == -1
|
|
|
|
&& strategyName.IndexOf("spread", StringComparison.InvariantCultureIgnoreCase) == -1
|
2018-12-15 22:07:29 +01:00
|
|
|
&& strategyName.IndexOf("pairs", StringComparison.InvariantCultureIgnoreCase) == -1)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static int GetStrategyValueDecimals(string strategyName)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
int result = 0;
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
switch (strategyName.ToLower())
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
case "lowbb":
|
|
|
|
case "highbb":
|
|
|
|
result = 8;
|
|
|
|
break;
|
|
|
|
case "gain":
|
|
|
|
case "loss":
|
|
|
|
case "smagain":
|
|
|
|
case "emagain":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmagain":
|
|
|
|
case "dmagain":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "smaspread":
|
|
|
|
case "emaspread":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmaspread":
|
|
|
|
case "dmaspread":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "smacross":
|
|
|
|
case "emacross":
|
2019-01-24 13:03:19 +01:00
|
|
|
case "hmacross":
|
|
|
|
case "dmacross":
|
|
|
|
case "anderson":
|
|
|
|
case "pdhigh":
|
2018-05-22 10:11:50 +02:00
|
|
|
result = 2;
|
|
|
|
break;
|
|
|
|
case "rsi":
|
|
|
|
case "stochrsi":
|
2018-12-01 18:06:14 +01:00
|
|
|
case "stochrsik":
|
|
|
|
case "stochrsid":
|
|
|
|
case "stochrsicross":
|
2018-05-22 10:11:50 +02:00
|
|
|
case "stoch":
|
|
|
|
case "macd":
|
|
|
|
case "obv":
|
|
|
|
case "bbwidth":
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static string GetStrategyText(Summary summary, List<Strategy> strategies, string strategyText, bool isTrue, bool isTrailingBuyActive)
|
2019-02-23 04:20:07 +01:00
|
|
|
{
|
|
|
|
bool isValidStrategy = false;
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (strategies.Count > 0)
|
|
|
|
{
|
|
|
|
foreach (Strategy strategy in strategies)
|
|
|
|
{
|
2018-06-05 09:40:22 +02:00
|
|
|
string textClass = (strategy.IsTrue) ? "label-success" : "label-danger";
|
2019-02-23 04:20:07 +01:00
|
|
|
|
|
|
|
isValidStrategy = StrategyHelper.IsValidStrategy(strategy.Name);
|
|
|
|
|
2019-04-23 13:27:12 +02:00
|
|
|
if (!isValidStrategy )
|
2018-12-15 22:07:29 +01:00
|
|
|
{
|
2019-05-05 12:17:32 +02:00
|
|
|
// Parse Formulas
|
2019-12-08 14:07:00 +01:00
|
|
|
if (strategy.Name.Contains("FORMULA") && !strategy.Name.Contains("STATS"))
|
2019-04-23 13:27:12 +02:00
|
|
|
{
|
2019-05-05 12:17:32 +02:00
|
|
|
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> ";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strategyText += "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"CONDITIONAL FORMULA\">(FORM)</span> ";
|
|
|
|
}
|
|
|
|
|
2019-04-23 13:27:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strategyText += "<span class=\"label label-warning\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategy.Name + "\">" + StrategyHelper.GetStrategyShortcut(strategy.Name, false) + "</span> ";
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
strategyText += "<span class=\"label " + textClass + "\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategy.Name + "\">" + StrategyHelper.GetStrategyShortcut(strategy.Name, false) + "</span> ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (isTrailingBuyActive)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
strategyText += " <i class=\"fa fa-flag text-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Trailing active!\"></i>";
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (isTrue)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
strategyText = "<span class=\"label label-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategyText + "\">" + StrategyHelper.GetStrategyShortcut(strategyText, true) + "</span>";
|
2018-06-05 09:40:22 +02:00
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (isTrailingBuyActive)
|
|
|
|
{
|
2018-06-05 09:40:22 +02:00
|
|
|
strategyText += " <i class=\"fa fa-flag text-success\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Trailing active!\"></i>";
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-02-23 04:20:07 +01:00
|
|
|
|
|
|
|
isValidStrategy = StrategyHelper.IsValidStrategy(strategyText);
|
|
|
|
|
|
|
|
if (isValidStrategy)
|
2018-12-15 22:07:29 +01:00
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
strategyText = "<span class=\"label label-danger\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategyText + "\">" + StrategyHelper.GetStrategyShortcut(strategyText, true) + "</span>";
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
2019-02-23 04:20:07 +01:00
|
|
|
|
|
|
|
else if (strategyText.Equals("") && isValidStrategy == false)
|
2018-12-15 22:07:29 +01:00
|
|
|
{
|
2019-02-23 04:20:07 +01:00
|
|
|
strategyText = "<span class=\"label label-muted\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Not Applicable: Not using DCA!\"></span>";
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
strategyText = "<span class=\"label label-warning\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + strategyText + "\">" + StrategyHelper.GetStrategyShortcut(strategyText, false) + "</span> ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return strategyText;
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static string GetCurrentValueText(List<Strategy> strategies, string strategyText, double bbValue, double simpleValue, bool includeShortcut)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
string result = "";
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (strategies.Count > 0)
|
|
|
|
{
|
|
|
|
foreach (Strategy strategy in strategies)
|
|
|
|
{
|
|
|
|
if (StrategyHelper.IsValidStrategy(strategy.Name))
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
if (!result.Equals("")) result += "<br />";
|
|
|
|
|
|
|
|
string decimalFormat = "";
|
|
|
|
int decimals = StrategyHelper.GetStrategyValueDecimals(strategy.Name);
|
2018-12-15 22:07:29 +01:00
|
|
|
for (int d = 1; d <= decimals; d++)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
decimalFormat += "0";
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (includeShortcut)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += "<span class=\"text-muted\">" + StrategyHelper.GetStrategyShortcut(strategy.Name, true) + "</span> ";
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (StrategyHelper.GetStrategyShortcut(strategy.Name, true).IndexOf("and", StringComparison.InvariantCultureIgnoreCase) > -1)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += simpleValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (decimals == 0)
|
|
|
|
{
|
|
|
|
if (!SystemHelper.IsInteger(strategy.CurrentValue))
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.CurrentValue.ToString("#,#", new System.Globalization.CultureInfo("en-US"));
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.CurrentValue.ToString("#,#0", new System.Globalization.CultureInfo("en-US"));
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.CurrentValue.ToString("#,#0." + decimalFormat, new System.Globalization.CultureInfo("en-US"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (StrategyHelper.GetStrategyShortcut(strategyText, true).IndexOf("bb", StringComparison.InvariantCultureIgnoreCase) > -1)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result = bbValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result = simpleValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
public static string GetTriggerValueText(Summary summary, List<Strategy> strategies, string strategyText, double bbValue, double simpleValue, int buyLevel, bool includeShortcut)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
string result = "";
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (strategies.Count > 0)
|
|
|
|
{
|
|
|
|
foreach (Strategy strategy in strategies)
|
|
|
|
{
|
|
|
|
if (StrategyHelper.IsValidStrategy(strategy.Name))
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
if (!result.Equals("")) result += "<br />";
|
|
|
|
|
|
|
|
string decimalFormat = "";
|
|
|
|
int decimals = StrategyHelper.GetStrategyValueDecimals(strategy.Name);
|
2018-12-15 22:07:29 +01:00
|
|
|
for (int d = 1; d <= decimals; d++)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
decimalFormat += "0";
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (includeShortcut)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += "<span class=\"text-muted\">" + StrategyHelper.GetStrategyShortcut(strategy.Name, true) + "</span> ";
|
|
|
|
}
|
|
|
|
|
2018-12-15 22:07:29 +01:00
|
|
|
if (StrategyHelper.GetStrategyShortcut(strategy.Name, true).IndexOf("and", StringComparison.InvariantCultureIgnoreCase) > -1)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.TriggerValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (decimals == 0)
|
|
|
|
{
|
|
|
|
if (!SystemHelper.IsInteger(strategy.EntryValue))
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.EntryValue.ToString(new System.Globalization.CultureInfo("en-US"));
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.EntryValue.ToString("#,#0", new System.Globalization.CultureInfo("en-US"));
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result += strategy.EntryValue.ToString("#,#0." + decimalFormat, new System.Globalization.CultureInfo("en-US"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (StrategyHelper.GetStrategyShortcut(strategyText, true).IndexOf("bb", StringComparison.InvariantCultureIgnoreCase) > -1)
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
result = bbValue.ToString("#,#0.00000000", new System.Globalization.CultureInfo("en-US"));
|
2018-12-15 22:07:29 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (simpleValue == Constants.MinTrendChange)
|
|
|
|
{
|
|
|
|
if (summary.DCATriggers.ContainsKey(buyLevel + 1))
|
|
|
|
{
|
2018-05-22 10:11:50 +02:00
|
|
|
simpleValue = summary.DCATriggers[buyLevel + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = simpleValue.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
2019-02-15 21:26:37 +01:00
|
|
|
}
|