mdraber
Published © GPL3+

Arduino Stock Quote Ticker

Built an IoT project with Arduino, integrating Alpha Vantage API for stock data. Efficiently parsing JSON for real-time data use

IntermediateWork in progress3 hours660
Arduino Stock Quote Ticker

Things used in this project

Story

Read more

Code

Reading stock quotes for three Stocks and parsing the results using tools from ArduinoJson library

Arduino
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>

const char* ssid = "xxxxxxx";
const char* password = "xxxxxxx";
const char* apiKey = "xxxxxxxxxx";
const char* serverName = "www.alphavantage.co";


// Define the WiFi client
WiFiClientSecure client;

void setup() {
  Serial.begin(9600);
  delay(10);

  // Connect to Wi-Fi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println(fetchStockData("IBM"));
  Serial.println(fetchStockData("AAPL"));
  Serial.println(fetchStockData("TSLA"));
}

void loop() {
  // Add your logic here if you need to repeat fetching data periodically
}

String roundStringToTwoDecimal(const char* valueStr) {
    // Convert string to float
    float value = atof(valueStr);
    // Round the float to two decimal places
    float roundedValue = roundf(value * 100) / 100;
    // Convert rounded float back to string
    return String(roundedValue, 2);
}


String fetchStockData(String stockSymbol) {
  client.setInsecure(); // Use this line if you don't have the SSL fingerprint and want to ignore SSL verification
  if (client.connect(serverName, 443)) { // Port 443 for HTTPS
    String url = "/query?function=GLOBAL_QUOTE&symbol=" + stockSymbol + "&apikey=" + apiKey;
    
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + serverName + "\r\n" + 
                 "Connection: close\r\n\r\n");
    
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return "";
      }
    }

    //Skip HTTP headers
    while (client.available()) {
      String line = client.readStringUntil('\r');
      if (line == "\n" || line == "\r\n") {
        break;
      }
    }

    // Read the JSON response
    String payload = "";
    while (client.available()) {
      payload += client.readStringUntil('\r');
    }

    //Serial.println("Received payload:");
    //Serial.println(payload);

    // Parse JSON
      DynamicJsonDocument doc(1024);
      deserializeJson(doc, payload);

    // Extract and print the desired information
    const char* symbol = doc["Global Quote"]["01. symbol"];
    const char* price = doc["Global Quote"]["05. price"];
    const char* change = doc["Global Quote"]["10. change percent"];

    // Combine the strings
    return String(symbol) + " " + roundStringToTwoDecimal(price) + " " + roundStringToTwoDecimal(change) + "%" ;

    client.stop();

  } else {
    Serial.println("Connection to server failed");
    return "";
  }
}

Requesting quotes for three stocks and displaying parsed result on the smal TFT 240x240 display

Arduino
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789

// ST7789 TFT module connections
#define TFT_DC    D1     // TFT DC pin is connected to NodeMCU pin D1 (GPIO5)
#define TFT_RST   D2     // TFT RST pin is connected to NodeMCU pin D2 (GPIO4)
#define TFT_CS    D8     // TFT CS pin is connected to NodeMCU pin D8 (GPIO15)

// Initialize ST7789 TFT library with hardware SPI module
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// Define color constants
#define BLACK       0x0000
#define WHITE       0xFFFF
#define RED         0xF800
#define GREEN       0x07E0
#define BLUE        0x001F

// Previous state buffers
String prevPrice[3] = {"", "", ""};
String prevPercentage[3] = {"", "", ""};

const char* ssid = "xxxxxx";
const char* password = "xxxxxxx";
const char* apiKey = "xxxxxx";
//const char* stockSymbol = "VOD.LON";
const char* serverName = "www.alphavantage.co";


// Define the WiFi client
WiFiClientSecure client;

