private async Task LoadWtmCoins(CancellationToken token = default(CancellationToken)) { List <AlgoCoin> tempCoinList = null; switch (Workers.CoinType) { case "All": tempCoinList = await WhatToMine.GetAllWtmSelectableCoins(false, token); break; case "Active": tempCoinList = await WhatToMine.GetAllWtmSelectableCoins(true, token); break; default: tempCoinList = await WhatToMine.GetWtmCoinNames(Workers.CoinType, token); break; } if (tempCoinList == null) { WtmCoins = null; if (!token.IsCancellationRequested) { var t = Task.Run(() => MessageBox.Show("Could not download the list of coins from\nwww.whattomine.com", "Error", MessageBoxButton.OK, MessageBoxImage.Error)); } } else { WtmCoins = new ObservableCollection <AlgoCoin>(tempCoinList); } }
public static async Task <ObservableCollection <Algorithm> > GetWtmData(CancellationToken token = default(CancellationToken)) { var allCoins = await WhatToMine.GetAllCoinsJson(token); if (allCoins == null) { return(null); } var sortedByAlgo = new ObservableCollection <Algorithm>(); foreach (var coin in allCoins) { var algoName = (string)((Dictionary <string, object>)coin.Value)["algorithm"]; var newCoin = new CoinId { Id = (int)((Dictionary <string, object>)coin.Value)["id"], Name = coin.Key, Symbol = (string)((Dictionary <string, object>)coin.Value)["tag"], Status = (string)((Dictionary <string, object>)coin.Value)["status"], }; newCoin.Show = string.Equals(newCoin.Status, "Active", StringComparison.InvariantCultureIgnoreCase) ? true : false; var algo = sortedByAlgo.FirstOrDefault(x => x.Name == algoName); if (algo != null) { var algoCoin = algo.Coins.FirstOrDefault(x => x.Name == coin.Key); if (algoCoin == null) { algo.Coins.Add(newCoin); } } else { var newAlgo = new Algorithm { Name = algoName, Coins = new ObservableCollection <CoinId>() }; newAlgo.AddCoinsCollectionChanged(); newAlgo.Coins.Add(newCoin); sortedByAlgo.Add(newAlgo); } } sortedByAlgo = new ObservableCollection <Algorithm>(sortedByAlgo.OrderBy(x => x.Name)); return(sortedByAlgo); }
public async Task <HistoricalData> GetNewPriceHistoryRecord(StreamWriter logFile) { var coinList = Workers.GetCoins(Workers.WorkerList); if (!coinList.Contains("Bitcoin")) { coinList.Add("Bitcoin"); } var coinHashList = GetHashrates(coinList); var wtmRequestIntervalOld = WtmSettings.WtmRequestInterval; if (WtmSettings.SaveAllCoins) { var allCoins = await WhatToMine.GetAllWtmCoinNamesFromJson(true); var difference = allCoins.Except(coinList); foreach (var coin in difference) { coinHashList[coin] = 1000; } } // Get WTM coin data var wtmDataResult = await WhatToMine.GetWtmCoinData(coinHashList, false, logFile).ConfigureAwait(false); if (wtmDataResult.result == WhatToMine.GetWtmCoinDataResult.CoinNotFound) { return(null); } var wtmDataDict = wtmDataResult.data; if (wtmDataDict != null) { return(new HistoricalData(DateTime.Now, wtmDataDict)); } else { return(null); } }
public async Task <SwitchResult> SwitchStandalone() { var streamServerAddress = BuildServerAddress(WtmSettings.ServerName, Constants.StreamServer); using (var logFile = new StreamWriter(Constants.SwitchLog, true)) { if (new FileInfo(Constants.SwitchLog).Length > 0) { logFile.WriteLine(string.Empty); } logFile.WriteLine(DateTime.Now); // Respect the DelayNextSwitchTime setting if (WtmSettings.DelayNextSwitchTime != 0) { var lastTime = new DateTime(); var lastTimeObj = GetRegistryKeyValue(Constants.SwitchRegistryKey, "LastSuccess"); string lastTimeStr = lastTimeObj as string; if (lastTimeStr != null && lastTimeStr != string.Empty) { lastTime = Convert.ToDateTime(lastTimeStr, DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); var now = DateTime.UtcNow; var lastTimePlusDelay = lastTime.AddHours(WtmSettings.DelayNextSwitchTime); if (now < lastTimePlusDelay) { logFile.WriteLine($"Because of the Delay option checked Auto Switch can proceed only after {lastTimePlusDelay.ToLocalTime()}."); return(SwitchResult.DelayIsNotOver); } } } // Update Workers from server if (WtmSettings.ApplicationMode == "Client" && WtmSettings.UpdateWorkersFromServer) { await UpdateWorkersFromServer(logFile); } //Find localhost name in Workers list (used in Standalone and Client modes ) var thisPcName = Environment.MachineName; Worker thisWorker = GetWorkerByPCName(thisPcName); if (thisWorker == null && WtmSettings.ApplicationMode != "Server") { string msg = $"{thisPcName} was not found in any worker."; logFile.WriteLine(msg); return(SwitchResult.ThisPcIsNotListed); } // Get coin names from worker description var coinList = new List <string>(); var allCoinList = new List <string>(); var workersList = new List <Worker>(); string noCoinChecked = string.Empty; if (thisWorker != null) { noCoinChecked = $"No coin is checked as switchable in {thisWorker.Name}."; } else { noCoinChecked = "No coin is checked as switchable."; } if (WtmSettings.ApplicationMode != "Server") // Standalone or Client mode - just the worker that contains localhost name { workersList = new List <Worker> { thisWorker }; } else // Server mode - all workers, all coins { foreach (var w in Workers.WorkerList) { workersList.Add(w.Clone()); } allCoinList = Workers.GetCoins(workersList, false, false); if (allCoinList == null || allCoinList.Count == 0) { logFile.WriteLine(noCoinChecked); return(SwitchResult.NothingToDo); } if (!allCoinList.Contains("Bitcoin")) { allCoinList.Add("Bitcoin"); } } coinList = Workers.GetCoins(workersList, false, true); // Only coins with Switch checked if (coinList == null || coinList.Count == 0) { logFile.WriteLine(noCoinChecked); return(SwitchResult.NothingToDo); } if (!coinList.Contains("Bitcoin")) { coinList.Add("Bitcoin"); } // Get WTM coins JSON data Dictionary <string, WtmData> wtmDataDict = new Dictionary <string, WtmData>(); // Attempt to download data from local server HistoricalData localDataCopy = null; if (WtmSettings.ApplicationMode == "Client") { var channel = Service.NewStreamChannel(streamServerAddress, TimeSpan.FromSeconds(60)); try { var response = await channel.GetWtmLocalDataAsync(); if (response != null) { var memoryStream = new MemoryStream(); await response.Stream.CopyToAsync(memoryStream); localDataCopy = NetHelper.DeserializeFromStream <HistoricalData>(memoryStream); } if (localDataCopy == null) { throw new NullReferenceException("Local data from server are null."); } } catch (Exception ex) { logFile.WriteLine($"Failed to download proxy data from local server {WtmSettings.ServerName}. " + ex.Message); if (!WtmSettings.QueryWtmOnLocalServerFail) { return(SwitchResult.NoWtmData); } } finally { NetHelper.CloseChannel(channel); } // Check if the received data are up to date if (localDataCopy != null) { bool dataTimestampGood = EvaluateWtmDataTimeRange(localDataCopy.Date); if (!dataTimestampGood && !WtmSettings.QueryWtmOnLocalServerFail) { logFile.WriteLine("The server cache data is expired." + " Make sure that AutoSwitch on the client launches later than on the server." + " For example, if AutoSwitch runs on a daily basis schedule AutoSwitch on the server to run at 9:00 and on the client machines at anyting between 10:00-23:59." + " This way the cache data obtained in the morning is valid for the rest of the day."); return(SwitchResult.Terminate); } if (dataTimestampGood) { // Filter out coins downloded from server that are not checked for AutoSwitch locally wtmDataDict = localDataCopy.PriceData.Where(x => coinList.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value); } } } // Download data from WhatToMine (Standalone or Server) if (wtmDataDict.Count == 0) { StatusBarText = "Downloading coin definitions from whattomine.com..."; (Dictionary <string, WtmData> data, WhatToMine.GetWtmCoinDataResult result)wtmDataResult = (null, WhatToMine.GetWtmCoinDataResult.OK); if (WtmSettings.ApplicationMode == "Server") { var allCoinHashList = GetHashrates(allCoinList); wtmDataResult = await WhatToMine.GetWtmCoinData(allCoinHashList, false, logFile).ConfigureAwait(false); } else { var coinHashList = GetHashrates(coinList); wtmDataResult = await WhatToMine.GetWtmCoinData(coinHashList, false, logFile).ConfigureAwait(false); } if (wtmDataResult.result == WhatToMine.GetWtmCoinDataResult.CoinNotFound) { return(SwitchResult.CoinNotFound); } wtmDataDict = wtmDataResult.data; if (wtmDataDict == null) { return(SwitchResult.CoinNotFound); } } // Update WTM coin data with historical averages from local database if opted to var historicalDataList = new List <HistoricalData>(); bool historicalDataUpToDate = false; if (WtmSettings.UseHistoricalAverage) { if (WtmSettings.ApplicationMode == "Client") { //Needs longer timeout for the server might be downloading all coins from whattomine.com var channel = Service.NewStreamChannel(streamServerAddress, TimeSpan.FromSeconds(180)); try { var response = await channel.GetPriceHistoryAsync(new StreamDownloadRequest { Period = WtmSettings.HistoricalAveragePeriod }).ConfigureAwait(false); if (response != null) { var memoryStream = new MemoryStream(); await response.Stream.CopyToAsync(memoryStream); historicalDataList = NetHelper.DeserializeFromStream <List <HistoricalData> >(memoryStream); historicalDataUpToDate = true; } } catch (Exception ex) { logFile.WriteLine($"Failed to obtain historical prices from local server {WtmSettings.ServerName}. " + ex.Message); return(SwitchResult.Error); } finally { NetHelper.CloseChannel(channel); } } else { var result = await UpdatePriceHistory(); if (result == UpdatePriceHistoryResult.Success || result == UpdatePriceHistoryResult.AlreadyUpToDate) { historicalDataList = ReadHistoricalData(WtmSettings.HistoricalAveragePeriod); historicalDataUpToDate = true; } } // Calculate historical prices for wtmDataList if (historicalDataUpToDate) { GetHistoricalAverages(wtmDataDict, historicalDataList); } } // Update WtmLocalData if in server mode if (WtmSettings.ApplicationMode == "Server") { if (wtmDataDict != null && wtmDataDict.Count != 0) { using (var db = new LiteDatabase(Constants.DataBase)) { var collection = db.GetCollection <HistoricalData>(Constants.LightDB_WtmCacheCollection); collection.Delete(LiteDB.Query.All()); collection.Insert(new HistoricalData(DateTime.Now, wtmDataDict)); } } } // Abandon if in server mode and DontSwitchServer is checked if (WtmSettings.ApplicationMode == "Server" && WtmSettings.DontSwitchServer) { return(SwitchResult.NoNeedToSwitch); } if (WtmSettings.ApplicationMode == "Server" && !WtmSettings.DontSwitchServer && thisWorker == null) { logFile.WriteLine("The server cannot switch because it is not listed in any worker table."); return(SwitchResult.ThisPcIsNotListed); } // Calculate profit table for this PC and analize it var profitTables = WhatToMine.CreateProfitTables(wtmDataDict, workersList, (decimal)Workers.PowerCost, WtmSettings, true); var profitTable = profitTables.First(); var currentCoinShortcut = Shortcut.GetCurrentCoin(); // Get current coin from Startup folder .lnk ProfitTableRow maxCoinRow = null; decimal maxProfit = 0; decimal currentProfit = 0; bool nothingChecked = false; WhatToMine.GetProfit(profitTable, currentCoinShortcut, out maxCoinRow, out maxProfit, out currentProfit, out nothingChecked); if (nothingChecked) { string msg = "Nothing to do. Make sure there are actual switchable coins defined in worker."; logFile.WriteLine(msg); return(SwitchResult.NothingToDo); } if (maxProfit == 0) { string msg = $"There is no coin with profit above 0 for {thisPcName}."; logFile.WriteLine(msg); return(SwitchResult.NothingToDo); } //Check profitability and price margin bool currentCoinMatch = currentCoinShortcut?.GetName() == maxCoinRow.Name; bool currentCoinPathMatch = currentCoinShortcut?.Path == maxCoinRow.Path; bool currentPforitIsHigherOrEqual = maxProfit <= currentProfit; bool currentProfitIsWithinMargin = false; if (WtmSettings.PriceMargin > 0) { currentProfitIsWithinMargin = maxProfit <= (currentProfit + (currentProfit * WtmSettings.PriceMargin / 100)); } if (currentPforitIsHigherOrEqual) { string msg; msg = $"No need to switch. {thisPcName} is already set to mine the most profitable coin {currentCoinShortcut?.GetNameAndSymbol()}."; logFile.WriteLine(msg); return(SwitchResult.NoNeedToSwitch); } if (currentProfitIsWithinMargin) { string msg; if (currentCoinMatch && !currentCoinPathMatch) { msg = $"No need to switch. {thisPcName} is set to mine {currentCoinShortcut?.GetNameAndSymbol()} started by \"{currentCoinShortcut?.Path}\". It is less profitable than {maxCoinRow.NameAndSymbol} started by \"{maxCoinRow.Path}\" but the difference is within price margin."; } else { msg = $"No need to switch. {thisPcName} is set to mine {currentCoinShortcut?.GetNameAndSymbol()}. It is less profitable than {maxCoinRow.NameAndSymbol} but the difference is within price margin."; } logFile.WriteLine(msg); return(SwitchResult.NoNeedToSwitch); } // Check if executable path exists if (!File.Exists(maxCoinRow.Path)) { logFile.WriteLine($"{maxCoinRow.Path} - file does not exist on {thisPcName}."); return(SwitchResult.CoinNotFound); } bool startOk = false; // Start miner process flag try { Shortcut.CreateCoinShortcut(maxCoinRow.Name, maxCoinRow.Symbol, maxCoinRow.Algorithm, maxCoinRow.Path, maxCoinRow.Arguments); if (WtmSettings.RestartComputer) { RestartComputerPending = true; } if (WtmSettings.RestartMiner) { // Kill processes from KillList var killResponse = KillProcesses(WtmSettings.KillList); if (!killResponse.success && killResponse.failList != null) { string errorMessage = $"Startup shortcut to mine {maxCoinRow.NameAndSymbol} has been created but some processes could not be killed:"; logFile.WriteLine(errorMessage); foreach (var entry in killResponse.failList) { if (entry != string.Empty) { logFile.WriteLine(entry); } } logFile.WriteLine($"{Environment.MachineName} will restart."); RestartComputerPending = true; SetRegistryKeyValue(Constants.SwitchRegistryKey, "LastSuccess", DateTime.UtcNow.ToString("o")); return(SwitchResult.SwitchedSuccessfully); } if (!System.IO.File.Exists(maxCoinRow.Path)) { logFile.WriteLine($"ERROR: File not found. {maxCoinRow.Path}"); return(SwitchResult.Error); } // Start miner process var startInfo = new ProcessStartInfo(maxCoinRow.Path, maxCoinRow.Arguments); Process process = new Process(); process.StartInfo = startInfo; startOk = process.Start(); if (!startOk) { throw new Exception($"\"{Path.GetFileName(maxCoinRow.Path)}\" failed to start."); } } SetRegistryKeyValue(Constants.SwitchRegistryKey, "LastSuccess", DateTime.UtcNow.ToString("o")); logFile.WriteLine($"Switched to {maxCoinRow.NameAndSymbol} successfully."); return(SwitchResult.SwitchedSuccessfully); } catch (Exception ex) { logFile.WriteLine($"Failed to switch to {maxCoinRow.NameAndSymbol}: {ex.Message}"); if (WtmSettings.RestartMiner && !startOk) { RestartComputerPending = true; logFile.WriteLine($"{Environment.MachineName} will restart."); } return(SwitchResult.Error); } } }
private async void CalculateProfitCommand(object parameter) { CalculateProfit.SetCanExecute(false); LoadHistoricalCharts.SetCanExecute(false); SwitchManually.SetCanExecute(false); ProfitTablesEnabled = true; var coinList = Workers.GetCoins(Workers.WorkerList, true); if (!coinList.Contains("Bitcoin")) { coinList.Add("Bitcoin"); } //Update Yahoo rates if necessary if (WtmSettings.UseYahooRates && WtmSettings.DisplayCurrency != "USD" && WtmSettings.DisplayCurrency != "BTC" && WtmSettingsObject.DisplayCurrencyListDate.Date != DateTime.Today) { await WtmSettings.GetYahooRates(); if (WtmSettings.DisplayCurrencyList.Count == 2) { BypassUndo(() => WtmSettings.UseYahooRates = false); MessageBox.Show($"{Constants.AppName} could not download the list of currencies from Yahoo. Values will be displayed in USD.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); } } // Calculate mean hashrate var coinHashList = GetHashrates(coinList); // Get WTM coin data Dictionary <string, WtmData> wtmDataDict = null; (Dictionary <string, WtmData> data, WhatToMine.GetWtmCoinDataResult)wtmDataResult = (null, WhatToMine.GetWtmCoinDataResult.Fail); try { wtmDataResult = await WhatToMine.GetWtmCoinData(coinHashList, true); } catch (Exception ex) { } wtmDataDict = wtmDataResult.data; if (wtmDataDict == null) { CalculateProfitCommandQuit(); return; } var btc = wtmDataDict["Bitcoin"]; string keyName; if (WtmSettings.Average24) { keyName = "exchange_rate24"; } else { keyName = "exchange_rate"; } string btcValue; btc.Json.TryGetValue(keyName, out btcValue); if (btcValue != null) { WtmSettings.DisplayCurrencyList["BTC"] = Helpers.StringToDecimal(btcValue); } else { MessageBox.Show("Failed to read BTC price from whattomine.com", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } // Form profit tables from wtmDataList ProfitTables.Tables.Clear(); var workersChecked = Workers.WorkerList.Where(w => w.Query).ToList(); var profitTables = WhatToMine.CreateProfitTables(wtmDataDict, workersChecked, (decimal)Workers.PowerCost, WtmSettings); foreach (var table in profitTables) { ProfitTables.Tables.Add(table); } CalculateProfitCommandQuit(); ScanLan.RaiseCanExecuteChanged(); ScanLanCommand(null); }
public static async Task <(Dictionary <string, WtmData> data, GetWtmCoinDataResult result)> GetWtmCoinData(IDictionary <string, double> coinHashList, bool interactive, StreamWriter logFile = null) { string statusBarText = "Downloading coin definitions from whattomine.com"; ViewModel.Instance.StatusBarText = statusBarText + "..."; int i = 0; int cnt = coinHashList.Count; var wtmRequestIntervalOld = ViewModel.Instance.WtmSettings.WtmRequestInterval; if (cnt > ViewModel.Instance.WtmSettings.DynamicRequestTrigger) { ViewModel.Instance.BypassUndo(() => { if (ViewModel.Instance.WtmSettings.WtmRequestInterval < ViewModel.Instance.WtmSettings.DynamicRequestInterval) { ViewModel.Instance.WtmSettings.WtmRequestInterval = ViewModel.Instance.WtmSettings.DynamicRequestInterval; } }); } bool errorFlag = false; bool continueFlag = false; bool exitEarly = false; CancellationTokenSource cancelSource = new CancellationTokenSource(); CancellationToken token = cancelSource.Token; ProgressManager pm = null; if (interactive) { pm = new ProgressManager("Accessing whattomine.com...", cancelSource); pm.SetIndeterminate(true); pm.SetProgressMaxValue(cnt); } await RespectTimeLimit(); var wtmLinks = await WhatToMine.GetWtmLinksFromJson(token).ConfigureAwait(false); if (token.IsCancellationRequested) { pm?.Close(); return(null, GetWtmCoinDataResult.Fail); } if (wtmLinks == null) { string errorMessage = "Failed to get the list of available coins from whattomine.com."; if (interactive) { pm?.Close(); MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } else { if (logFile != null) { logFile.WriteLine(errorMessage); } } return(null, GetWtmCoinDataResult.Fail); } if (interactive && pm != null) { pm.SetIndeterminate(false); pm.SetText("Downloading " + i + " of " + cnt); pm.SetProgressValue(0); } var wtmDataDict = new Dictionary <string, WtmData>(); string currentJsonStr = string.Empty; string currentCoinHtml = string.Empty; GetWtmCoinDataResult methodResult = GetWtmCoinDataResult.OK; foreach (var coin in coinHashList) { continueFlag = false; List <string> httpResults = new List <string>(); WtmLinks entry; wtmLinks.TryGetValue(coin.Key, out entry); if (entry == null) { string errorMessage = $"{coin.Key} has not been found among coins at http://whattomine.com/calculators. Execution aborted."; errorFlag = true; methodResult = GetWtmCoinDataResult.CoinNotFound; if (interactive) { Helpers.ShowErrorMessage(errorMessage); } else { if (logFile != null) { logFile.WriteLine(errorMessage); } } break; } //Check whattomine coin status if (!string.Equals(entry.Status, "Active", StringComparison.InvariantCultureIgnoreCase)) { MessageBoxResult response = MessageBoxResult.OK; string message = $"The status of {coin.Key} is reported as \"{entry.Status}\" by whattomine.com."; if (interactive) { response = MessageBox.Show(message, "Coin is not active", MessageBoxButton.OKCancel, MessageBoxImage.Warning); } else { logFile.WriteLine(message); } if (interactive && response == MessageBoxResult.Cancel) { errorFlag = true; break; } continue; } await RespectTimeLimit(); try { var response = await WtmHttpClient.GetAsync(entry.JsonLink + "?hr=" + coin.Value.ToString(CultureInfo.InvariantCulture), token).ConfigureAwait(false); var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); if (result != null && result.Contains("errors")) { var wtmErrorDict = JsonConverter.ConvertFromJson <Dictionary <string, object> >(result); if (wtmErrorDict != null) { object errorObj = null; wtmErrorDict.TryGetValue("errors", out errorObj); var errorList = errorObj as ArrayList; if (errorList != null) { string errorMessage = string.Join(". ", errorList.ToArray()); if (errorMessage != null) { throw new Exception(errorMessage); } } } } response.EnsureSuccessStatusCode(); httpResults.Add(result); } catch (Exception e) { if (interactive && e.Message == "A task was canceled.") { errorFlag = true; methodResult = GetWtmCoinDataResult.Fail; } else { string errorMessage = $"Failed to download {coin.Key} definition from whattomine.com."; //continueFlag = true; errorFlag = true; methodResult = GetWtmCoinDataResult.Fail; if (interactive) { Helpers.ShowErrorMessage(errorMessage + "\n\n" + e.Message); } else { if (logFile != null) { logFile.WriteLine(errorMessage); } } } } //if (continueFlag) // continue; if (errorFlag || httpResults == null) { break; } // Interpret JSON currentJsonStr = httpResults[0]; Dictionary <string, string> json = new Dictionary <string, string>(); json = JsonConverter.ConvertFromJson <Dictionary <string, string> >(currentJsonStr); if (json == null) { string errorMessage = $"Failed to interpret {coin.Key} definition from whattomine.com."; errorFlag = true; methodResult = GetWtmCoinDataResult.Fail; if (interactive) { Helpers.ShowErrorMessage(errorMessage); } else { if (logFile != null) { logFile.WriteLine(errorMessage); } } break; } else { var defaultHashrate = coin.Value; wtmDataDict.Add(coin.Key, new WtmData { DefaultHashrate = defaultHashrate, Json = json }); } if (pm != null && !pm.IsAlive) { exitEarly = true; break; } i++; if (interactive && pm != null) { pm.SetText("Downloaded " + i + " of " + cnt); pm.SetProgressValue(i); } else { ViewModel.Instance.StatusBarText = statusBarText + ": " + i + " of " + cnt; } } ViewModel.Instance.BypassUndo(() => ViewModel.Instance.WtmSettings.WtmRequestInterval = wtmRequestIntervalOld); ViewModel.Instance.UpdateNextJobStatus(); if (!exitEarly && interactive) { pm?.Close(); } if (errorFlag || exitEarly) { return(null, methodResult); } if (!interactive && (logFile != null)) { var noun = wtmDataDict.Count == 1 ? "coin" : "coins"; logFile.WriteLine($"The list of {wtmDataDict.Count} whattomine.com {noun} has been downloaded."); } return(wtmDataDict, GetWtmCoinDataResult.OK); }
private void LoadHistoricalChartsCommand(object obj) { DateTime FromDate; DateTime ToDate; using (var db = new LiteDatabase(Constants.DataBase)) { Helpers.MouseCursorWait(); var collection = db.GetCollection <HistoricalData>(Constants.LightDB_HistoricalDataCollection); var allDays = collection.FindAll(); if (allDays.Count() == 0) { MessageBox.Show("The historical prices database is empty. Set up 'Accumulate Historical Prices', collect some stats for a while and return then.", "Nothing to show", MessageBoxButton.OK, MessageBoxImage.Warning); Helpers.MouseCursorNormal(); return; } var selectDatesWindow = new SelectDateRange(); var viewModel = new SelectDateRangeVM(allDays.First().Date, allDays.Last().Date); selectDatesWindow.DataContext = viewModel; Helpers.MouseCursorNormal(); var dialogResult = selectDatesWindow.ShowDialog(); if (dialogResult == false) { return; } FromDate = viewModel.FromDate; ToDate = viewModel.ToDate; } var workersChecked = Workers.WorkerList.Where(w => w.Query).ToList(); var historicalCharts = new Dictionary <string, HistoricalChart>(); // Create a chart for each worker foreach (var worker in workersChecked) { //var coinListFullName = Workers.GetCoins(new List<Worker> { worker }, false, false, true); var chart = new HistoricalChart { Name = worker.Name, Description = worker.Description, Computers = new ObservableCollection <string>(worker.Computers), Coins = new ObservablePairCollection <string, ChartCoin>(), PlotModel = new PlotModel(), DisplayCoinAs = Workers.DisplayCoinAs }; chart.HookUpCoinsCollectionChanged(); // Add AutoSwitch "coin" chart.Coins.Add("0, AutoSwitch", new ChartCoin { Color = OxyColors.Red.ToBrush(), IsChecked = true, Name = "AutoSwitch", Symbol = "AutoSwitch" }); var serie = new LineSeries { StrokeThickness = 2, MarkerSize = 3, Color = OxyColors.Red, MarkerType = MarkerType.Circle, CanTrackerInterpolatePoints = false, Title = "AutoSwitch", Smooth = false, Tag = 0 }; chart.PlotModel.Series.Add(serie); // Add real coins int index = 1; foreach (var coinTable in worker.CoinList) { var lockExpiry = FromDate.Date.Date.AddHours(WtmSettings.DelayNextSwitchTime); var oxyColor = ChartColors.Colors[chart.PlotModel.Series.Count % ChartColors.Colors.Count]; chart.Coins.Add($"{index}, {coinTable.FullName}", new ChartCoin { Index = index, IsChecked = true, LockedUntil = lockExpiry, Color = oxyColor.ToBrush(), Name = coinTable.FullName, Symbol = coinTable.FullSymbol }); var newSerie = new LineSeries { StrokeThickness = 2, MarkerSize = 3, Color = oxyColor, MarkerType = MarkerType.Circle, CanTrackerInterpolatePoints = false, Title = coinTable.FullName, Smooth = false, Tag = index }; chart.PlotModel.Series.Add(newSerie); index++; } CultureInfo currentCulture = CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.ToString()); chart.PlotModel.Axes.Add(new DateTimeAxis { IsPanEnabled = true, IsZoomEnabled = false, Position = AxisPosition.Bottom, StringFormat = currentCulture.DateTimeFormat.ShortDatePattern, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, TextColor = ChartColors.DarkBlue, TicklineColor = ChartColors.DarkBlue, MajorGridlineColor = ChartColors.DarkBlue, MinorGridlineThickness = 0.9, AxislineThickness = 0.9, MajorGridlineThickness = 0.9, IntervalLength = 80 }); chart.PlotModel.Axes.Add(new LinearAxis { IsZoomEnabled = false, Position = AxisPosition.Left, Title = "Daily profit", Minimum = 0, TitleColor = ChartColors.DarkBlue, TextColor = ChartColors.DarkBlue, TicklineColor = ChartColors.DarkBlue, MajorGridlineColor = ChartColors.DarkBlue, MinorTicklineColor = ChartColors.DarkBlue, MinorGridlineColor = ChartColors.DarkBlue, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, AxislineThickness = 0.9, MinorGridlineThickness = 0.9, MajorGridlineThickness = 0.9, }); chart.PlotModel.IsLegendVisible = false; chart.PlotModel.PlotAreaBorderThickness = new OxyThickness(0.9, 0.9, 0.9, 0.9); chart.PlotModel.PlotAreaBorderColor = ChartColors.DarkBlue; chart.PlotModel.Padding = new OxyThickness(0, 10, 0, -10); chart.PlotModel.DefaultColors = ChartColors.Colors; historicalCharts.Add(worker.Name, chart); } //Fill PlotModel with data using (var db = new LiteDatabase(Constants.DataBase)) { var collection = db.GetCollection <HistoricalData>(Constants.LightDB_HistoricalDataCollection); var selectedDays = collection.Find(x => x.Date >= FromDate && x.Date <= ToDate); if (selectedDays.FirstOrDefault() == null) { MessageBox.Show("The time selection is missing actual records in database.", "ERROR", MessageBoxButton.OK, MessageBoxImage.Error); return; } DateTime previousDay = selectedDays.FirstOrDefault().Date.Date; foreach (var day in selectedDays) { // Check if there's a gap and fill the missing days with blank data var difference = (day.Date.Date - previousDay.Date).Days; if (difference > 1) { for (int i = 1; i <= difference - 1; i++) { foreach (var worker in workersChecked) { var index = 1; var chart = historicalCharts[worker.Name]; // The chart that corresponds to the worker chart.AutoSwitchCoinName = null; var serie = chart.PlotModel.Series.First() as LineSeries; var point = new DataPoint(DateTimeAxis.ToDouble(previousDay.Date.AddDays(i)), 0); serie.Points.Add(point); foreach (var coinTable in worker.CoinList) { serie = chart.PlotModel.Series.FirstOrDefault(x => (int)x.Tag == index) as LineSeries; point = new DataPoint(DateTimeAxis.ToDouble(previousDay.Date.AddDays(i)), 0); serie.Points.Add(point); index++; } } } } WtmData btc = null; day.PriceData.TryGetValue("Bitcoin", out btc); foreach (var worker in workersChecked) { var chart = historicalCharts[worker.Name]; // The chart that corresponds to the worker var AutoSwitchPseudoCoin = chart.Coins["0, AutoSwitch"]; var index = 1; foreach (var coinTable in worker.CoinList) { var currentChartCoin = chart.Coins[$"{index}, {coinTable.FullName}"]; if (currentChartCoin.Accumulator == null) { currentChartCoin.Accumulator = new Accumulator(coinTable.Coins); } // Calculate profit var profitResult = WhatToMine.CalculateProfit(coinTable, day.PriceData, btc, WtmSettings, (decimal)Workers.PowerCost); decimal profit24 = profitResult.profit24; currentChartCoin.TodaysProfit = profit24; // Accumulate daily reward foreach (var coin in coinTable.Coins) { if (day.PriceData.ContainsKey(coin.Name)) { decimal ratio = (decimal)coin.Hashrate / (decimal)day.PriceData[coin.Name].DefaultHashrate; var dayReward = Helpers.StringToDecimal(day.PriceData[coin.Name].Json["estimated_rewards"]) * ratio; // Daily reward in mined coin dayReward -= dayReward * (decimal)coinTable.Fees / 100; // Deduct fees currentChartCoin.Accumulator.AddValue(coin.Name, dayReward); } else { currentChartCoin.Accumulator.AddValue(coin.Name, 0); } } currentChartCoin.PowerAccumulator += coinTable.Power / 1000 * 24; // Accumulate daily power consumption // Sell accumulated reward if lock is expired bool invalidateCoin = false; if (day.Date.Date >= currentChartCoin.LockedUntil.Date) { decimal btcRate = 0; if (WtmSettings.Average24) { btcRate = btc != null?Helpers.StringToDecimal(btc.Json["exchange_rate24"]) : 0; } else { btcRate = btc != null?Helpers.StringToDecimal(btc.Json["exchange_rate"]) : 0; } foreach (var coin in currentChartCoin.Accumulator.CoinList) { if (day.PriceData.ContainsKey(coin.Name)) { var coinRate = WtmSettings.Average24 ? Helpers.StringToDecimal(day.PriceData[coin.Name].Json["exchange_rate24"]) : Helpers.StringToDecimal(day.PriceData[coin.Name].Json["exchange_rate"]); var revenue = coin.Value * coinRate * btcRate; currentChartCoin.TotalProfit += revenue; if (chart.AutoSwitchCoinName == coinTable.FullName) { AutoSwitchPseudoCoin.TotalProfit += revenue; } } else { invalidateCoin = true; } } if (!invalidateCoin) { var powerExpense = (decimal)(currentChartCoin.PowerAccumulator * Workers.PowerCost); currentChartCoin.TotalProfit -= powerExpense; if (chart.AutoSwitchCoinName == coinTable.FullName) { AutoSwitchPseudoCoin.TotalProfit -= powerExpense; } } currentChartCoin.Accumulator.Clear(); currentChartCoin.PowerAccumulator = 0; currentChartCoin.LockedUntil = day.Date.Date.AddHours(WtmSettings.DelayNextSwitchTime); } // Add a new point for this day to the Graph var point = new DataPoint(DateTimeAxis.ToDouble(day.Date), (double)profit24); var serie = chart.PlotModel.Series.FirstOrDefault(x => (int)x.Tag == index) as LineSeries; if (serie != null) { serie.Points.Add(point); } index++; }// foreach CoinTable ChartCoin currentAutoSwitchCoin = null; if (chart.AutoSwitchCoinName != null) { currentAutoSwitchCoin = chart.Coins[chart.AutoSwitchCoinName]; } // AutoSwitch emulator if (day.Date.Date >= AutoSwitchPseudoCoin.LockedUntil.Date) { var mostProfitableCoin = chart.GetMostProfitableCoin(); decimal maxProfit = mostProfitableCoin.Value != null ? mostProfitableCoin.Value.TodaysProfit : 0; if (chart.AutoSwitchCoinName == null) { chart.AutoSwitchCoinName = mostProfitableCoin.Key != null ? mostProfitableCoin.Key : null; //AutoSwitchPseudoCoin.TotalProfit = mostProfitableCoin.Value != null ? mostProfitableCoin.Value.TotalProfit : 0; currentAutoSwitchCoin = chart.AutoSwitchCoinName != null ? chart.Coins[chart.AutoSwitchCoinName] : null; } var currentProfit = chart.AutoSwitchCoinName != null ? chart.Coins[chart.AutoSwitchCoinName].TodaysProfit : 0; if (maxProfit > (currentProfit + (currentProfit * WtmSettings.PriceMargin / 100))) // Switch coin in new profit is higher { chart.AutoSwitchCoinName = mostProfitableCoin.Key != null ? mostProfitableCoin.Key : null; AutoSwitchPseudoCoin.LockedUntil = day.Date.Date.AddHours(WtmSettings.DelayNextSwitchTime); } } var currentAutoSwitchCoinProfit = currentAutoSwitchCoin != null ? currentAutoSwitchCoin.TodaysProfit : 0; AutoSwitchPseudoCoin.TotalProfit += currentAutoSwitchCoinProfit; var autoSwitchPoint = new DataPoint(DateTimeAxis.ToDouble(day.Date), (double)currentAutoSwitchCoinProfit); var autoSwitchSerie = chart.PlotModel.Series.First() as LineSeries; autoSwitchSerie.Points.Add(autoSwitchPoint); } // foreach Worker previousDay = day.Date.Date; }// foreach days } HistoricalCharts.Clear(); foreach (var chart in historicalCharts) { HistoricalCharts.Add(chart.Value); } HistoricalChartsEnabled = true; Helpers.MouseCursorWait(); }