use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value; use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Market {
pub can_close_early: Option<bool>,
pub cap_strike: Option<f64>,
pub category: Option<String>,
pub close_time: Option<DateTime<Utc>>,
pub custom_strike: Option<HashMap<String, Value>>,
pub event_ticker: Option<String>,
pub expected_expiration_time: Option<DateTime<Utc>>,
pub expiration_time: Option<DateTime<Utc>>,
pub expiration_value: Option<String>,
pub fee_waiver_expiration_time: Option<DateTime<Utc>>,
pub floor_strike: Option<f64>,
pub functional_strike: Option<String>,
pub last_price: Option<f64>,
pub latest_expiration_time: Option<DateTime<Utc>>,
pub liquidity: Option<i64>,
pub no_ask: Option<f64>,
pub no_bid: Option<f64>,
pub no_sub_title: Option<String>,
pub notional_value: Option<f64>,
pub open_interest: Option<f64>,
pub open_time: Option<DateTime<Utc>>,
pub previous_price: Option<f64>,
pub previous_yes_ask: Option<f64>,
pub previous_yes_bid: Option<f64>,
pub response_price_units: Option<String>,
pub result: Option<String>,
pub risk_limit_cents: Option<f64>,
pub rules_primary: Option<String>,
pub rules_secondary: Option<String>,
pub settlement_timer_seconds: Option<f64>,
pub settlement_value: Option<f64>,
pub strike_type: Option<String>,
pub subtitle: Option<String>,
pub tick_size: Option<f64>,
pub ticker: Option<String>,
pub title: Option<String>,
pub volume: Option<f64>,
pub volume_24h: Option<f64>,
pub yes_ask: Option<f64>,
pub yes_bid: Option<f64>,
pub yes_sub_title: Option<String>,
}
impl Market {
pub fn liquidity_dollars(&self) -> String {
self.liquidity
.map(|cents| format!("${:.2}", cents as f64 / 100.0))
.unwrap_or_else(|| "Liquidity N/A".to_string())
}
pub fn volume_dollars(&self) -> String {
self.volume
.map(|volume| format!("${:.2}", volume))
.unwrap_or_else(|| "Volume N/A".to_string())
}
pub fn pretty_print(&self) {
println!("Market: {}", self.ticker.as_deref().unwrap_or("N/A"));
println!("Liquidity: {}", self.liquidity_dollars());
println!(
"Yes Side Prices - Ask: {}, Bid: {}, Avg: {}",
self.yes_ask.map_or("N/A".to_string(), |v| v.to_string()),
self.yes_bid.map_or("N/A".to_string(), |v| v.to_string()),
self.yes_ask
.zip(self.yes_bid)
.map_or("N/A".to_string(), |(ask, bid)| ((ask + bid) / 2.0)
.to_string())
);
println!(
"No Side Prices - Ask: {}, Bid: {}, Avg: {}",
self.no_ask.map_or("N/A".to_string(), |v| v.to_string()),
self.no_bid.map_or("N/A".to_string(), |v| v.to_string()),
self.no_ask
.zip(self.no_bid)
.map_or("N/A".to_string(), |(ask, bid)| ((ask + bid) / 2.0)
.to_string())
);
println!("-------------------------")
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BalanceResponse {
pub balance: Option<i64>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PortfolioValueResponse {
pub total_value: Option<i64>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CursorResponse {
pub cursor: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Event {
pub category: String,
pub event_ticker: String,
pub mutually_exclusive: bool,
pub series_ticker: String,
pub strike_date: DateTime<Utc>,
pub sub_title: Option<String>,
pub title: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct EventsResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
pub events: Vec<Event>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MarketsResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
pub markets: Vec<Market>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Orderbook {
pub no: Vec<Vec<u32>>,
pub no_dollars: Vec<DollarEntry>,
pub yes: Vec<Vec<u32>>,
pub yes_dollars: Vec<DollarEntry>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DollarEntry {
#[serde(rename = "Count")]
pub count: u32,
#[serde(rename = "Dollars")]
pub dollars: Vec<u32>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OrderbookWrapper {
pub orderbook: Orderbook,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct EventResponse {
pub event: Event,
pub markets: Vec<Market>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Fill {
pub action: String,
pub count: i64,
pub created_time: DateTime<Utc>,
pub is_taker: bool,
pub no_price: i64,
pub order_id: String,
pub side: String,
pub ticker: String,
pub trade_id: String,
pub yes_price: i64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FillsResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
#[serde(skip_serializing_if = "Option::is_none")]
pub fills: Option<Vec<Fill>>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Action {
Buy,
Sell,
}
impl From<String> for Action {
fn from(action: String) -> Self {
match action.as_str() {
"buy" => Action::Buy,
"sell" => Action::Sell,
_ => panic!("Invalid action type for conversion to Action"),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum TimeInForce {
FillOrKill,
ImmediateOrCancel,
GoodTilCanceled,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OrderRequest {
pub action: Action,
#[serde(skip_serializing_if = "Option::is_none")]
pub buy_max_cost: Option<i64>,
pub client_order_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expiration_ts: Option<u128>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_price: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_price_dollars: Option<Vec<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_group_id: Option<String>,
pub post_only: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub self_trade_prevention_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sell_position_capped: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sell_position_floor: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub side: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ticker: Option<String>,
pub time_in_force: String,
#[serde(rename = "type")]
pub order_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub yes_price: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub yes_price_dollars: Option<Vec<i64>>,
}
#[derive(Debug, Deserialize)]
pub struct OrderResponse {
pub order: Order,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Order {
pub action: Option<Action>,
pub client_order_id: Option<String>,
#[serde(rename = "created_time")]
pub created_time: serde_json::Value,
#[serde(rename = "expiration_time")]
pub expiration_time: serde_json::Value,
pub no_price: u32,
pub no_price_dollars: Vec<u32>,
pub order_group_id: String,
pub order_id: String,
pub self_trade_prevention_type: String,
pub side: String,
pub status: String,
pub ticker: String,
#[serde(rename = "type")]
pub order_type: OrderKind,
pub user_id: String,
pub yes_price: u32,
pub yes_price_dollars: Vec<u32>,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum OrderKind {
Limit,
Market,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OrdersResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
pub orders: Vec<Order>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct EventPosition {
pub event_exposure: i64,
pub event_ticker: String,
pub fees_paid: i64,
pub realized_pnl: i64,
pub resting_order_count: i64,
pub total_cost: i64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MarketPosition {
pub fees_paid: i64,
pub position: i64,
pub realized_pnl: i64,
pub resting_orders_count: i64,
pub ticker: String,
pub total_traded: i64,
pub market_exposure: i64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PositionsResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
#[serde(skip_serializing_if = "Option::is_none")]
pub event_positions: Option<Vec<EventPosition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub market_positions: Option<Vec<MarketPosition>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Settlement {
pub market_result: String,
pub no_count: i64,
pub no_total_cost: i64,
pub revenue: i64,
pub settled_time: DateTime<Utc>,
pub ticker: String,
pub yes_count: i64,
pub yes_total_cost: i64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SettlementsResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
pub settlements: Vec<Settlement>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Trade {
pub count: i64,
pub created_time: DateTime<Utc>,
pub no_price: i64,
pub taker_side: String,
pub ticker: String,
pub trade_id: String,
pub yes_price: i64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct TradesResponse {
#[serde(flatten)]
pub cursor: CursorResponse,
pub trades: Vec<Trade>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExchangeStatusResponse {
pub exchange_active: bool,
pub trading_active: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Series {
pub frequency: String,
pub ticker: String,
pub title: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SeriesResponse {
pub series: Series,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum SideKind {
Neutral,
Yes,
No,
}
impl From<String> for SideKind {
fn from(side: String) -> Self {
match side.as_str() {
"Yes" => SideKind::Yes,
"No" => SideKind::No,
_ => SideKind::Neutral,
}
}
}