Skip to main content

trading_ig/client_sentiment/
api.rs

1//! Client sentiment API endpoints.
2
3use http::Method;
4use serde::Deserialize;
5use tracing::instrument;
6
7use crate::Result;
8use crate::client::IgClient;
9
10use super::models::Sentiment;
11
12/// Typed accessor for the `/clientsentiment` endpoints.
13///
14/// Obtain via [`IgClient::client_sentiment`].
15#[derive(Debug)]
16pub struct ClientSentimentApi<'a> {
17    pub(crate) client: &'a IgClient,
18}
19
20#[derive(Deserialize)]
21#[serde(rename_all = "camelCase")]
22struct SentimentEnvelope {
23    client_sentiments: Vec<Sentiment>,
24}
25
26impl ClientSentimentApi<'_> {
27    /// Fetch client sentiment for a single market.
28    ///
29    /// # Errors
30    ///
31    /// Returns [`crate::Error::Api`] with `errorCode`
32    /// `error.public-api.failure.market-not-found` if the market ID does not
33    /// exist.
34    #[instrument(skip(self), fields(market_id = %market_id))]
35    pub async fn get(&self, market_id: &str) -> Result<Sentiment> {
36        let path = format!("clientsentiment/{market_id}");
37        self.client
38            .transport
39            .request::<(), Sentiment>(
40                Method::GET,
41                &path,
42                Some(1),
43                None::<&()>,
44                &self.client.session,
45            )
46            .await
47    }
48
49    /// Fetch client sentiment for multiple markets in a single call.
50    ///
51    /// `market_ids` should be a slice of market identifiers (e.g.
52    /// `["CC.D.LCO.UNC.IP", "IX.D.DAX.IFD.IP"]`).
53    #[instrument(skip(self), fields(count = market_ids.len()))]
54    pub async fn get_many(&self, market_ids: &[&str]) -> Result<Vec<Sentiment>> {
55        let ids = market_ids.join(",");
56        let path = format!("clientsentiment?marketIds={ids}");
57        let envelope: SentimentEnvelope = self
58            .client
59            .transport
60            .request(
61                Method::GET,
62                &path,
63                Some(1),
64                None::<&()>,
65                &self.client.session,
66            )
67            .await?;
68        Ok(envelope.client_sentiments)
69    }
70
71    /// Fetch client sentiment for markets related to the given market.
72    ///
73    /// Returns sentiment for correlated instruments that IG considers
74    /// "related" to `market_id`.
75    #[instrument(skip(self), fields(market_id = %market_id))]
76    pub async fn related(&self, market_id: &str) -> Result<Vec<Sentiment>> {
77        let path = format!("clientsentiment/related/{market_id}");
78        let envelope: SentimentEnvelope = self
79            .client
80            .transport
81            .request(
82                Method::GET,
83                &path,
84                Some(1),
85                None::<&()>,
86                &self.client.session,
87            )
88            .await?;
89        Ok(envelope.client_sentiments)
90    }
91}