ig_client/application/models/
market.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 13/5/25
5******************************************************************************/
6use serde::{Deserialize, Serialize};
7use std::fmt::Display;
8
9/// Instrument type
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
11#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
12pub enum InstrumentType {
13    /// Stocks and shares
14    Shares,
15    /// Foreign exchange currency pairs
16    Currencies,
17    /// Market indices
18    Indices,
19    /// Short-term binary bets
20    SprintMarket,
21    /// Raw materials and natural resources
22    Commodities,
23    /// Option contracts
24    Options,
25    /// Binary options
26    #[serde(rename = "BINARY")]
27    Binary,
28    /// Unknown instrument type
29    #[serde(other)]
30    Unknown,
31}
32
33/// Model for a market instrument
34#[derive(Debug, Clone, Deserialize)]
35pub struct Instrument {
36    /// Unique identifier for the instrument
37    pub epic: String,
38    /// Human-readable name of the instrument
39    pub name: String,
40    /// Type of the instrument
41    #[serde(rename = "instrumentType")]
42    pub instrument_type: InstrumentType,
43    /// Expiry date of the instrument
44    pub expiry: String,
45    /// Size of one contract
46    #[serde(rename = "contractSize")]
47    pub contract_size: Option<f64>,
48    /// Size of one lot
49    #[serde(rename = "lotSize")]
50    pub lot_size: Option<f64>,
51    /// Upper price limit for the instrument
52    #[serde(rename = "highLimitPrice")]
53    pub high_limit_price: Option<f64>,
54    /// Lower price limit for the instrument
55    #[serde(rename = "lowLimitPrice")]
56    pub low_limit_price: Option<f64>,
57    /// Margin factor for the instrument
58    #[serde(rename = "marginFactor")]
59    pub margin_factor: Option<f64>,
60    /// Unit for the margin factor
61    #[serde(rename = "marginFactorUnit")]
62    pub margin_factor_unit: Option<String>,
63    /// Factor for price slippage
64    #[serde(rename = "slippageFactor")]
65    pub slippage_factor: Option<f64>,
66    /// Premium for limited risk trades
67    #[serde(rename = "limitedRiskPremium")]
68    pub limited_risk_premium: Option<f64>,
69    /// Code for news related to this instrument
70    #[serde(rename = "newsCode")]
71    pub news_code: Option<String>,
72    /// Code for chart data related to this instrument
73    #[serde(rename = "chartCode")]
74    pub chart_code: Option<String>,
75    /// Available currencies for trading this instrument
76    pub currencies: Option<Vec<Currency>>,
77}
78
79/// Model for an instrument's currency
80#[derive(Debug, Clone, Deserialize)]
81pub struct Currency {
82    /// Currency code (e.g., "USD", "EUR")
83    pub code: String,
84    /// Currency symbol (e.g., "$", "€")
85    pub symbol: Option<String>,
86    /// Base exchange rate for the currency
87    #[serde(rename = "baseExchangeRate")]
88    pub base_exchange_rate: Option<f64>,
89    /// Current exchange rate
90    #[serde(rename = "exchangeRate")]
91    pub exchange_rate: Option<f64>,
92    /// Whether this is the default currency for the instrument
93    #[serde(rename = "isDefault")]
94    pub is_default: Option<bool>,
95}
96
97/// Model for market data
98#[derive(Debug, Clone, Deserialize)]
99pub struct MarketDetails {
100    /// Detailed information about the instrument
101    pub instrument: Instrument,
102    /// Current market snapshot with prices
103    pub snapshot: MarketSnapshot,
104}
105
106/// Trading rules for a market
107#[derive(Debug, Clone, Deserialize)]
108pub struct DealingRules {
109    /// Minimum deal size allowed
110    #[serde(rename = "minDealSize")]
111    pub min_deal_size: Option<f64>,
112    /// Maximum deal size allowed
113    #[serde(rename = "maxDealSize")]
114    pub max_deal_size: Option<f64>,
115    /// Minimum distance for controlled risk stop
116    #[serde(rename = "minControlledRiskStopDistance")]
117    pub min_controlled_risk_stop_distance: Option<f64>,
118    /// Minimum distance for normal stop or limit orders
119    #[serde(rename = "minNormalStopOrLimitDistance")]
120    pub min_normal_stop_or_limit_distance: Option<f64>,
121    /// Maximum distance for stop or limit orders
122    #[serde(rename = "maxStopOrLimitDistance")]
123    pub max_stop_or_limit_distance: Option<f64>,
124    /// Market order preference setting
125    #[serde(rename = "marketOrderPreference")]
126    pub market_order_preference: String,
127    /// Trailing stops preference setting
128    #[serde(rename = "trailingStopsPreference")]
129    pub trailing_stops_preference: String,
130}
131
132/// Market snapshot
133#[derive(Debug, Clone, Deserialize)]
134pub struct MarketSnapshot {
135    /// Current status of the market (e.g., "OPEN", "CLOSED")
136    #[serde(rename = "marketStatus")]
137    pub market_status: String,
138    /// Net change in price since previous close
139    #[serde(rename = "netChange")]
140    pub net_change: Option<f64>,
141    /// Percentage change in price since previous close
142    #[serde(rename = "percentageChange")]
143    pub percentage_change: Option<f64>,
144    /// Time of the last price update
145    #[serde(rename = "updateTime")]
146    pub update_time: Option<String>,
147    /// Delay time in milliseconds for market data
148    #[serde(rename = "delayTime")]
149    pub delay_time: Option<i64>,
150    /// Current bid price
151    pub bid: Option<f64>,
152    /// Current offer/ask price
153    pub offer: Option<f64>,
154    /// Highest price of the current trading session
155    #[serde(rename = "high")]
156    pub high: Option<f64>,
157    /// Lowest price of the current trading session
158    #[serde(rename = "low")]
159    pub low: Option<f64>,
160    /// Odds for binary markets
161    #[serde(rename = "binaryOdds")]
162    pub binary_odds: Option<f64>,
163    /// Factor for decimal places in price display
164    #[serde(rename = "decimalPlacesFactor")]
165    pub decimal_places_factor: Option<i64>,
166    /// Factor for scaling prices
167    #[serde(rename = "scalingFactor")]
168    pub scaling_factor: Option<i64>,
169    /// Extra spread for controlled risk trades
170    #[serde(rename = "controlledRiskExtraSpread")]
171    pub controlled_risk_extra_spread: Option<f64>,
172}
173
174/// Model for market search results
175#[derive(Debug, Clone, Deserialize)]
176pub struct MarketSearchResult {
177    /// List of markets matching the search criteria
178    pub markets: Vec<MarketData>,
179}
180
181/// Basic market data
182#[derive(Debug, Clone, Deserialize, Serialize)]
183pub struct MarketData {
184    /// Unique identifier for the market
185    pub epic: String,
186    /// Human-readable name of the instrument
187    #[serde(rename = "instrumentName")]
188    pub instrument_name: String,
189    /// Type of the instrument
190    #[serde(rename = "instrumentType")]
191    pub instrument_type: InstrumentType,
192    /// Expiry date of the instrument
193    pub expiry: String,
194    /// Upper price limit for the market
195    #[serde(rename = "highLimitPrice")]
196    pub high_limit_price: Option<f64>,
197    /// Lower price limit for the market
198    #[serde(rename = "lowLimitPrice")]
199    pub low_limit_price: Option<f64>,
200    /// Current status of the market
201    #[serde(rename = "marketStatus")]
202    pub market_status: String,
203    /// Net change in price since previous close
204    #[serde(rename = "netChange")]
205    pub net_change: Option<f64>,
206    /// Percentage change in price since previous close
207    #[serde(rename = "percentageChange")]
208    pub percentage_change: Option<f64>,
209    /// Time of the last price update
210    #[serde(rename = "updateTime")]
211    pub update_time: Option<String>,
212    /// Current bid price
213    pub bid: Option<f64>,
214    /// Current offer/ask price
215    pub offer: Option<f64>,
216}
217
218impl Display for MarketData {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        let json = serde_json::to_string(self).unwrap_or_else(|_| "Invalid JSON".to_string());
221        write!(f, "{}", json)
222    }
223}
224
225/// Model for historical prices
226#[derive(Debug, Clone, Deserialize)]
227pub struct HistoricalPricesResponse {
228    /// List of historical price points
229    pub prices: Vec<HistoricalPrice>,
230    /// Type of the instrument
231    #[serde(rename = "instrumentType")]
232    pub instrument_type: InstrumentType,
233    /// API usage allowance information
234    #[serde(rename = "allowance")]
235    pub allowance: PriceAllowance,
236}
237
238/// Historical price data point
239#[derive(Debug, Clone, Deserialize)]
240pub struct HistoricalPrice {
241    /// Timestamp of the price data point
242    #[serde(rename = "snapshotTime")]
243    pub snapshot_time: String,
244    /// Opening price for the period
245    #[serde(rename = "openPrice")]
246    pub open_price: PricePoint,
247    /// Highest price for the period
248    #[serde(rename = "highPrice")]
249    pub high_price: PricePoint,
250    /// Lowest price for the period
251    #[serde(rename = "lowPrice")]
252    pub low_price: PricePoint,
253    /// Closing price for the period
254    #[serde(rename = "closePrice")]
255    pub close_price: PricePoint,
256    /// Volume traded during the period
257    #[serde(rename = "lastTradedVolume")]
258    pub last_traded_volume: Option<i64>,
259}
260
261/// Price point with bid, ask and last traded prices
262#[derive(Debug, Clone, Deserialize)]
263pub struct PricePoint {
264    /// Bid price at this point
265    pub bid: Option<f64>,
266    /// Ask/offer price at this point
267    pub ask: Option<f64>,
268    /// Last traded price at this point
269    #[serde(rename = "lastTraded")]
270    pub last_traded: Option<f64>,
271}
272
273/// Information about API usage allowance for price data
274#[derive(Debug, Clone, Deserialize)]
275pub struct PriceAllowance {
276    /// Remaining API calls allowed in the current period
277    #[serde(rename = "remainingAllowance")]
278    pub remaining_allowance: i64,
279    /// Total API calls allowed per period
280    #[serde(rename = "totalAllowance")]
281    pub total_allowance: i64,
282    /// Time until the allowance resets
283    #[serde(rename = "allowanceExpiry")]
284    pub allowance_expiry: i64,
285}