use serde::Deserialize;
use std::collections::HashMap;
pub use crate::strnum::FloatOrString;
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Guru {
pub id: String,
pub name: String,
pub url: Option<String>,
pub company: String,
pub num_of_stocks: FloatOrString,
pub value: FloatOrString,
pub turnover: FloatOrString,
pub latest_update: String,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Gurus {
pub all: HashMap<String, Vec<Guru>>,
pub my: HashMap<String, Vec<String>>,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruTrades {
pub holdings: Vec<GuruHoldings>,
pub picks: Vec<GuruPicks2>,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruHoldings {
pub change: FloatOrString,
pub current_shares: FloatOrString,
pub date: String,
pub guru: String,
pub guru_id: String,
pub perc_assets: FloatOrString,
pub perc_shares: FloatOrString,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruPicks2 {
#[serde(rename = "Avg")]
pub avg: FloatOrString,
pub action: String,
pub comment: String,
pub current_shares: FloatOrString,
pub date: String,
pub guru: String,
pub guru_id: String,
pub impact: FloatOrString,
pub price_max: FloatOrString,
pub price_min: FloatOrString,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruPick {
#[serde(rename = "GuruName")]
pub guru_name: String,
#[serde(rename = "RecmAction")]
pub recm_action: String,
#[serde(rename = "RecmDate")]
pub recm_date: String,
#[serde(rename = "RecmPrice")]
pub recm_price: FloatOrString,
pub change: FloatOrString,
pub comment: String,
pub company: String,
pub currency: String,
pub currency_txt: String,
pub price: FloatOrString,
pub price_max: FloatOrString,
pub price_min: FloatOrString,
pub sector: String,
pub share_current: FloatOrString,
pub symbol: String,
pub symbol_ori: String,
pub trans_share: FloatOrString,
#[serde(rename = "type")]
pub transaction_type: String,
pub exchange: String,
pub industry: String,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruPortfolio {
pub summary: GuruPortSummary,
pub port: Vec<GuruPosition>,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruPortSummary {
pub country: String,
pub date: String,
pub equity: FloatOrString,
pub firm: String,
pub num_new: FloatOrString,
pub number_of_stocks: FloatOrString,
pub turnover: FloatOrString,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct GuruPosition {
#[serde(rename = "13f_date")]
pub date_13f: String,
#[serde(rename = "52h")]
pub num_52h: FloatOrString,
#[serde(rename = "52l")]
pub num_52l: FloatOrString,
pub change: FloatOrString,
pub company: String,
pub currency: String,
pub currency_txt: String,
pub exchange: String,
pub impact: FloatOrString,
pub industry: String,
pub mktcap: FloatOrString,
pub pct: FloatOrString,
pub pe: FloatOrString,
pub position: FloatOrString,
pub price: FloatOrString,
pub sector: String,
pub share: FloatOrString,
pub symbol: String,
pub symbol_ori: String,
pub value: FloatOrString,
#[serde(rename = "yield")]
pub transaction_yield: FloatOrString,
pub class: String,
pub share_change_pct: FloatOrString,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Politician {
pub id: u32,
pub full_name: String,
pub position: String,
pub party: String,
pub district: Option<String>,
pub state: String,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct PoliticianTransaction {
pub symbol: String,
pub company: String,
pub exchange: String,
pub industry: usize,
pub class: AssetType,
pub stockid: String,
pub option_type: Option<String>,
pub strike_price: Option<FloatOrString>,
pub trans_type: String,
pub amount: String,
pub disclosure_date: String,
pub transaction_date: String,
pub expiration_date: Option<String>,
pub id: u32,
pub full_name: String,
pub official_full: Option<String>,
pub position: String,
pub state: String,
pub party: String,
}
#[derive(Deserialize, Debug)]
pub enum AssetType {
#[serde(rename = "Common Stock")]
CommonStock,
Option,
#[serde(rename = "ETF")]
Etf,
#[serde(rename = "Preferred Stock")]
PreferredStock,
Bond,
Units,
Warrant,
Other,
}
#[derive(Deserialize, Debug)]
pub struct PoliticianTransactionList {
pub count: usize,
#[serde(rename = "currentPage")]
pub current_page: u32,
#[serde(rename = "lastPage")]
pub last_page: u32,
pub total: u32,
pub data: Vec<PoliticianTransaction>,
}
#[cfg(test)]
mod tests {
use super::super::*;
use super::*;
use crate::serde_json::Error;
use std::{convert::TryFrom, env};
use time::{Date, UtcDateTime};
fn get_months_before(date: Date, months: u8) -> Date {
let mut day = date.day();
let mut month = date.month() as u8;
let mut year = date.year();
while month + 1 < months {
month += 12;
year -= 1;
}
month -= months;
let month: time::Month = time::Month::try_from(month).unwrap();
day = day.min(month.length(year));
Date::from_calendar_date(year, month, day).unwrap()
}
#[tokio::test]
async fn test_guru_trades() {
if let Ok(token) = env::var("GURUFOCUS_TOKEN") {
if !token.is_empty() {
let gf_connect = GuruFocusConnector::new(token);
let stock = "WMT";
let trades = gf_connect.get_guru_trades(stock).await;
assert!(trades.is_ok());
let trades = serde_json::from_value::<HashMap<String, GuruTrades>>(trades.unwrap());
assert!(trades.is_ok());
}
}
}
#[tokio::test]
async fn test_guru_picks() {
if let Ok(token) = env::var("GURUFOCUS_TOKEN") {
if !token.is_empty() {
let gf_connect = GuruFocusConnector::new(token);
let gurus = ["7", "16", "28"];
let now = UtcDateTime::now().date();
let three_months_ago = get_months_before(now, 3);
let page = 1;
let trades = gf_connect
.get_guru_picks(&gurus, three_months_ago, page)
.await;
assert!(trades.is_ok());
}
}
}
#[tokio::test]
async fn test_gurulist() {
if let Ok(token) = env::var("GURUFOCUS_TOKEN") {
if !token.is_empty() {
let gf_connect = GuruFocusConnector::new(token);
let guru_data = gf_connect.get_gurus().await;
assert!(guru_data.is_ok());
}
}
}
#[tokio::test]
async fn test_guru_portfolios() {
if let Ok(token) = env::var("GURUFOCUS_TOKEN") {
if !token.is_empty() {
let gf_connect = GuruFocusConnector::new(token);
let gurus = ["47", "39"];
let portfolios = gf_connect.get_guru_portfolios(&gurus).await;
assert!(portfolios.is_ok());
let portfolios =
serde_json::from_value::<HashMap<String, GuruPortfolio>>(portfolios.unwrap());
assert!(portfolios.is_ok());
}
}
}
#[tokio::test]
async fn test_politicianlist() {
if let Ok(token) = env::var("GURUFOCUS_TOKEN") {
if !token.is_empty() {
let gf_connect = GuruFocusConnector::new(token);
let politicians = gf_connect.get_politicians().await;
assert!(politicians.is_ok());
}
}
}
#[tokio::test]
async fn test_politiciantransactions() {
if let Ok(token) = env::var("GURUFOCUS_TOKEN") {
if !token.is_empty() {
let gf_connect = GuruFocusConnector::new(token);
let politician_transactions = gf_connect.get_politician_transactions(1, None).await;
assert!(politician_transactions.is_ok());
let politician_transactions: Result<PoliticianTransactionList, Error> =
serde_json::from_value(politician_transactions.unwrap());
assert!(politician_transactions.is_ok());
}
}
}
}