use serde::{Deserialize, Serialize};
use crate::adapters::common::encode_path_segment;
use crate::error::Result;
use super::build_client;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SicCode {
#[serde(rename = "sicCode")]
pub sic_code: Option<String>,
#[serde(rename = "industryTitle")]
pub industry_title: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SicEntry {
pub symbol: Option<String>,
pub name: Option<String>,
pub cik: Option<String>,
#[serde(rename = "sicCode")]
pub sic_code: Option<String>,
#[serde(rename = "industryTitle")]
pub industry_title: Option<String>,
#[serde(rename = "businessAddress")]
pub business_address: Option<String>,
#[serde(rename = "phoneNumber")]
pub phone_number: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct CotSymbol {
#[serde(rename = "trading_symbol")]
pub trading_symbol: Option<String>,
#[serde(rename = "short_name")]
pub short_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct CotReport {
pub date: Option<String>,
pub symbol: Option<String>,
#[serde(rename = "short_name")]
pub short_name: Option<String>,
#[serde(rename = "current_long_all")]
pub current_long_all: Option<f64>,
#[serde(rename = "current_short_all")]
pub current_short_all: Option<f64>,
#[serde(rename = "change_long_all")]
pub change_long_all: Option<f64>,
#[serde(rename = "change_short_all")]
pub change_short_all: Option<f64>,
#[serde(rename = "pct_of_oi_long_all")]
pub pct_of_oi_long_all: Option<f64>,
#[serde(rename = "pct_of_oi_short_all")]
pub pct_of_oi_short_all: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct CotAnalysis {
pub date: Option<String>,
pub symbol: Option<String>,
#[serde(rename = "short_name")]
pub short_name: Option<String>,
pub sector: Option<String>,
#[serde(rename = "currentNetPosition")]
pub current_net_position: Option<f64>,
#[serde(rename = "previousNetPosition")]
pub previous_net_position: Option<f64>,
#[serde(rename = "changeInNetPosition")]
pub change_in_net_position: Option<f64>,
#[serde(rename = "marketSentiment")]
pub market_sentiment: Option<String>,
#[serde(rename = "reversalTrend")]
pub reversal_trend: Option<String>,
}
pub async fn sic_codes() -> Result<Vec<SicCode>> {
let client = build_client()?;
client
.get("/api/v4/standard_industrial_classification_list", &[])
.await
}
pub async fn sic_by_code(code: &str) -> Result<Vec<SicEntry>> {
let client = build_client()?;
client
.get(
"/api/v4/standard_industrial_classification",
&[("sicCode", code)],
)
.await
}
pub async fn cot_symbols() -> Result<Vec<CotSymbol>> {
let client = build_client()?;
client
.get("/api/v4/commitment_of_traders_report/list", &[])
.await
}
pub async fn cot_report(symbol: &str) -> Result<Vec<CotReport>> {
let client = build_client()?;
let path = format!(
"/api/v4/commitment_of_traders_report/{}",
encode_path_segment(symbol)
);
client.get(&path, &[]).await
}
pub async fn cot_analysis(symbol: &str) -> Result<Vec<CotAnalysis>> {
let client = build_client()?;
let path = format!(
"/api/v4/commitment_of_traders_report_analysis/{}",
encode_path_segment(symbol)
);
client.get(&path, &[]).await
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_sic_codes_mock() {
let mut server = mockito::Server::new_async().await;
let _mock = server
.mock("GET", "/api/v4/standard_industrial_classification_list")
.match_query(mockito::Matcher::AllOf(vec![mockito::Matcher::UrlEncoded(
"apikey".into(),
"test-key".into(),
)]))
.with_status(200)
.with_body(
serde_json::json!([
{
"sicCode": "3674",
"industryTitle": "Semiconductors and Related Devices"
}
])
.to_string(),
)
.create_async()
.await;
let client = super::super::build_test_client(&server.url()).unwrap();
let result: Vec<SicCode> = client
.get("/api/v4/standard_industrial_classification_list", &[])
.await
.unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].sic_code.as_deref(), Some("3674"));
assert_eq!(
result[0].industry_title.as_deref(),
Some("Semiconductors and Related Devices")
);
}
}