1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
//! This retrieve and creates mapping between stock ticker and their current CIK.
//! These are defined per sec.gov website

use std::collections::HashMap;

/// Gets ticker and cik mappings
///
/// Returns a hashmap where key=value maps to ticker=cik
///
/// # Examples
/// ```
/// let map = sec_ticker_parser::list().unwrap();
/// assert_ne!(map.len(), 0)
/// ```
pub fn list() -> Result<HashMap<String, u64>, reqwest::Error> {
    let url = format!("https://www.sec.gov/include/ticker.txt");
    let body = reqwest::blocking::get(url.as_str())?.text();
    match body {
        Ok(r) => {
            let companies = r.split("\n").collect::<Vec<&str>>();
            let mut map = HashMap::new();
            for c in companies {
                let ticker_cik = c.split("\t").collect::<Vec<&str>>();
                let cik = match ticker_cik[1].parse::<u64>() {
                    Ok(r1) => r1,
                    Err(e1) => {
                        println!("Could not parse CIK: {:?}. {}", &c, &e1);
                        0
                    }
                };
                map.insert(ticker_cik[0].to_string(), cik);
            }
            Ok(map)
        }
        Err(e) => panic!("Error with query. URL: {}. {}", &url, &e),
    }
}

/// Given a valid map and ticker, return the cik.
/// If no valid cik matches, then will return 0.
///
/// # Example
/// ```
/// let map = sec_ticker_parser::list().unwrap();
/// let my_cik = sec_ticker_parser::cik(&map, "vz");
/// assert_eq!(my_cik, 732712);
/// ```
pub fn cik(map: &HashMap<String, u64>, ticker: &str) -> u64 {
    match map.get(&ticker.to_lowercase()) {
        Some(r) => *r,
        None => 0,
    }
}

/// Give a valid map and cik, return the ticket symbol.
/// This will iterate over the hashmap until value is found matching.
/// If no ticker matches, will return the string "none".
///
/// # Example
/// ```
/// let map = sec_ticker_parser::list().unwrap();
/// let my_ticker = sec_ticker_parser::ticker(&map, &732712);
/// assert_eq!(my_ticker, "vz");
/// ```
pub fn ticker(map: &HashMap<String, u64>, cik: &u64) -> String {
    for (ticker, value) in map {
        if value == cik {
            return ticker.to_string();
        }
    }
    "none".to_string()
}

/// Unit test  for each function
#[cfg(test)]
mod tests {
    #[test]
    fn test_list() {
        let o = super::list().unwrap();
        // println!("{:?}", o);
        assert!(!o.is_empty());
        assert_eq!(o.get("vz"), Some(&732712))
    }

    #[test]
    fn test_cik() {
        let map = super::list().unwrap();
        let my_cik = super::cik(&map, "vz");
        assert_eq!(my_cik, 732712);
        let invalid_cik = super::cik(&map, "invalid");
        assert_eq!(invalid_cik, 0);
    }

    #[test]
    fn test_ticker() {
        let map = super::list().unwrap();
        let my_ticker = super::ticker(&map, &732712);
        assert_eq!(my_ticker, "vz");
        let invalid_ticker = super::ticker(&map, &0);
        assert_eq!(invalid_ticker, "none")
    }
}