From 2ea0ec698a6ae152b0fcefca6a4f63d7017f0305 Mon Sep 17 00:00:00 2001 From: HojouFotytu <36724681+HojouFotytu@users.noreply.github.com> Date: Tue, 15 Oct 2019 22:05:53 +0900 Subject: [PATCH 1/4] Bag Totals and Bug Fixes --- Core/DataObjects/ProfitTrailerData.cs | 2 +- Core/ProfitTrailer/StrategyHelper.cs | 2 +- Monitor/Pages/BagAnalyzer.cshtml | 2 +- Monitor/Pages/_get/DashboardTop.cshtml | 13 ++++++++++++- Monitor/Pages/_get/DashboardTop.cshtml.cs | 4 +++- Monitor/wwwroot/assets/js/analyzer-settings.js | 2 +- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Core/DataObjects/ProfitTrailerData.cs b/Core/DataObjects/ProfitTrailerData.cs index 99a206e..e951049 100644 --- a/Core/DataObjects/ProfitTrailerData.cs +++ b/Core/DataObjects/ProfitTrailerData.cs @@ -615,7 +615,7 @@ namespace Core.Main.DataObjects buyStrategy.IsTrue = ((string)(bs.positive)).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1; // Is SOM? - buyLogData.IsSom = buyLogData.IsSom || buyStrategy.Name.Equals("som enabled", StringComparison.OrdinalIgnoreCase); + buyLogData.IsSom = buyLogData.IsSom || buyStrategy.Name.Contains("som enabled", StringComparison.OrdinalIgnoreCase); // Is the pair trailing? buyLogData.IsTrailing = buyLogData.IsTrailing || buyStrategy.IsTrailing; diff --git a/Core/ProfitTrailer/StrategyHelper.cs b/Core/ProfitTrailer/StrategyHelper.cs index ff30efe..7b0fbf1 100644 --- a/Core/ProfitTrailer/StrategyHelper.cs +++ b/Core/ProfitTrailer/StrategyHelper.cs @@ -336,7 +336,7 @@ namespace Core.ProfitTrailer case "anderson": result = String.Concat(strategyLetter, "AND"); break; - case "som enabled": + case "config som enabled": result = String.Concat(strategyLetter, "SOM"); break; case "max buy times": diff --git a/Monitor/Pages/BagAnalyzer.cshtml b/Monitor/Pages/BagAnalyzer.cshtml index e2a3e3f..de6e9a9 100644 --- a/Monitor/Pages/BagAnalyzer.cshtml +++ b/Monitor/Pages/BagAnalyzer.cshtml @@ -30,7 +30,7 @@ Market Trend Amount - Value + Cost DCA Buy Strats BS Value diff --git a/Monitor/Pages/_get/DashboardTop.cshtml b/Monitor/Pages/_get/DashboardTop.cshtml index bc1377f..e41e687 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml +++ b/Monitor/Pages/_get/DashboardTop.cshtml @@ -94,7 +94,7 @@ Market 24H Trend - Value + Cost DCA Buy Strats Sell Strats @@ -147,6 +147,11 @@ bool lostValue = false; lostValue = (dcaLogEntry.TotalCost == 0.0) || (dcaLogEntry.AverageBuyPrice == 0.0); + // Aggregate totals + Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost; + double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * 0.002; + Model.TotalBagValue = Model.TotalBagValue + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) - TradingFee); + // Render the row @if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0) { @@ -185,6 +190,12 @@ } + + Totals: + @Html.Raw(Model.TotalBagCost.ToString("#,#0.000000", new System.Globalization.CultureInfo("en-US"))) + + @Html.Raw((((Model.TotalBagValue - Model.TotalBagCost) / Model.TotalBagCost) * 100).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))% + diff --git a/Monitor/Pages/_get/DashboardTop.cshtml.cs b/Monitor/Pages/_get/DashboardTop.cshtml.cs index 9c4824e..d01629a 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml.cs +++ b/Monitor/Pages/_get/DashboardTop.cshtml.cs @@ -11,7 +11,7 @@ namespace Monitor.Pages { public class DashboardTopModel : _Internal.BasePageModelSecureAJAX { public ProfitTrailerData PTData = null; public DateTimeOffset DateTimeNow = Constants.confMinDate; - + public void OnGet() { // Initialize Config base.Init(); @@ -19,6 +19,8 @@ namespace Monitor.Pages { BindData(); } + public double TotalBagCost = 0; + public double TotalBagValue = 0; private void BindData() { PTData = this.PtDataObject; diff --git a/Monitor/wwwroot/assets/js/analyzer-settings.js b/Monitor/wwwroot/assets/js/analyzer-settings.js index 405a6c7..b273f0a 100644 --- a/Monitor/wwwroot/assets/js/analyzer-settings.js +++ b/Monitor/wwwroot/assets/js/analyzer-settings.js @@ -93,7 +93,7 @@ const PropertyTemplate = ({ settingType, settingName, propertyType, propertyKey,
- Any variable from PT's settings may be used! + Any variable from PT's settings may be used!
From aa08050fccf286d8aca0296e6a8f94c527a162eb Mon Sep 17 00:00:00 2001 From: HojouFotytu <36724681+HojouFotytu@users.noreply.github.com> Date: Wed, 16 Oct 2019 10:05:19 +0900 Subject: [PATCH 2/4] Exchange fees --- Monitor/Pages/_get/DashboardTop.cshtml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Monitor/Pages/_get/DashboardTop.cshtml b/Monitor/Pages/_get/DashboardTop.cshtml index e41e687..eca954f 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml +++ b/Monitor/Pages/_get/DashboardTop.cshtml @@ -149,7 +149,18 @@ // Aggregate totals Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost; - double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * 0.002; + + if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance")) { + double ExchangeFee = 0.002; + } + if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex")) { + double ExchangeFee = 0.0025; + } + if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex")) { + double ExchangeFee = 0.0025; + } + + double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * ExchangeFee; Model.TotalBagValue = Model.TotalBagValue + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) - TradingFee); // Render the row From 24cb40326abe15613f7b0140e7fc322f3123adfc Mon Sep 17 00:00:00 2001 From: HojouFotytu <36724681+HojouFotytu@users.noreply.github.com> Date: Wed, 16 Oct 2019 14:03:19 +0900 Subject: [PATCH 3/4] Added BinanceUS --- Core/Helper/SystemHelper.cs | 6 + Core/Main/PTMagic.cs | 8 +- Core/MarketAnalyzer/BinanceUS.cs | 455 ++++++++++++++++++++++ Monitor/Pages/MarketAnalyzer.cshtml | 26 +- Monitor/Pages/SettingsGeneral.cshtml | 7 + Monitor/Pages/_get/DashboardBottom.cshtml | 2 +- Monitor/Pages/_get/DashboardTop.cshtml | 11 +- 7 files changed, 508 insertions(+), 7 deletions(-) create mode 100644 Core/MarketAnalyzer/BinanceUS.cs diff --git a/Core/Helper/SystemHelper.cs b/Core/Helper/SystemHelper.cs index f576f9f..5d6c4e3 100644 --- a/Core/Helper/SystemHelper.cs +++ b/Core/Helper/SystemHelper.cs @@ -557,6 +557,9 @@ namespace Core.Helper case "Binance": result = "https://www.binance.com/trade.html?symbol=" + market; break; + case "BinanceUS": + result = "https://www.binance.us/trade.html?symbol=" + market; + break; case "Poloniex": result = "https://poloniex.com/exchange#" + market.ToLower(); break; @@ -578,6 +581,9 @@ namespace Core.Helper case "Binance": result = market + mainMarket; break; + case "BinanceUS": + result = market + mainMarket; + break; case "Poloniex": result = mainMarket + "_" + market; break; diff --git a/Core/Main/PTMagic.cs b/Core/Main/PTMagic.cs index 73217da..2c8d2a1 100644 --- a/Core/Main/PTMagic.cs +++ b/Core/Main/PTMagic.cs @@ -695,6 +695,7 @@ namespace Core.Main // Check if exchange is valid if (!this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase) + && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase)) { this.Log.DoLogError("Exchange '" + this.PTMagicConfiguration.GeneralSettings.Application.Exchange + "' specified in settings.general.json is invalid! Terminating process..."); @@ -1091,7 +1092,7 @@ namespace Core.Main } else { - if (!this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase)) + if (!this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase)) { Log.DoLogError("Your setting for Application.Exchange in settings.general.json is invalid (" + this.PTMagicConfiguration.GeneralSettings.Application.Exchange + ")! Terminating process."); this.Timer.Stop(); @@ -1245,6 +1246,11 @@ namespace Core.Main // Get most recent market data from Binance this.ExchangeMarketList = Binance.GetMarketData(this.LastRuntimeSummary.MainMarket, this.MarketInfos, this.PTMagicConfiguration, this.Log); } + else if (this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase)) + { + // Get most recent market data from BinanceUS + this.ExchangeMarketList = BinanceUS.GetMarketData(this.LastRuntimeSummary.MainMarket, this.MarketInfos, this.PTMagicConfiguration, this.Log); + } else if (this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase)) { diff --git a/Core/MarketAnalyzer/BinanceUS.cs b/Core/MarketAnalyzer/BinanceUS.cs new file mode 100644 index 0000000..d13fe9f --- /dev/null +++ b/Core/MarketAnalyzer/BinanceUS.cs @@ -0,0 +1,455 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text; +using Core.Main; +using Core.Helper; +using Core.Main.DataObjects.PTMagicData; +using Newtonsoft.Json; +using Core.ProfitTrailer; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Concurrent; + +namespace Core.MarketAnalyzer +{ + public class BinanceUS : BaseAnalyzer + { + public static double GetMainCurrencyPrice(string mainMarket, PTMagicConfiguration systemConfiguration, LogHelper log) + { + double result = 0; + + try + { + string baseUrl = "https://api.binance.us/api/v1/ticker/24hr?symbol=" + mainMarket + "USDT"; + + log.DoLogInfo("BinanceUS - Getting main market price..."); + Newtonsoft.Json.Linq.JObject jsonObject = GetSimpleJsonObjectFromURL(baseUrl, log, false); + if (jsonObject != null) + { + log.DoLogInfo("BinanceUS - Market data received for " + mainMarket + "USDT"); + + result = (double)jsonObject.GetValue("lastPrice"); + log.DoLogInfo("BinanceUS - Current price for " + mainMarket + "USDT: " + result.ToString("#,#0.00") + " USD"); + } + } + catch (Exception ex) + { + log.DoLogCritical(ex.Message, ex); + } + + return result; + } + + public static List GetMarketData(string mainMarket, Dictionary marketInfos, PTMagicConfiguration systemConfiguration, LogHelper log) + { + List result = new List(); + + string lastMarket = ""; + Newtonsoft.Json.Linq.JObject lastTicker = null; + try + { + string baseUrl = "https://api.binance.us/api/v1/ticker/24hr"; + + log.DoLogInfo("BinanceUS - Getting market data..."); + Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log); + if (jsonArray.Count > 0) + { + double mainCurrencyPrice = 1; + if (!mainMarket.Equals("USDT", StringComparison.InvariantCultureIgnoreCase)) + { + mainCurrencyPrice = BinanceUS.GetMainCurrencyPrice(mainMarket, systemConfiguration, log); + } + + log.DoLogInfo("BinanceUS - Market data received for " + jsonArray.Count.ToString() + " currencies"); + + if (mainCurrencyPrice > 0) + { + Dictionary markets = new Dictionary(); + foreach (Newtonsoft.Json.Linq.JObject currencyTicker in jsonArray) + { + string marketName = currencyTicker["symbol"].ToString(); + //New variables for filtering out bad markets + float marketLastPrice = currencyTicker["lastPrice"].ToObject(); + float marketVolume = currencyTicker["volume"].ToObject(); + if (marketName.EndsWith(mainMarket, StringComparison.InvariantCultureIgnoreCase)) + { + if (marketLastPrice > 0 && marketVolume > 0) + { + + // Set last values in case any error occurs + lastMarket = marketName; + lastTicker = currencyTicker; + + Market market = new Market(); + market.Position = markets.Count + 1; + market.Name = marketName; + market.Symbol = currencyTicker["symbol"].ToString(); + market.Price = SystemHelper.TextToDouble(currencyTicker["lastPrice"].ToString(), 0, "en-US"); + market.Volume24h = SystemHelper.TextToDouble(currencyTicker["quoteVolume"].ToString(), 0, "en-US"); + market.MainCurrencyPriceUSD = mainCurrencyPrice; + + markets.Add(market.Name, market); + + result.Add(market.Name); + } + else + { + //Let the user know that the problem market was ignored. + log.DoLogInfo("BinanceUS - Ignoring bad market data for " + marketName); + } + } + } + + BinanceUS.CheckFirstSeenDates(markets, ref marketInfos, systemConfiguration, log); + + BaseAnalyzer.SaveMarketInfosToFile(marketInfos, systemConfiguration, log); + + BinanceUS.CheckForMarketDataRecreation(mainMarket, markets, systemConfiguration, log); + + DateTime fileDateTime = DateTime.UtcNow; + + FileHelper.WriteTextToFile(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar, "MarketData_" + fileDateTime.ToString("yyyy-MM-dd_HH.mm") + ".json", JsonConvert.SerializeObject(markets), fileDateTime, fileDateTime); + + log.DoLogInfo("BinanceUS - Market data saved for " + markets.Count.ToString() + " markets with " + mainMarket + "."); + + FileHelper.CleanupFiles(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar, systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours); + log.DoLogInfo("BinanceUS - Market data cleaned."); + } + else + { + log.DoLogError("BinanceUS - Failed to get main market price for " + mainMarket + "."); + result = null; + } + } + } + catch (WebException ex) + { + if (ex.Response != null) + { + using (HttpWebResponse errorResponse = (HttpWebResponse)ex.Response) + { + using (StreamReader reader = new StreamReader(errorResponse.GetResponseStream())) + { + Dictionary errorData = JsonConvert.DeserializeObject>(reader.ReadToEnd()); + if (errorData != null) + { + string errorMessage = "Unable to get data from BinanceUS with URL '" + errorResponse.ResponseUri + "'!"; + if (errorData.ContainsKey("code")) + { + errorMessage += " - Code: " + errorData["code"]; + } + + if (errorData.ContainsKey("msg")) + { + errorMessage += " - Message: " + errorData["msg"]; + } + + log.DoLogError(errorMessage); + } + } + } + } + result = null; + } + catch (Exception ex) + { + log.DoLogCritical("Exception while getting data for '" + lastMarket + "': " + ex.Message, ex); + result = null; + } + + return result; + } + + public static void CheckFirstSeenDates(Dictionary markets, ref Dictionary marketInfos, PTMagicConfiguration systemConfiguration, LogHelper log) + { + log.DoLogInfo("BinanceUS - Checking first seen dates for " + markets.Count + " markets. This may take a while..."); + + int marketsChecked = 0; + + foreach (string key in markets.Keys) + { + // Save market info + MarketInfo marketInfo = null; + if (marketInfos.ContainsKey(key)) + { + marketInfo = marketInfos[key]; + } + + if (marketInfo == null) + { + marketInfo = new MarketInfo(); + marketInfo.Name = key; + marketInfos.Add(key, marketInfo); + marketInfo.FirstSeen = BinanceUS.GetFirstSeenDate(key, systemConfiguration, log); + } + else + { + if (marketInfo.FirstSeen == Constants.confMinDate) + { + marketInfo.FirstSeen = BinanceUS.GetFirstSeenDate(key, systemConfiguration, log); + } + } + marketInfo.LastSeen = DateTime.UtcNow; + + marketsChecked++; + + if ((marketsChecked % 20) == 0) + { + log.DoLogInfo("BinanceUS - Yes, I am still checking first seen dates... " + marketsChecked + "/" + markets.Count + " markets done..."); + } + } + } + + public static DateTime GetFirstSeenDate(string marketName, PTMagicConfiguration systemConfiguration, LogHelper log) + { + DateTime result = Constants.confMinDate; + + string baseUrl = "https://api.binance.us/api/v1/klines?interval=1d&symbol=" + marketName + "&limit=100"; + + log.DoLogDebug("BinanceUS - Getting first seen date for '" + marketName + "'..."); + + Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log); + if (jsonArray.Count > 0) + { + result = Constants.Epoch.AddMilliseconds((Int64)jsonArray[0][0]); + log.DoLogDebug("BinanceUS - First seen date for '" + marketName + "' set to " + result.ToString()); + } + + return result; + } + + public static List GetMarketTicks(string marketName, int ticksNeeded, PTMagicConfiguration systemConfiguration, LogHelper log) + { + List result = new List(); + + try + { + Int64 endTime = (Int64)Math.Ceiling(DateTime.UtcNow.Subtract(Constants.Epoch).TotalMilliseconds); + int ticksLimit = 500; + string baseUrl = ""; + int ticksFetched = 0; + + if (ticksNeeded < ticksLimit) + { + ticksLimit = ticksNeeded; + } + + bool go = true; + while (ticksFetched < ticksNeeded && go) + { + baseUrl = "https://api.binance.us/api/v1/klines?interval=1m&symbol=" + marketName + "&endTime=" + endTime.ToString() + "&limit=" + ticksLimit.ToString(); + + log.DoLogDebug("BinanceUS - Getting " + ticksLimit.ToString() + " ticks for '" + marketName + "'..."); + Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log); + if (jsonArray.Count > 0) + { + log.DoLogDebug("BinanceUS - " + jsonArray.Count.ToString() + " ticks received."); + + foreach (Newtonsoft.Json.Linq.JArray marketTick in jsonArray) + { + + MarketTick tick = new MarketTick(); + tick.Price = (double)marketTick[4]; + tick.Volume24h = (double)marketTick[7]; + tick.Time = Constants.Epoch.AddMilliseconds((Int64)marketTick[0]); + + result.Add(tick); + } + + ticksFetched = ticksFetched + jsonArray.Count; + endTime = endTime - ticksLimit * 60 * 1000; + if (ticksNeeded - ticksFetched < ticksLimit) + { + ticksLimit = ticksNeeded - ticksFetched; + } + } + else + { + log.DoLogDebug("BinanceUS - No ticks received."); + go = false; + } + } + } + catch (WebException ex) + { + if (ex.Response != null) + { + using (HttpWebResponse errorResponse = (HttpWebResponse)ex.Response) + { + using (StreamReader reader = new StreamReader(errorResponse.GetResponseStream())) + { + Dictionary errorData = JsonConvert.DeserializeObject>(reader.ReadToEnd()); + if (errorData != null) + { + string errorMessage = "Unable to get data from BinanceUS with URL '" + errorResponse.ResponseUri + "'!"; + if (errorData.ContainsKey("code")) + { + errorMessage += " - Code: " + errorData["code"]; + } + + if (errorData.ContainsKey("msg")) + { + errorMessage += " - Message: " + errorData["msg"]; + } + + log.DoLogError(errorMessage); + } + } + } + } + result = null; + } + catch (Exception ex) + { + log.DoLogCritical(ex.Message, ex); + } + + return result; + } + + public static void CheckForMarketDataRecreation(string mainMarket, Dictionary markets, PTMagicConfiguration systemConfiguration, LogHelper log) + { + string binanceUSDataDirectoryPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar; + + if (!Directory.Exists(binanceUSDataDirectoryPath)) + { + Directory.CreateDirectory(binanceUSDataDirectoryPath); + } + + DirectoryInfo dataDirectory = new DirectoryInfo(binanceUSDataDirectoryPath); + + // Check for existing market files + DateTime latestMarketDataFileDateTime = Constants.confMinDate; + List marketFiles = dataDirectory.EnumerateFiles("MarketData*").ToList(); + FileInfo latestMarketDataFile = null; + if (marketFiles.Count > 0) + { + latestMarketDataFile = marketFiles.OrderByDescending(mdf => mdf.LastWriteTimeUtc).First(); + latestMarketDataFileDateTime = latestMarketDataFile.LastWriteTimeUtc; + } + + if (latestMarketDataFileDateTime < DateTime.UtcNow.AddMinutes(-20)) + { + int lastMarketDataAgeInSeconds = (int)Math.Ceiling(DateTime.UtcNow.Subtract(latestMarketDataFileDateTime).TotalSeconds); + + // Go back in time and create market data + DateTime startDateTime = DateTime.UtcNow; + DateTime endDateTime = DateTime.UtcNow.AddHours(-systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours); + if (latestMarketDataFileDateTime != Constants.confMinDate && latestMarketDataFileDateTime > endDateTime) + { + // Existing market files too old => Recreate market data for configured timeframe + log.DoLogInfo("BinanceUS - Recreating market data for " + markets.Count + " markets over " + SystemHelper.GetProperDurationTime(lastMarketDataAgeInSeconds) + ". This may take a while..."); + endDateTime = latestMarketDataFileDateTime; + } + else + { + // No existing market files found => Recreate market data for configured timeframe + log.DoLogInfo("BinanceUS - Recreating market data for " + markets.Count + " markets over " + systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours + " hours. This may take a while..."); + } + + int totalTicks = (int)Math.Ceiling(startDateTime.Subtract(endDateTime).TotalMinutes); + + // Get Ticks for main market + List mainMarketTicks = new List(); + if (!mainMarket.Equals("USDT", StringComparison.InvariantCultureIgnoreCase)) + { + mainMarketTicks = BinanceUS.GetMarketTicks(mainMarket + "USDT", totalTicks, systemConfiguration, log); + } + + // Get Ticks for all markets + log.DoLogDebug("BinanceUS - Getting ticks for '" + markets.Count + "' markets"); + ConcurrentDictionary> marketTicks = new ConcurrentDictionary>(); + + int ParallelThrottle = 4; + if (systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours > 200) + { + ParallelThrottle = 2; + log.DoLogInfo("----------------------------------------------------------------------------"); + log.DoLogInfo("StoreDataMaxHours is greater than 200. Historical data requests will be"); + log.DoLogInfo("throttled to avoid exceeding exchange data request limits. This initial "); + log.DoLogInfo("run could take more than 30 minutes. Please go outside for a walk..."); + log.DoLogInfo("----------------------------------------------------------------------------"); + } + + Parallel.ForEach(markets.Keys, + new ParallelOptions { MaxDegreeOfParallelism = ParallelThrottle}, + (key) => + { + if (!marketTicks.TryAdd(key, GetMarketTicks(key, totalTicks, systemConfiguration, log))) + { + // Failed to add ticks to dictionary + throw new Exception("Failed to add ticks for " + key + " to the memory dictionary, results may be incorrectly calculated!"); + } + + if ((marketTicks.Count % 10) == 0) + { + log.DoLogInfo("BinanceUS - No worries, I am still alive... " + marketTicks.Count + "/" + markets.Count + " markets done..."); + } + }); + + log.DoLogInfo("BinanceUS - Ticks completed."); + + log.DoLogInfo("BinanceUS - Creating initial market data ticks. This may take another while..."); + + // Go back in time and create market data + int completedTicks = 0; + if (marketTicks.Count > 0) + { + for (DateTime tickTime = startDateTime; tickTime >= endDateTime; tickTime = tickTime.AddMinutes(-1)) + { + completedTicks++; + + double mainCurrencyPrice = 1; + if (mainMarketTicks.Count > 0) + { + List mainCurrencyTickRange = mainMarketTicks.FindAll(t => t.Time <= tickTime); + if (mainCurrencyTickRange.Count > 0) + { + MarketTick mainCurrencyTick = mainCurrencyTickRange.OrderByDescending(t => t.Time).First(); + mainCurrencyPrice = mainCurrencyTick.Price; + } + } + + Dictionary tickMarkets = new Dictionary(); + foreach (string key in markets.Keys) + { + List tickRange = marketTicks[key] != null ? marketTicks[key].FindAll(t => t.Time <= tickTime) : new List(); + + if (tickRange.Count > 0) + { + MarketTick marketTick = tickRange.OrderByDescending(t => t.Time).First(); + + Market market = new Market(); + market.Position = markets.Count + 1; + market.Name = key; + market.Symbol = key; + market.Price = marketTick.Price; + //market.Volume24h = marketTick.Volume24h; + market.MainCurrencyPriceUSD = mainCurrencyPrice; + + tickMarkets.Add(market.Name, market); + } + } + + DateTime fileDateTime = new DateTime(tickTime.ToLocalTime().Year, tickTime.ToLocalTime().Month, tickTime.ToLocalTime().Day, tickTime.ToLocalTime().Hour, tickTime.ToLocalTime().Minute, 0).ToUniversalTime(); + + FileHelper.WriteTextToFile(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar, "MarketData_" + fileDateTime.ToString("yyyy-MM-dd_HH.mm") + ".json", JsonConvert.SerializeObject(tickMarkets), fileDateTime, fileDateTime); + + log.DoLogDebug("BinanceUS - Market data saved for tick " + fileDateTime.ToString() + " - MainCurrencyPrice=" + mainCurrencyPrice.ToString("#,#0.00") + " USD."); + + if ((completedTicks % 100) == 0) + { + log.DoLogInfo("BinanceUS - Our magicbots are still at work, hang on... " + completedTicks + "/" + totalTicks + " ticks done..."); + } + } + } + + log.DoLogInfo("BinanceUS - Initial market data created. Ready to go!"); + } + + } + } +} \ No newline at end of file diff --git a/Monitor/Pages/MarketAnalyzer.cshtml b/Monitor/Pages/MarketAnalyzer.cshtml index 95deaf9..a8d67c2 100644 --- a/Monitor/Pages/MarketAnalyzer.cshtml +++ b/Monitor/Pages/MarketAnalyzer.cshtml @@ -57,7 +57,29 @@ }
- } + } + else + if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase)) { + string TvSymbol = "BINANCE:" + @Core.Helper.SystemHelper.GetMainCurrencySymbol(Model.Summary.MainMarket) + "USD"; +
+
+ +
+ } else if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase)) { string TvSymbol = "BITTREX:" + @Core.Helper.SystemHelper.GetMainCurrencySymbol(Model.Summary.MainMarket) + "USD"; @@ -110,7 +132,7 @@
-

Market Trend Averages

+

Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange

diff --git a/Monitor/Pages/SettingsGeneral.cshtml b/Monitor/Pages/SettingsGeneral.cshtml index 58df383..f5838cc 100644 --- a/Monitor/Pages/SettingsGeneral.cshtml +++ b/Monitor/Pages/SettingsGeneral.cshtml @@ -61,6 +61,13 @@ +
+ +
+ @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange +
+
+
diff --git a/Monitor/Pages/_get/DashboardBottom.cshtml b/Monitor/Pages/_get/DashboardBottom.cshtml index 16bad91..137f0e9 100644 --- a/Monitor/Pages/_get/DashboardBottom.cshtml +++ b/Monitor/Pages/_get/DashboardBottom.cshtml @@ -53,7 +53,7 @@
-

Market Trendsmore

+

Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchangemore

diff --git a/Monitor/Pages/_get/DashboardTop.cshtml b/Monitor/Pages/_get/DashboardTop.cshtml index eca954f..8090158 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml +++ b/Monitor/Pages/_get/DashboardTop.cshtml @@ -150,14 +150,19 @@ // Aggregate totals Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost; + double ExchangeFee = 0; + if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance")) { - double ExchangeFee = 0.002; + ExchangeFee = 0.002; + } + if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS")) { + ExchangeFee = 0.002; } if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex")) { - double ExchangeFee = 0.0025; + ExchangeFee = 0.0025; } if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex")) { - double ExchangeFee = 0.0025; + ExchangeFee = 0.0025; } double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * ExchangeFee; From 6a9341615057c7dbf322f3b0cc70969d9b78cb42 Mon Sep 17 00:00:00 2001 From: HojouFotytu <36724681+HojouFotytu@users.noreply.github.com> Date: Thu, 17 Oct 2019 11:06:16 +0900 Subject: [PATCH 4/4] Trading fee update --- Monitor/Pages/_get/DashboardTop.cshtml | 28 +++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Monitor/Pages/_get/DashboardTop.cshtml b/Monitor/Pages/_get/DashboardTop.cshtml index 8090158..ade252f 100644 --- a/Monitor/Pages/_get/DashboardTop.cshtml +++ b/Monitor/Pages/_get/DashboardTop.cshtml @@ -149,20 +149,24 @@ // Aggregate totals Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost; - double ExchangeFee = 0; - if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance")) { - ExchangeFee = 0.002; - } - if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS")) { - ExchangeFee = 0.002; - } - if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex")) { - ExchangeFee = 0.0025; - } - if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex")) { - ExchangeFee = 0.0025; + switch (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.ToLower()) + { + case "binance": + ExchangeFee = 0.002; + break; + case "binanceus": + ExchangeFee = 0.002; + break; + case "bittrex": + ExchangeFee = 0.0025; + break; + case "poloniex": + ExchangeFee = 0.0025; + break; + default: + break; } double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * ExchangeFee;