Merge pull request #231 from HojouFotytu/develop

Enabled Pairs & Ignore Outliers
This commit is contained in:
HojouFotytu 2021-02-02 01:54:37 +09:00 committed by GitHub
commit c7e4cc7b2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 81 additions and 73 deletions

View File

@ -146,6 +146,9 @@ namespace Core.Main.DataObjects.PTMagicData
[DefaultValue("")]
public string AllowedMarkets { get; set; } = "";
[DefaultValue(0)]
public int TrendThreshold { get; set; } = 0;
[DefaultValue(true)]
public bool ExcludeMainCurrency { get; set; } = true;
}

View File

@ -601,7 +601,7 @@ namespace Core.Helper
result = market + mainMarket;
break;
case "BinanceFutures":
result = market + "_" + mainMarket;
result = market + mainMarket;
break;
case "Poloniex":
result = mainMarket + "_" + market;

View File

@ -1310,7 +1310,7 @@ namespace Core.Main
// CoinMarketCap
this.GlobalMarketTrendChanges = BaseAnalyzer.BuildMarketTrends("CoinMarketCap", this.LastRuntimeSummary.MainMarket, new List<string>(), "", true, this.GlobalMarketTrendChanges, this.PTMagicConfiguration, this.Log);
// Bittrex
// Exchange
foreach (MarketTrend marketTrend in this.PTMagicConfiguration.AnalyzerSettings.MarketAnalyzer.MarketTrends.FindAll(mt => mt.Platform.Equals("Exchange", StringComparison.InvariantCultureIgnoreCase)))
{
if (this.SingleMarketTrendChanges.ContainsKey(marketTrend.Name))

View File

@ -18,7 +18,6 @@ namespace Core.MarketAnalyzer
public static string GetJsonStringFromURL(string url, LogHelper log, (string header, string value)[] headers = null)
{
HttpClient webClient = null;
if (webClient == null)
{
webClient = new HttpClient();
@ -52,9 +51,7 @@ namespace Core.MarketAnalyzer
{
// log.DoLogInfo("Calling URL: " + url);
var response = webClient.GetAsync(url).Result;
string repsonseString = response.Content.ReadAsStringAsync().Result;
if (response.IsSuccessStatusCode)
{
return repsonseString;
@ -63,9 +60,7 @@ namespace Core.MarketAnalyzer
{
// Error
var message = string.Format("Error whilst calling {0} - {1}", url, repsonseString);
log.DoLogError(message);
throw new Exception(message);
}
}
@ -73,13 +68,11 @@ namespace Core.MarketAnalyzer
{
// Conneciton timeout
log.DoLogError(string.Format("Timeout whilst calling {0} - {1}", url, tcEx.Message));
throw;
}
catch (Exception ex)
{
log.DoLogError(string.Format("Error whilst calling {0} \nError: {1}", url, ex.Message));
throw;
}
}
@ -87,45 +80,34 @@ namespace Core.MarketAnalyzer
public static Dictionary<string, dynamic> GetJsonFromURL(string url, LogHelper log, (string header, string value)[] headers = null)
{
Dictionary<string, dynamic> jsonObject = null;
string jsonString = GetJsonStringFromURL(url, log, headers);
// Convert the response to JSON
jsonObject = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(jsonString);
return jsonObject;
}
public static Newtonsoft.Json.Linq.JObject GetSimpleJsonObjectFromURL(string url, LogHelper log, (string header, string value)[] headers = null)
{
Newtonsoft.Json.Linq.JObject jsonObject = null;
string jsonString = GetJsonStringFromURL(url, log, headers);
jsonObject = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(jsonString);
return jsonObject;
}
public static List<dynamic> GetSimpleJsonListFromURL(string url, LogHelper log)
{
List<dynamic> jsonObject = null;
string jsonString = GetJsonStringFromURL(url, log, null);
jsonObject = JsonConvert.DeserializeObject<List<dynamic>>(jsonString);
return jsonObject;
}
public static Newtonsoft.Json.Linq.JArray GetSimpleJsonArrayFromURL(string url, LogHelper log)
{
Newtonsoft.Json.Linq.JArray jsonObject = null;
string jsonString = GetJsonStringFromURL(url, log, null);
jsonObject = JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JArray>(jsonString);
return jsonObject;
}
@ -138,7 +120,6 @@ namespace Core.MarketAnalyzer
string baseUrl = "https://api.github.com/repos/PTMagicians/PTMagic/releases/latest";
Newtonsoft.Json.Linq.JObject jsonObject = GetSimpleJsonObjectFromURL(baseUrl, log, new (string header, string value)[] { ("User-Agent", "PTMagic.Import") });
if (jsonObject != null)
{
result = jsonObject.GetValue("tag_name").ToString();
@ -152,14 +133,12 @@ namespace Core.MarketAnalyzer
{
log.DoLogDebug("GitHub version check error: " + ex.Message);
}
return result;
}
public static double GetMainFiatCurrencyRate(string currency, string FreeCurrencyAPI, LogHelper log)
{
double result = 1;
string baseUrl = "http://free.currencyconverterapi.com/api/v5/convert?q=USD_" + currency + "&compact=y&apiKey=" + FreeCurrencyAPI;
log.DoLogDebug("http://free.currencyconverterapi.com - Getting latest exchange rates...");
@ -171,7 +150,6 @@ namespace Core.MarketAnalyzer
result = (double)jsonObject["USD_" + currency]["val"];
log.DoLogInfo("http://free.currencyconverterapi.com - Latest exchange rate for USD to " + currency + " is " + result);
}
return result;
}
@ -191,12 +169,10 @@ namespace Core.MarketAnalyzer
log.DoLogDebug(ex.Message);
}
}
if (result == null)
{
result = new Dictionary<string, MarketInfo>();
}
return result;
}
@ -208,7 +184,6 @@ namespace Core.MarketAnalyzer
public static Dictionary<string, Market> GetMarketDataFromFile(PTMagicConfiguration systemConfiguration, LogHelper log, string platform, DateTime maxDateTime, string marketCaption)
{
Dictionary<string, Market> result = new Dictionary<string, Market>();
DirectoryInfo dataDirectory = new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + platform + Path.DirectorySeparatorChar);
// Get market files older than max datetime in descending order (newest file up top)
@ -239,7 +214,6 @@ namespace Core.MarketAnalyzer
log.DoLogDebug(platform + " - " + marketCaption + " market data loaded (" + marketFile.LastWriteTimeUtc.ToString() + ")");
}
}
try
{
// Get JSON object
@ -249,7 +223,6 @@ namespace Core.MarketAnalyzer
{
log.DoLogCritical(ex.Message, ex);
}
return result;
}
@ -312,7 +285,6 @@ namespace Core.MarketAnalyzer
{
sortedMarkets = new SortedDictionary<string, Market>(recentMarkets).OrderByDescending(m => m.Value.Volume24h);
}
int marketCount = 1;
foreach (KeyValuePair<string, Market> recentMarketPair in sortedMarkets)
{
@ -336,7 +308,6 @@ namespace Core.MarketAnalyzer
}
Market recentMarket;
if (recentMarkets.TryGetValue(recentMarketPair.Key, out recentMarket))
{
List<string> ignoredMarkets = SystemHelper.ConvertTokenStringToList(marketTrend.IgnoredMarkets, ",");
@ -345,7 +316,6 @@ namespace Core.MarketAnalyzer
log.DoLogDebug(platform + " - Market trend '" + marketTrend.Name + "' for '" + recentMarketPair.Key + "' is ignored in this trend.");
continue;
}
List<string> allowedMarkets = SystemHelper.ConvertTokenStringToList(marketTrend.AllowedMarkets, ",");
if (allowedMarkets.Count > 0 && !allowedMarkets.Contains(recentMarketPair.Value.Symbol))
{
@ -361,12 +331,10 @@ namespace Core.MarketAnalyzer
}
Market trendMarket;
if (trendMarkets.TryGetValue(recentMarketPair.Key, out trendMarket))
{
double recentMarketPrice = recentMarket.Price;
double trendMarketPrice = trendMarket.Price;
if (!platform.Equals("CoinMarketCap", StringComparison.InvariantCulture) && marketTrend.TrendCurrency.Equals("Fiat", StringComparison.InvariantCultureIgnoreCase))
{
if (recentMarket.MainCurrencyPriceUSD > 0 && trendMarket.MainCurrencyPriceUSD > 0)
@ -388,9 +356,7 @@ namespace Core.MarketAnalyzer
mtc.TrendDateTime = DateTime.UtcNow;
result.Add(mtc);
log.DoLogDebug(platform + " - Market trend '" + marketTrend.Name + "' for '" + recentMarketPair.Key + "' (Vol. " + recentMarket.Volume24h.ToString("#,#0.00") + ") is " + trendMarketChange.ToString("#,#0.00") + "% in " + SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60).ToLower() + ".");
marketCount++;
}
else
@ -401,14 +367,11 @@ namespace Core.MarketAnalyzer
}
}
}
if (marketTrend.MaxMarkets > 0 && isGlobal)
{
int maxMarkets = (marketTrend.MaxMarkets <= result.Count) ? marketTrend.MaxMarkets : result.Count;
result = result.GetRange(0, maxMarkets);
}
return result;
}
@ -422,35 +385,49 @@ namespace Core.MarketAnalyzer
foreach (MarketTrend marketTrend in marketTrends)
{
log.DoLogInfo("Building market trend average for '" + marketTrend.Name + "'");
if (globalMarketTrendChanges.ContainsKey(marketTrend.Name))
{
List<MarketTrendChange> marketTrendChanges = globalMarketTrendChanges[marketTrend.Name];
if (marketTrendChanges != null && marketTrendChanges.Count > 0)
{
double averageTrendChange = marketTrendChanges.Average(mtc => mtc.TrendChange);
double totalTrendChange = 0;
int trendChangeCount = marketTrendChanges.Count;
foreach (MarketTrendChange marketTrendChange in marketTrendChanges)
{
if (marketTrend.TrendThreshold != 0)
{
if ((marketTrendChange.TrendChange > marketTrend.TrendThreshold) || (marketTrendChange.TrendChange < (marketTrend.TrendThreshold * -1)))
{
log.DoLogInfo("Market trend '" + marketTrend.Name + "' is ignoring " + marketTrendChange.Market + " for exceeding TrendThreshold.");
trendChangeCount += -1;
}
else
{
totalTrendChange += marketTrendChange.TrendChange;
}
}
else
{
totalTrendChange += marketTrendChange.TrendChange;
}
}
double averageTrendChange = totalTrendChange / trendChangeCount;
result.Add(marketTrend.Name, averageTrendChange);
log.DoLogInfo("Built average market trend change '" + marketTrend.Name + "' (" + averageTrendChange.ToString("#,#0.00") + "% in " + marketTrend.TrendMinutes.ToString() + " minutes) for " + marketTrendChanges.Count.ToString() + " markets.");
}
else
{
result.Add(marketTrend.Name, 0);
log.DoLogWarn("No market trend changes found for '" + marketTrend.Name + "' - returning 0%");
}
}
else
{
result.Add(marketTrend.Name, 0);
log.DoLogWarn("Market trend '" + marketTrend.Name + "' not found in globalMarketTrendChanges[] - returning 0%");
}
}
}
return result;
}
}

