- ago
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:
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) } } }
0
149
4 Replies

Reply

Bookmark

Sort
Glitch8
 ( 13.30% )
- ago
#1
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");
1
- ago
#2
0
Glitch8
 ( 13.30% )
- ago
#3
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.
1
- ago
#4
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.
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).       }    } }

1

Reply

Bookmark

Sort