tradingview-rs 0.0.2

Tradingview datafeed api `tradingview-rs` project.
Documentation
use crate::{
    MarketType, News, NewsArea, NewsContent, NewsHeadlines, NewsSection, Result, UserCookies,
    utils::get,
};
use bon::builder;

static BASE_NEWS_URL: &str = "https://news-headlines.tradingview.com/v2";

fn get_news_category(market_type: MarketType) -> &'static str {
    match market_type {
        MarketType::All => "base",
        MarketType::Stocks(_) => "stock",
        MarketType::Funds(_) => "etf",
        MarketType::Futures => "futures",
        MarketType::Forex => "forex",
        MarketType::Crypto(_) => "crypto",
        MarketType::Indices => "index",
        MarketType::Bonds => "bond",
        MarketType::Economy => "economic",
    }
}

fn get_news_area(area: NewsArea) -> &'static str {
    match area {
        NewsArea::World => "WLD",
        NewsArea::Americas => "AME",
        NewsArea::Europe => "EUR",
        NewsArea::Asia => "ASI",
        NewsArea::Oceania => "OCN",
        NewsArea::Africa => "AFR",
    }
}

fn get_news_section(section: NewsSection) -> &'static str {
    match section {
        NewsSection::PressRelease => "press_release",
        NewsSection::FinancialStatement => "financial_statement",
        NewsSection::InsiderTrading => "insider_trading",
        NewsSection::ESG => "esg",
        NewsSection::CorpActivitiesAll => "corp_activity",
        NewsSection::AnalysisAll => "analysis",
        NewsSection::AnalysisRecommendations => "recommendation",
        NewsSection::EstimatesAndForecasts => "prediction",
        NewsSection::MarketToday => "markets_today",
        NewsSection::Surveys => "survey",
    }
}

#[builder]
pub async fn list_news(
    client: Option<&UserCookies>,
    #[builder(default = MarketType::All)] category: MarketType,
    area: Option<NewsArea>,
    section: Option<NewsSection>,
) -> Result<NewsHeadlines> {
    let category = get_news_category(category);
    let mut queries = vec![
        ("category", category),
        ("client", "web"),
        ("lang", "en"),
        ("streaming", "false"),
    ];
    if let Some(area) = area {
        queries.push(("area", get_news_area(area)));
    }
    if let Some(section) = section {
        queries.push(("section", get_news_section(section)));
    }
    let res = get(client, &format!("{BASE_NEWS_URL}/headlines"), &queries)
        .await?
        .json::<NewsHeadlines>()
        .await?;

    Ok(res)
}

async fn fetch_news(id: &str) -> Result<NewsContent> {
    let res = get(
        None,
        &format!("{BASE_NEWS_URL}/story"),
        &[("id", id), ("lang", "en")],
    )
    .await?
    .json::<NewsContent>()
    .await?;

    Ok(res)
}

impl News {
    pub fn get_url(&self) -> String {
        format!("https://www.tradingview.com{}", self.story_path)
    }

    pub fn get_source_url(&self) -> String {
        if let Some(url) = &self.link {
            return url.to_string();
        }
        self.get_url()
    }

    pub fn get_related_symbols(&self) -> Vec<String> {
        self.related_symbols
            .iter()
            .map(|s| s.symbol.to_owned())
            .collect()
    }

    pub async fn get_content(&self) -> Result<NewsContent> {
        fetch_news(&self.id).await
    }

    pub async fn get_source_html(&self) -> Result<String> {
        let res = get(None, &self.get_source_url(), &[]).await?.text().await?;
        Ok(res)
    }
}

#[tokio::test]
async fn test_list_news() -> Result<()> {
    let res = list_news().section(NewsSection::AnalysisAll).call().await?;
    println!("{:#?}", res);
    Ok(())
}

#[tokio::test]
async fn test_fetch_news() -> Result<()> {
    let _ = fetch_news("tag:reuters.com,2024:newsml_L4N3E9476:0").await?;

    let res = list_news().section(NewsSection::AnalysisAll).call().await?;

    for item in res.items[0..2].iter() {
        let content = item.get_content().await?;
        println!("{:#?}", content);
    }

    Ok(())
}

#[tokio::test]
async fn test_get_source_html() -> Result<()> {
    let res = list_news().section(NewsSection::AnalysisAll).call().await?;

    for item in res.items[0..1].iter() {
        let html = item.get_source_html().await?;
        println!("{:#?}", html);
    }

    Ok(())
}