View File

@ -19,8 +19,8 @@ namespace Core.ProfitTrailer
string strategyLetter = "";
string strategyNameOnly = strategyName;
// PT allows for "advanced_stats" to show details of the trailing logic.
if (result.Contains("STATS"))
// PT allows for "advanced_stats" to show details of the trailing logic and dynamic formulas.
if (result.Contains("STATS") || result.Contains("DYN"))
{
result = "";
}

View File

@ -162,6 +162,7 @@ else
<th>Name</th>
<th class="text-right">Markets</th>
<th class="text-right">Timeframe</th>
<th class="text-right">Threshold %</th>
<th class="text-right">Change</th>
</tr>
</thead>
@ -182,7 +183,14 @@ else
<tr>
<td>@Core.Helper.SystemHelper.SplitCamelCase(marketTrend.Name)</td>
<td class="text-right">@marketCountString</td>
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td>
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td> @if (marketTrend.TrendThreshold == 0)
{
<td class="text-right">--</td>
}
else
{
<td class="text-right">@marketTrend.TrendThreshold</td>
}
<td class="text-right text-autocolor">@trendChangeOutput%</td>
</tr>
}

View File

@ -77,6 +77,7 @@ namespace Monitor.Pages
mt.TrendCurrency = HttpContext.Request.Form[mtFormKey + "TrendCurrency"];
mt.IgnoredMarkets = HttpContext.Request.Form[mtFormKey + "IgnoredMarkets"];
mt.AllowedMarkets = HttpContext.Request.Form[mtFormKey + "AllowedMarkets"];
mt.TrendThreshold = SystemHelper.TextToInteger(HttpContext.Request.Form[mtFormKey + "TrendThreshold"], mt.TrendThreshold);
mt.DisplayGraph = HttpContext.Request.Form[mtFormKey + "DisplayGraph"].Equals("on");
mt.ExcludeMainCurrency = HttpContext.Request.Form[mtFormKey + "ExcludeMainCurrency"].Equals("on");

