Skip to main content

oanda_client/models/
instrument.rs

1//! OANDA v20 instrument definitions.
2// Shared imports vary by definition family; unused ones are deliberately allowed.
3#[allow(unused_imports)]
4use super::*;
5#[allow(unused_imports)]
6use crate::ids::*;
7#[allow(unused_imports)]
8use crate::timestamp::Timestamp;
9#[allow(unused_imports)]
10use rust_decimal::Decimal;
11#[allow(unused_imports)]
12use serde::{Deserialize, Serialize};
13
14/// The granularity of a candlestick
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16#[non_exhaustive]
17pub enum CandlestickGranularity {
18    /// 5 second candlesticks, minute alignment
19    S5,
20    /// 10 second candlesticks, minute alignment
21    S10,
22    /// 15 second candlesticks, minute alignment
23    S15,
24    /// 30 second candlesticks, minute alignment
25    S30,
26    /// 1 minute candlesticks, minute alignment
27    M1,
28    /// 2 minute candlesticks, hour alignment
29    M2,
30    /// 4 minute candlesticks, hour alignment
31    M4,
32    /// 5 minute candlesticks, hour alignment
33    M5,
34    /// 10 minute candlesticks, hour alignment
35    M10,
36    /// 15 minute candlesticks, hour alignment
37    M15,
38    /// 30 minute candlesticks, hour alignment
39    M30,
40    /// 1 hour candlesticks, hour alignment
41    H1,
42    /// 2 hour candlesticks, day alignment
43    H2,
44    /// 3 hour candlesticks, day alignment
45    H3,
46    /// 4 hour candlesticks, day alignment
47    H4,
48    /// 6 hour candlesticks, day alignment
49    H6,
50    /// 8 hour candlesticks, day alignment
51    H8,
52    /// 12 hour candlesticks, day alignment
53    H12,
54    /// 1 day candlesticks, day alignment
55    D,
56    /// 1 week candlesticks, aligned to start of week
57    W,
58    /// 1 month candlesticks, aligned to first day of the month
59    M,
60    /// An unrecognized provider value, preserved for forward compatibility.
61    Unknown(String),
62}
63
64impl CandlestickGranularity {
65    /// Return the exact provider spelling.
66    pub fn as_str(&self) -> &str {
67        match self {
68            Self::S5 => "S5",
69            Self::S10 => "S10",
70            Self::S15 => "S15",
71            Self::S30 => "S30",
72            Self::M1 => "M1",
73            Self::M2 => "M2",
74            Self::M4 => "M4",
75            Self::M5 => "M5",
76            Self::M10 => "M10",
77            Self::M15 => "M15",
78            Self::M30 => "M30",
79            Self::H1 => "H1",
80            Self::H2 => "H2",
81            Self::H3 => "H3",
82            Self::H4 => "H4",
83            Self::H6 => "H6",
84            Self::H8 => "H8",
85            Self::H12 => "H12",
86            Self::D => "D",
87            Self::W => "W",
88            Self::M => "M",
89            Self::Unknown(value) => value,
90        }
91    }
92}
93
94impl Serialize for CandlestickGranularity {
95    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
96        serializer.serialize_str(self.as_str())
97    }
98}
99
100impl<'de> Deserialize<'de> for CandlestickGranularity {
101    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
102        let value = String::deserialize(deserializer)?;
103        Ok(match value.as_str() {
104            "S5" => Self::S5,
105            "S10" => Self::S10,
106            "S15" => Self::S15,
107            "S30" => Self::S30,
108            "M1" => Self::M1,
109            "M2" => Self::M2,
110            "M4" => Self::M4,
111            "M5" => Self::M5,
112            "M10" => Self::M10,
113            "M15" => Self::M15,
114            "M30" => Self::M30,
115            "H1" => Self::H1,
116            "H2" => Self::H2,
117            "H3" => Self::H3,
118            "H4" => Self::H4,
119            "H6" => Self::H6,
120            "H8" => Self::H8,
121            "H12" => Self::H12,
122            "D" => Self::D,
123            "W" => Self::W,
124            "M" => Self::M,
125            _ => Self::Unknown(value),
126        })
127    }
128}
129
130/// The day of the week to use for candlestick granularities with weekly alignment.
131#[derive(Debug, Clone, PartialEq, Eq, Hash)]
132#[non_exhaustive]
133pub enum WeeklyAlignment {
134    /// Monday
135    Monday,
136    /// Tuesday
137    Tuesday,
138    /// Wednesday
139    Wednesday,
140    /// Thursday
141    Thursday,
142    /// Friday
143    Friday,
144    /// Saturday
145    Saturday,
146    /// Sunday
147    Sunday,
148    /// An unrecognized provider value, preserved for forward compatibility.
149    Unknown(String),
150}
151
152impl WeeklyAlignment {
153    /// Return the exact provider spelling.
154    pub fn as_str(&self) -> &str {
155        match self {
156            Self::Monday => "Monday",
157            Self::Tuesday => "Tuesday",
158            Self::Wednesday => "Wednesday",
159            Self::Thursday => "Thursday",
160            Self::Friday => "Friday",
161            Self::Saturday => "Saturday",
162            Self::Sunday => "Sunday",
163            Self::Unknown(value) => value,
164        }
165    }
166}
167
168impl Serialize for WeeklyAlignment {
169    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
170        serializer.serialize_str(self.as_str())
171    }
172}
173
174impl<'de> Deserialize<'de> for WeeklyAlignment {
175    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
176        let value = String::deserialize(deserializer)?;
177        Ok(match value.as_str() {
178            "Monday" => Self::Monday,
179            "Tuesday" => Self::Tuesday,
180            "Wednesday" => Self::Wednesday,
181            "Thursday" => Self::Thursday,
182            "Friday" => Self::Friday,
183            "Saturday" => Self::Saturday,
184            "Sunday" => Self::Sunday,
185            _ => Self::Unknown(value),
186        })
187    }
188}
189
190/// The Candlestick representation
191#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
192#[serde(rename_all = "camelCase")]
193pub struct Candlestick {
194    /// The start time of the candlestick
195    #[serde(rename = "time", default, skip_serializing_if = "Option::is_none")]
196    pub time: Option<Timestamp>,
197    /// The candlestick data based on bids. Only provided if bid-based candles were requested.
198    #[serde(rename = "bid", default, skip_serializing_if = "Option::is_none")]
199    pub bid: Option<CandlestickData>,
200    /// The candlestick data based on asks. Only provided if ask-based candles were requested.
201    #[serde(rename = "ask", default, skip_serializing_if = "Option::is_none")]
202    pub ask: Option<CandlestickData>,
203    /// The candlestick data based on midpoints. Only provided if midpoint-based candles were requested.
204    #[serde(rename = "mid", default, skip_serializing_if = "Option::is_none")]
205    pub mid: Option<CandlestickData>,
206    /// The number of prices created during the time-range represented by the candlestick.
207    #[serde(rename = "volume", default, skip_serializing_if = "Option::is_none")]
208    pub volume: Option<i64>,
209    /// A flag indicating if the candlestick is complete. A complete candlestick is one whose ending time is not
210    /// in the future.
211    #[serde(rename = "complete", default, skip_serializing_if = "Option::is_none")]
212    pub complete: Option<bool>,
213}
214
215/// The price data (open, high, low, close) for the Candlestick representation.
216#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
217#[serde(rename_all = "camelCase")]
218pub struct CandlestickData {
219    /// The first (open) price in the time-range represented by the candlestick.
220    #[serde(rename = "o", default, skip_serializing_if = "Option::is_none")]
221    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
222    pub o: Option<Decimal>,
223    /// The highest price in the time-range represented by the candlestick.
224    #[serde(rename = "h", default, skip_serializing_if = "Option::is_none")]
225    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
226    pub h: Option<Decimal>,
227    /// The lowest price in the time-range represented by the candlestick.
228    #[serde(rename = "l", default, skip_serializing_if = "Option::is_none")]
229    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
230    pub l: Option<Decimal>,
231    /// The last (closing) price in the time-range represented by the candlestick.
232    #[serde(rename = "c", default, skip_serializing_if = "Option::is_none")]
233    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
234    pub c: Option<Decimal>,
235}
236
237/// Response containing instrument, granularity, and list of candles.
238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
239#[serde(rename_all = "camelCase")]
240pub struct CandlestickResponse {
241    /// The instrument whose Prices are represented by the candlesticks.
242    #[serde(
243        rename = "instrument",
244        default,
245        skip_serializing_if = "Option::is_none"
246    )]
247    pub instrument: Option<InstrumentName>,
248    /// The granularity of the candlesticks provided.
249    #[serde(
250        rename = "granularity",
251        default,
252        skip_serializing_if = "Option::is_none"
253    )]
254    pub granularity: Option<CandlestickGranularity>,
255    /// The list of candlesticks that satisfy the request.
256    #[serde(rename = "candles", default, skip_serializing_if = "Option::is_none")]
257    pub candles: Option<Vec<Candlestick>>,
258}