void setup() {
  Serial.begin(9600);
  delay(10000 );

  // Connect to Wi-Fi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  //Serial.println(fetchStockData("IBM"));
  //Serial.println(fetchStockData("AAPL"));
  //Serial.println(fetchStockData("TSLA"));
  // Initialize the display
  tft.init(240, 240, SPI_MODE2);  // Init ST7789 display 240x240 pixels

  // Set the rotation (adjust as needed)
  tft.setRotation(3);

  Serial.println(F("Initialized"));

  // Clear the screen
  tft.fillScreen(BLACK);
  String META = fetchStockData("META");
  String GOOG = fetchStockData("AMZN");
  String AAPL = fetchStockData("AAPL");
  displayStockInfo(META, 0);
  displayStockInfo(GOOG, 1);
  displayStockInfo(AAPL, 2);

}

void loop(){

}

String roundStringToTwoDecimal(const char* valueStr) {
    // Convert string to float
    float value = atof(valueStr);
    // Round the float to two decimal places
    float roundedValue = roundf(value * 100) / 100;
    // Convert rounded float back to string
    return String(roundedValue, 2);
}


String fetchStockData(String stockSymbol) {
  client.setInsecure(); // Use this line if you don't have the SSL fingerprint and want to ignore SSL verification
  if (client.connect(serverName, 443)) { // Port 443 for HTTPS
    String url = "/query?function=GLOBAL_QUOTE&symbol=" + stockSymbol + "&apikey=" + apiKey;
    
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + serverName + "\r\n" + 
                 "Connection: close\r\n\r\n");
    
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return "";
      }
    }

    //Skip HTTP headers
    while (client.available()) {
      String line = client.readStringUntil('\r');
      if (line == "\n" || line == "\r\n") {
        break;
      }
    }

    // Read the JSON response
    String payload = "";
    while (client.available()) {
      payload += client.readStringUntil('\r');
    }

    //Serial.println("Received payload:");
    Serial.println(payload);

    // Parse JSON
      DynamicJsonDocument doc(1024);
      deserializeJson(doc, payload);

    // Extract and print the desired information
    const char* symbol = doc["Global Quote"]["01. symbol"];
    const char* price = doc["Global Quote"]["05. price"];
    const char* change = doc["Global Quote"]["10. change percent"];

    // Combine the strings
    return String(symbol) + ";" + roundStringToTwoDecimal(price) + ";" + roundStringToTwoDecimal(change) + "%" ;

    client.stop();

  } else {
    Serial.println("Connection to server failed");
    return "";
  }
}

void displayStockInfo(String stockInfo, int lineNumber) {
  
  // Set the font size
  tft.setTextSize(2);
  if (stockInfo.indexOf("-")>0) tft.setTextColor(RED, BLACK); else tft.setTextColor(GREEN, BLACK);
  
  // Calculate the Y position based on line number
  int yPos = lineNumber * 20;
  
  // Set the cursor to the start of the line
  tft.setCursor(0, yPos);
  
  // Print the stock info to the display
  tft.print(stockInfo);
}

Requesting 3 quotes but this time ChatGPT helped me format the parsed response on the TFT screen