View File

@ -10,7 +10,7 @@
}
<div class="row">
<div class="col-md-4 px-1">
<div class="col-md-5 px-1">
<div class="card-box px-2" style="height:305px;">
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
@if (!Model.TrendChartDataJSON.Equals("")) {
@ -48,7 +48,7 @@
</div>
</div>
<div class="col-md-5 px-1">
<div class="col-md-4 px-1">
<div class="cdev" data-percent="100" data-duration="@Html.Raw(@Model.PTMagicConfiguration.GeneralSettings.Monitor.RefreshSeconds * 1000)" data-color="#aaa,#414d59"></div>
<div class="card-box px-2" style="height:305px;">
@if (!Model.ProfitChartDataJSON.Equals("")) {
@ -74,6 +74,7 @@
<th>Name</th>
<th class="text-right">Markets</th>
<th class="text-right">Timeframe</th>
<th class="text-right" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are excluded from the trend average.">Threshold %</th>
<th class="text-right">Change</th>
</tr>
</thead>
@ -95,6 +96,14 @@
<td>@Core.Helper.SystemHelper.SplitCamelCase(marketTrend.Name)</td>
<td class="text-right">@marketCountString</td>
<td class="text-right">@Core.Helper.SystemHelper.GetProperDurationTime(marketTrend.TrendMinutes * 60, false)</td>
@if (marketTrend.TrendThreshold == 0)
{
<td class="text-right">--</td>
}
else
{
<td class="text-right">@marketTrend.TrendThreshold</td>
}
<td class="text-right text-autocolor">@trendChangeOutput%</td>
</tr>
}

View File

@ -206,28 +206,38 @@
<td>@Html.Raw(buyStrategyText)</td>
<td>@Html.Raw(sellStrategyText)</td>
@if (sellStrategyText.Contains("CROSSED"))
// if leverage, recalculate profit target
@if (!sellStrategyText.Contains("WATCHMODE"))
{
string leverageText = sellStrategyText.Remove(0, sellStrategyText.IndexOf("CROSSED")+9);
leverage = leverageText.Remove(leverageText.IndexOf(".0)"), leverageText.Length - leverageText.IndexOf(".0)"));
leverageValue = double.Parse(leverage);
}
@if (sellStrategyText.Contains("ISOLATED"))
{
string leverageText = sellStrategyText.Remove(0, sellStrategyText.IndexOf("ISOLATED")+10);
leverage = leverageText.Remove(leverageText.IndexOf(".0)"), leverageText.Length - leverageText.IndexOf(".0)"));
leverageValue = double.Parse(leverage);
}
@if (leverageValue == 1)
{
<td class="@Html.Raw((dcaLogEntry.TargetGainValue.HasValue && (dcaLogEntry.ProfitPercent > dcaLogEntry.TargetGainValue.Value)) ? "text-success" : "text-danger")">@Html.Raw(dcaLogEntry.TargetGainValue.HasValue ? dcaLogEntry.TargetGainValue.Value.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%" : "&nbsp")</td>
@if (sellStrategyText.Contains("CROSSED"))
// if leverage, recalculate profit target
{
string leverageText = sellStrategyText.Remove(0, sellStrategyText.IndexOf("CROSSED")+9);
leverage = leverageText.Remove(leverageText.IndexOf(".0)"), leverageText.Length - leverageText.IndexOf(".0)"));
leverageValue = double.Parse(leverage);
}
@if (sellStrategyText.Contains("ISOLATED"))
{
string leverageText = sellStrategyText.Remove(0, sellStrategyText.IndexOf("ISOLATED")+10);
leverage = leverageText.Remove(leverageText.IndexOf(".0)"), leverageText.Length - leverageText.IndexOf(".0)"));
leverageValue = double.Parse(leverage);
}
@if (leverageValue == 1)
{
<td class="@Html.Raw((dcaLogEntry.TargetGainValue.HasValue && (dcaLogEntry.ProfitPercent > dcaLogEntry.TargetGainValue.Value)) ? "text-success" : "text-danger")">@Html.Raw(dcaLogEntry.TargetGainValue.HasValue ? dcaLogEntry.TargetGainValue.Value.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%" : "&nbsp")</td>
}
else
{
double TargetGain = leverageValue * dcaLogEntry.TargetGainValue.Value;
<td class="@Html.Raw((dcaLogEntry.TargetGainValue.HasValue && (dcaLogEntry.ProfitPercent > dcaLogEntry.TargetGainValue.Value)) ? "text-success" : "text-danger")">@Html.Raw(dcaLogEntry.TargetGainValue.HasValue ? TargetGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%" : "&nbsp")</td>
}
}
else
{
double leverageTargetGain = leverageValue * dcaLogEntry.TargetGainValue.Value;
<td class="@Html.Raw((dcaLogEntry.TargetGainValue.HasValue && (dcaLogEntry.ProfitPercent > dcaLogEntry.TargetGainValue.Value)) ? "text-success" : "text-danger")">@Html.Raw(dcaLogEntry.TargetGainValue.HasValue ? leverageTargetGain.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")) + "%" : "&nbsp")</td>
<td class="text-left"></td>
}
@if (!@lostValue)
{
<td class="text-autocolor">@dcaLogEntry.ProfitPercent.ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"))%</td>

View File

@ -16,17 +16,17 @@
string iconColor = "text-success";
string ptMagicHealthIcon = "fa-heartbeat";
string ptMagicHealthTooltip = "PT Magic is alive and healthy!";
if (elapsedSecondsSinceRuntime > (intervalSeconds + intervalSeconds)) {
string ptMagicHealthTooltip = "PT Magic is alive and healthy! <br> Time elapsed since last run:"+ lastRuntime;
if (elapsedSecondsSinceRuntime > (intervalSeconds * 2)) {
ptMagicHealthIcon = "fa-exclamation-triangle";
ptMagicHealthTooltip = "PT Magic seems to have problems, check the logs!";
ptMagicHealthTooltip = "PT Magic seems to have problems, check the logs! Time elapsed since last run: "+ Math.Round(elapsedSecondsSinceRuntime / 60, 1) + " mins.";
iconColor = "text-danger";
}
}
<div class="card-box card-box-mini card-box-ptmagic-outlined">
<span data-toggle="tooltip" data-placement="bottom" title="Active global setting">
@Core.Helper.SystemHelper.SplitCamelCase(Model.Summary.CurrentGlobalSetting.SettingName)</span><span class = "header-title"><a href="ManaSettingsAnalyzergeSMS">@Html.Raw(" " + globalSettingInfoIcon)</a></span>
@Core.Helper.SystemHelper.SplitCamelCase(Model.Summary.CurrentGlobalSetting.SettingName)</span><span class = "header-title"><a href="StatusSummary">@Html.Raw(" " + globalSettingInfoIcon)</a></span>
</div>
<div class="card-box card-box-mini card-box-ptmagic-outlined">