I'm coding my first own custom indicator to fetch the Fear & Greed Index of the Crypto market. How can I do HTTPS requests? I'm beginner in C#.
HttpClient client = new HttpClient(); can't be used, as it seems its not available.
This is my current code:
HttpClient client = new HttpClient(); can't be used, as it seems its not available.
This is my current code:
CODE:
using WealthLab.Core; using System; using System.Collections.Generic; using System.Globalization; using System.Net.Http; using System.Threading.Tasks; using WealthLab.Indicators; using Newtonsoft.Json.Linq; using System.Diagnostics; namespace WealthLab.MyIndicators { public class CustomCryptoFearGreedIndex : IndicatorBase { // Static HttpClient instance for sending HTTP requests. // This is shared across all instances of this class to avoid socket exhaustion. private static readonly HttpClient client = new HttpClient(); // Default constructor initializing overbought and oversold levels. public CustomCryptoFearGreedIndex() : base() { OverboughtLevel = 70; // Overbought threshold OversoldLevel = 30; // Oversold threshold } // Constructor for creating the indicator programmatically with source data and period. public CustomCryptoFearGreedIndex(TimeSeries source, int period) : base() { Parameters[0].Value = source; // Assign source time series Parameters[1].Value = period; // Assign lookback period OverboughtLevel = 70; OversoldLevel = 30; Populate(); // Populate the indicator values } // Static factory method for creating an instance of the indicator. public static CustomCryptoFearGreedIndex Series(TimeSeries source, int period) { return new CustomCryptoFearGreedIndex(source, period); } // Name of the indicator, displayed in WealthLab. public override string Name => "Custom Crypto Fear & Greed Index"; // Shortened name/abbreviation for the indicator. public override string Abbreviation => "CustomCryptoFearGreedIndex"; // Help description displayed in the WealthLab indicator manager. public override string HelpDescription => "Custom Crypto Fear & Greed Index based on external data source."; // Specifies that the indicator should be plotted in a separate pane. public override string PaneTag => "CustomCryptoFearGreedIndex"; // Default color of the indicator line. public override WLColor DefaultColor => WLColor.Navy; // Main method for calculating the indicator's values. public override void Populate() { // Get input time series and parameter values. TimeSeries source = Parameters[0].AsTimeSeries; int period = Parameters[1].AsInt; // Assign the DateTimes from the source data. DateTimes = source.DateTimes; // Exit if source data is null or empty, or if the period is invalid. if (source == null || source.Count == 0 || period <= 0) return; // Initialize the Values list to hold calculated indicator values. if (Values == null || Values.Count != source.Count) Values = new List<double>(new double[source.Count]); // Retrieve Fear & Greed data from the external API. var fearGreedData = GetFearGreedData().Result; // Exit if no data was retrieved. if (fearGreedData == null || fearGreedData.Count == 0) return; // Loop through the source data and map the Fear & Greed values to the corresponding dates. for (int i = 0; i < source.Count; i++) { DateTime date = source.DateTimes[i]; if (fearGreedData.TryGetValue(date, out int value)) { Values[i] = value; // Assign the retrieved value for the date. } else { // If no data for the date, use the previous value or 0 if it's the first value. Values[i] = i > 0 ? Values[i - 1] : 0; } } } // Asynchronous method to fetch Fear & Greed data from the external API. private async Task<Dictionary<DateTime, int>> GetFearGreedData() { var data = new Dictionary<DateTime, int>(); // Dictionary to store date-value pairs. try { // API request to get Fear & Greed index data in JSON format. var response = await client.GetStringAsync( "<a href="https://api.alternative.me/fng/?limit=999999&format=json&date_format=us" target="_blank">https://api.alternative.me/fng/?limit=999999&format=json&date_format=us</a>"); // Parse the JSON response. var jsonResponse = JObject.Parse(response); var dataArray = jsonResponse["data"]; // Loop through the JSON array and extract values. foreach (var item in dataArray) { if (DateTime.TryParseExact(item["timestamp"].ToString(), "MM-dd-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date) && int.TryParse(item["value"].ToString(), out int value)) { data[date] = value; // Add date and value to the dictionary. } } } catch (Exception ex) { // Log errors for debugging if any issue occurs during data fetching. Debug.WriteLine($"Error fetching Fear & Greed data: {ex.Message}"); } return data; // Return the dictionary with date-value pairs. } // Method to define input parameters for the indicator. protected override void GenerateParameters() { // Define parameters: source time series and period. AddParameter("Source", ParameterType.TimeSeries, PriceComponent.Close); // Input series (e.g., closing price) AddParameter("Period", ParameterType.Int32, 20); // Lookback period (default 20) } } }
Rename
This is the relevant code in our CNN Fear/Greed indicator, we use an in-house class called WLWebClient.
WLWebClient client = new WLWebClient(WLWebClientOptions.Compression);
client.AddAcceptHeaders("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
client.AddLanguageHeaders("en-US,en;q=0.9");
client.AddHeader("Upgrade-Insecure-Requests", "1");
string s = client.Get("https://production.dataviz.cnn.io/index/fearandgreed/graphdata");
WLWebClient client = new WLWebClient(WLWebClientOptions.Compression);
client.AddAcceptHeaders("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
client.AddLanguageHeaders("en-US,en;q=0.9");
client.AddHeader("Upgrade-Insecure-Requests", "1");
string s = client.Get("https://production.dataviz.cnn.io/index/fearandgreed/graphdata");
No, a custom indicator is the right way. The source is returning data for a single TimeSeries, not OHLC/V data. We express these kinds of things as custom indicators in the WL7/8 paradigm.
Thanks it works now.
@Glitch: You could add this indicator now as community indicator if you like.
I implemented even a cache functionality inside, that not too many HTTPS requests are made.
@Glitch: You could add this indicator now as community indicator if you like.
I implemented even a cache functionality inside, that not too many HTTPS requests are made.
CODE:
/* * CustomCryptoFearGreedIndex * Author: Stephan Ferraro * Email: stephan.ferraro@aionda.com * * Description: * This code defines a custom indicator for WealthLab called "Custom Crypto Fear & Greed Index". * It fetches external data from an API to calculate the Fear & Greed Index for cryptocurrency markets. * The indicator caches the data to avoid unnecessary HTTP requests if the latest date in the time series has not changed. * If a new data point (candle) is added to the time series, the cache is refreshed to ensure updated values are fetched. * * Key Features: * - Static caching mechanism to optimize performance and reduce HTTP calls. * - Dynamically maps Fear & Greed values to corresponding dates in the time series. * - Supports visualization in WealthLab with overbought and oversold levels. */ using WealthLab.Core; using System; using System.Collections.Generic; using System.Globalization; using WealthLab.Indicators; using Newtonsoft.Json.Linq; using System.Diagnostics; namespace WealthLab.MyIndicators { public class CustomCryptoFearGreedIndex : IndicatorBase { // Static cache to store Fear & Greed data to minimize redundant API calls. private static Dictionary<DateTime, int> _cachedData = new Dictionary<DateTime, int>(); // Tracks the last date when the cache was updated. private static DateTime _lastCacheDate = DateTime.MinValue; // Default constructor initializing overbought and oversold levels. public CustomCryptoFearGreedIndex() : base() { OverboughtLevel = 70; // Overbought threshold for the index. OversoldLevel = 30; // Oversold threshold for the index. } // Constructor for initializing with source data public CustomCryptoFearGreedIndex(TimeSeries source) : base() { Parameters[0].Value = source; // Assign the input time series. OverboughtLevel = 70; OversoldLevel = 30; Populate(); // Calculate the indicator values. } // Factory method for creating an instance of the indicator. public static CustomCryptoFearGreedIndex Series(TimeSeries source) { return new CustomCryptoFearGreedIndex(source); } // Name displayed in the WealthLab indicator list. public override string Name => "Custom Crypto Fear & Greed Index"; // Abbreviation of the indicator name. public override string Abbreviation => "CustomCryptoFearGreedIndex"; // Description displayed in the indicator manager in WealthLab. public override string HelpDescription => "Custom Crypto Fear & Greed Index based on external data source."; // Ensures the indicator is plotted in a separate pane. public override string PaneTag => "CustomCryptoFearGreedIndex"; // Default color for the indicator plot. public override WLColor DefaultColor => WLColor.Navy; // Main calculation method for populating the indicator values. public override void Populate() { TimeSeries source = Parameters[0].AsTimeSeries; // Get the input time series. DateTimes = source.DateTimes; // Set DateTimes from the source data. // Exit if source data is invalid or insufficient. if (source == null || source.Count == 0) return; // Initialize Values to hold calculated indicator values. if (Values == null || Values.Count != source.Count) Values = new List<double>(new double[source.Count]); DateTime latestDate = source.DateTimes[^1]; // Get the last date in the time series. // Refresh cache if a new data point is detected. if (_cachedData.Count == 0 || _lastCacheDate < latestDate) { _cachedData = GetFearGreedData(); // Fetch new data from the API. _lastCacheDate = latestDate; // Update the last cache date. } // Exit if no data is available in the cache. if (_cachedData == null || _cachedData.Count == 0) return; // Map Fear & Greed values to the corresponding dates in the time series. for (int i = 0; i < source.Count; i++) { DateTime date = source.DateTimes[i]; if (_cachedData.TryGetValue(date, out int value)) { Values[i] = value; // Assign the cached value for the date. } else { // If no data for the date, use the previous value or 0 if it's the first value. Values[i] = i > 0 ? Values[i - 1] : 0; } } } // Method to fetch Fear & Greed data from an external API. private Dictionary<DateTime, int> GetFearGreedData() { var data = new Dictionary<DateTime, int>(); try { // Set up HTTP client with necessary headers. WLWebClient client = new WLWebClient(WLWebClientOptions.Compression); client.AddAcceptHeaders("application/json"); client.AddLanguageHeaders("en-US,en;q=0.9"); client.AddHeader("Upgrade-Insecure-Requests", "1"); string response = client.Get("<a href="https://api.alternative.me/fng/?limit=999999&format=json&date_format=world" target="_blank">https://api.alternative.me/fng/?limit=999999&format=json&date_format=world</a>"); // Parse the JSON response. var jsonResponse = JObject.Parse(response); var dataArray = jsonResponse["data"]; // Extract date and value pairs from the JSON array. foreach (var item in dataArray) { if (DateTime.TryParseExact(item["timestamp"].ToString(), "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date) && int.TryParse(item["value"].ToString(), out int value)) { data[date] = value; // Store the date-value pair in the dictionary. } } } catch (Exception ex) { // Log any errors during data retrieval. Debug.WriteLine($"Error fetching Fear & Greed data: {ex.Message}"); } return data; // Return the populated dictionary. } // Method to define input parameters for the indicator. protected override void GenerateParameters() { // Add source time series and lookback period as parameters. AddParameter("Source", ParameterType.TimeSeries, PriceComponent.Close); // Input time series (e.g., closing price). } } }
Your Response
Post
Edit Post
Login is required