Arduino
#include <ESP8266WiFi.h>
  #include <WiFiClientSecure.h>
  #include <ArduinoJson.h>
  #include <SPI.h>
  #include <Adafruit_GFX.h>    // Core graphics library
  #include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
  
  // ST7789 TFT module connections
  #define TFT_DC    D1     // TFT DC pin is connected to NodeMCU pin D1 (GPIO5)
  #define TFT_RST   D2     // TFT RST pin is connected to NodeMCU pin D2 (GPIO4)
  #define TFT_CS    D8     // TFT CS pin is connected to NodeMCU pin D8 (GPIO15)
  
  // Initialize ST7789 TFT library with hardware SPI module
  Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
  
  // Define color constants
  #define BLACK       0x0000
  #define WHITE       0xFFFF
  #define RED         0xF800
  #define GREEN       0x07E0
  #define BLUE        0x001F
  
  // Previous state buffers
  String prevPrice[3] = {"", "", ""};
  String prevPercentage[3] = {"", "", ""};
  
  const char* ssid = "xxxxxx";
  const char* password = "xxxxx";
  const char* apiKey = "xxxxxx";
  //const char* stockSymbol = "VOD.LON";
  const char* serverName = "www.alphavantage.co";
  
  
  // Define the WiFi client
  WiFiClientSecure client;
  
  void setup() {
    Serial.begin(9600);
    delay(30000);
  
    // Connect to Wi-Fi network
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
  
    WiFi.begin(ssid, password);
  
    while (WiFi.status() != WL_CONNECTED) {
      delay(1000);
      Serial.print(".");
    }
  
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  
    // Initialize the display
    tft.init(240, 240, SPI_MODE2);  // Init ST7789 display 240x240 pixels
  
    // Set the rotation (adjust as needed)
    tft.setRotation(3);
  
    Serial.println(F("Initialized"));
  
    // Clear the screen
    tft.fillScreen(BLACK);
  
    // Draw static elements
    drawStockNames();
  }
  
  void loop() {
   
    // Add your logic here if you need to repeat fetching data periodically
    String AAPL = fetchStockData("AAPL");
    String AMZN = fetchStockData("AMZN");
    String META = fetchStockData("META");
    updateStockInfo(AAPL, 0);
    updateStockInfo(AMZN, 1);
    updateStockInfo(META, 2);
    // for the ticker to work you have to have access to real time stock exchange data:(. If you do not have it you will be displayed one value each day
    delay(60000);
  
  }
  
  String roundStringToTwoDecimal(const char* valueStr) {
      // Convert string to float
      float value = atof(valueStr);
      // Round the float to two decimal places
      float roundedValue = roundf(value * 100) / 100;
      // Convert rounded float back to string
      return String(roundedValue, 2);
  }
  
  
  String fetchStockData(String stockSymbol) {
    client.setInsecure(); // Use this line if you don't have the SSL fingerprint and want to ignore SSL verification
    if (client.connect(serverName, 443)) { // Port 443 for HTTPS
      String url = "/query?function=GLOBAL_QUOTE&symbol=" + stockSymbol + "&apikey=" + apiKey;
      
      client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + serverName + "\r\n" + 
                   "Connection: close\r\n\r\n");
      
      unsigned long timeout = millis();
      while (client.available() == 0) {
        if (millis() - timeout > 5000) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return "";
        }
      }
  
      //Skip HTTP headers
      while (client.available()) {
        String line = client.readStringUntil('\r');
        if (line == "\n" || line == "\r\n") {
          break;
        }
      }
  
      // Read the JSON response
      String payload = "";
      while (client.available()) {
        payload += client.readStringUntil('\r');
      }
  
      //Serial.println("Received payload:");
      Serial.println(payload);
  
      // Parse JSON
        DynamicJsonDocument doc(1024);
        deserializeJson(doc, payload);
  
      // Extract and print the desired information
      const char* symbol = doc["Global Quote"]["01. symbol"];
      const char* price = doc["Global Quote"]["05. price"];
      const char* change = doc["Global Quote"]["10. change percent"];
  
      // Combine the strings
      return String(symbol) + ";" + roundStringToTwoDecimal(price) + ";" + roundStringToTwoDecimal(change) + "%" ;
  
      client.stop();
  
    } else {
      Serial.println("Connection to server failed");
      return "";
    }
  }
  
  void drawStockNames() {
    // Draw static stock names
    drawStockName("AAPL", 0);
    drawStockName("AMZN", 1);
    drawStockName("META", 2);
  }
  
  void drawStockName(String stockName, int position) {
    int yOffset = position * 80; // Calculate vertical offset based on position
  
    // Define rectangle sizes and spacing
    int stockRectWidth = 70;
    int rectHeight = 30;
  
    // Draw stock name rectangle
    tft.fillRect(5, yOffset, stockRectWidth, rectHeight, WHITE);
    tft.setCursor(10, yOffset + 8);
    tft.setTextColor(BLACK);
    tft.setTextSize(2);
    tft.print(stockName);
  }
  
  void updateStockInfo(String stockInfo, int position) {
  int yOffset = position * 80; // Calculate vertical offset based on position

  // Split the stockInfo string into stockName, price, and percentage
  int firstSemi = stockInfo.indexOf(';');
  int secondSemi = stockInfo.indexOf(';', firstSemi + 1);

  String stockName = stockInfo.substring(0, firstSemi);
  String price = stockInfo.substring(firstSemi + 1, secondSemi);
  String percentage = stockInfo.substring(secondSemi + 1);

  // Define rectangle sizes and spacing
  int rectWidth = 110;
  int rectHeight = 30;
  int rectSpacing = 3;

  // Define colors based on percentage sign
  uint16_t color = (percentage[0] == '-') ? RED : GREEN;

  // Update only if there are changes
  if (prevPrice[position] != price) {
    // Clear the previous price
    tft.fillRect(5, yOffset + rectHeight + rectSpacing, rectWidth, rectHeight, BLACK);
    // Draw price rectangle
    tft.fillRect(5, yOffset + rectHeight + rectSpacing, rectWidth, rectHeight, color);
    tft.setCursor(10, yOffset + rectHeight + rectSpacing + 8);
    tft.setTextColor((color == GREEN) ? BLACK : WHITE); // Set text color based on box color
    tft.setTextSize(2);
    tft.print(price);
    prevPrice[position] = price;
  }

  if (prevPercentage[position] != percentage) {
    // Clear the previous percentage
    tft.fillRect(5 + rectWidth + rectSpacing, yOffset + rectHeight + rectSpacing, rectWidth, rectHeight, BLACK);
    // Draw percentage rectangle
    tft.fillRect(5 + rectWidth + rectSpacing, yOffset + rectHeight + rectSpacing, rectWidth, rectHeight, color);
    tft.setCursor(10 + rectWidth + rectSpacing, yOffset + rectHeight + rectSpacing + 8);
    tft.setTextColor((color == GREEN) ? BLACK : WHITE); // Set text color based on box color
    tft.setTextSize(2);
    tft.print(percentage);
    prevPercentage[position] = percentage;
  }
}

