David's Blog

Performing Technical Analysis in Rust

By David Li on Mon, 20 September 2023

Performing Technical Analysis in Rust

In this article, we will explore how to perform technical analysis in Rust. Technical analysis is a trading tool used to evaluate securities by analyzing statistical trends, such as price movements and trading volume. It is commonly used by traders to predict future price movements, making it an essential tool for trading strategies.

Rust is a systems programming language that is designed for performance, safety, and concurrency. Its memory safety guarantees and expressive type system make it an ideal choice for implementing reliable and efficient financial algorithms.

Setting Up the Environment

Before we dive into the main topic, ensure that you have Rust installed on your machine. If not, follow the installation guide found at the official Rust website.

Create a New Rust Project

Let’s start by creating a new Rust project:

$ cargo new technical_analysis_rust
$ cd technical_analysis_rust

Adding Dependencies

We will use the reqwest and serde libraries to fetch and parse historical price data from a REST API. Add the following dependencies to your Cargo.toml file:

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Fetching Historical Price Data

We will fetch historical price data for a given symbol from a REST API. For this example, we will use the Alpha Vantage API. Sign up for a free API key, and replace YOUR_API_KEY with the provided key.

use reqwest::Error;
use serde::Deserialize;
use std::collections::HashMap;

#[derive(Deserialize, Debug)]
struct TimeSeries {
    #[serde(rename = "Time Series (Daily)")]
    time_series: HashMap<String, DailyData>,
}

#[derive(Deserialize, Debug)]
struct DailyData {
    #[serde(rename = "1. open")]
    open: String,
    #[serde(rename = "2. high")]
    high: String,
    #[serde(rename = "3. low")]
    low: String,
    #[serde(rename = "4. close")]
    close: String,
    #[serde(rename = "5. volume")]
    volume: String,
}

async fn fetch_historical_data(symbol: &str, api_key: &str) -> Result<TimeSeries, Error> {
    let url = format!(
        "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={}&apikey={}",
        symbol, api_key
    );

    let response = reqwest::get(&url).await?;
    let time_series: TimeSeries = response.json().await?;

    Ok(time_series)
}

Calculating Moving Averages

Moving averages are a common technical analysis indicator. They smooth out price data by creating a constantly updated average price. We will implement the simple moving average (SMA) and exponential moving average (EMA) functions.

fn simple_moving_average(prices: &[f64], period: usize) -> Vec<f64> {
    let mut sma = vec![];

    for i in period..prices.len() {
        let average = prices[i - period..i].iter().sum::<f64>() / period as f64;
        sma.push(average);
    }

    sma
}

fn exponential_moving_average(prices: &[f64], period: usize) -> Vec<f64> {
    let mut ema = vec![prices[0]];

    let multiplier = 2.0 / (period as f64 + 1.0);

    for i in 1..prices.len() {
        let current_ema = (prices[i] - ema[i - 1]) * multiplier + ema[i - 1];
        ema.push(current_ema);
    }

    ema
}

Putting It All Together

Now let’s create a main function that fetches historical price data, calculates moving averages, and prints the results.

#[tokio::main]
async fn main() -> Result<(), Error> {
    let symbol = "MSFT";
    let api_key = "YOUR_API_KEY";
    let period = 14;

    let time_series = fetch_historical_data(symbol, api_key).await?;
    let prices: Vec<f64> = time_series
        .time_series
        .iter()
        .map(|(_, daily_data)| daily_data.close.parse::<f64>().unwrap())
        .collect();

    let sma = simple_moving_average(&prices, period);
    let ema = exponential_moving_average(&prices, period);

    println!("Simple Moving Average ({} days): {:?}", period, sma);
    println!("Exponential Moving Average ({} days): {:?}", period, ema);

    Ok(())
}

Conclusion

In this article, we demonstrated how to perform technical analysis using the Rust programming language. We fetched historical price data from a REST API, calculated simple and exponential moving averages, and printed the results. This is just the beginning, and you can build upon these concepts to create more advanced trading algorithms and strategies.

Rust’s memory safety guarantees and performance make it a great choice for implementing financial applications. By leveraging Rust’s powerful type system and library ecosystem, you can create efficient and reliable trading systems that can handle the demands of modern financial markets.

© Copyright 2024 by FriendlyUsers Tech Blog. Built with ♥ by FriendlyUser. Last updated on 2024-04-15.