Reading stock quote for Apple and displaying received unparsed information in the serial monitor

Arduino
We are reading received response ignoring control data and displaying ony Json part of the response
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

const char* ssid = "Dziubym";
const char* password = "Mikigosia1";
const char* apiKey = "C38RBEPO37T9RG1D";
const char* stockSymbol = "AAPL";
const char* serverName = "www.alphavantage.co";


// Define the WiFi client
WiFiClientSecure client;

void setup() {
  Serial.begin(9600);
  delay(10);

  // Connect to Wi-Fi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  fetchStockData();
}

void loop() {
  // Add your logic here if you need to repeat fetching data periodically
}

void fetchStockData() {
  client.setInsecure(); // Use this line if you don't have the SSL fingerprint and want to ignore SSL verification
  if (client.connect(serverName, 443)) { // Port 443 for HTTPS
    String url = "/query?function=GLOBAL_QUOTE&symbol=" + String(stockSymbol) + "&apikey=" + apiKey;
    
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + serverName + "\r\n" + 
                 "Connection: close\r\n\r\n");
    
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }
    }

    // Skip HTTP headers
    while (client.available()) {
      String line = client.readStringUntil('\r');
      if (line == "\n" || line == "\r\n") {
        break;
      }
    }

    // Read the JSON response
    String payload = "";
    while (client.available()) {
      payload += client.readStringUntil('\r');
    }

    Serial.println("Received payload:");
    Serial.println(payload);

    client.stop();

  } else {
    Serial.println("Connection to server failed");
  }
}

Credits

mdraber
50 projects • 73 followers
Contact

Comments

Please log in or sign up to comment.