diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..99fc5c1
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+DATAMAXI_API_KEY=
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..2ad40f2
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,45 @@
+name: Publish Documentation
+
+on:
+ push:
+ branches: [main]
+
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Setup Rust
+ uses: dtolnay/rust-toolchain@stable
+
+ - name: Configure cache
+ uses: Swatinem/rust-cache@v2
+
+ - name: Setup pages
+ id: pages
+ uses: actions/configure-pages@v4
+
+ - name: Clean docs folder
+ run: cargo clean --doc
+
+ - name: Build docs
+ run: cargo doc --no-deps
+
+ - name: Add redirect
+ run: echo '' > target/doc/index.html
+
+ - name: Remove lock file
+ run: rm target/doc/.lock
+
+ - name: Deploy to GitHub Pages
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./target/doc
+ publish_branch: gh-pages
+ allow_empty_commit: true
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
new file mode 100644
index 0000000..87e3d0a
--- /dev/null
+++ b/.github/workflows/rust.yml
@@ -0,0 +1,38 @@
+name: Rust
+
+on:
+ push:
+ pull_request:
+
+env:
+ CARGO_TERM_COLOR: always
+
+jobs:
+ lint:
+ name: lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions-rs/toolchain@v1
+ with:
+ profile: minimal
+ toolchain: nightly
+ override: true
+ components: clippy
+ - run: cargo clippy --all-targets
+
+ fmt:
+ name: format
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: nightly
+ override: true
+ profile: minimal
+ components: rustfmt
+ - uses: actions-rs/cargo@v1
+ with:
+ command: fmt
+ args: --all -- --check
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5879244
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/target
+src/main.rs
+
+Cargo.lock
+.env
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..10a095a
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "datamaxi"
+version = "0.1.0"
+edition = "2021"
+readme = "README.md"
+license = "MIT"
+
+[dependencies]
+dotenv = "0.15.0"
+api = "0.2.0"
+error-chain = "0.12.4"
+reqwest = { version = "0.12.7", features = ["blocking", "json"] }
+serde = { version = "1.0.209", features = ["derive"] }
+serde_json = "1.0.127"
+tungstenite = "0.24.0"
+url = "2.5.2"
+
+[dev-dependencies]
+mockito = "1.5.0"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5a818ba
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Bisonai
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..79b8936
--- /dev/null
+++ b/README.md
@@ -0,0 +1,120 @@
+## DataMaxi+ Rust SDK
+
+This is the official implementation of Rust SDK for [DataMaxi+](https://datamaxiplus.com/).
+The package can be used to fetch both historical and latest data using [DataMaxi+ API](https://docs.datamaxiplus.com/).
+
+- [Installation](#installation)
+- [Configuration](#configuration)
+- [Links](#links)
+- [Contributing](#contributing)
+- [License](#license)
+
+### Installation
+
+```shell
+[dependencies]
+datamaxi = { git = "https://github.com/bisonai/datamaxi-rust.git" }
+```
+
+### Configuration
+
+Private API endpoints are protected by an API key.
+You can get the API key upon registering at .
+
+
+| Option | Explanation |
+|------------|-------------------------------------------------------------------------------|
+| `api_key` | Your API key |
+| `base_url` | If `base_url` is not provided, it defaults to `https://api.datamaxiplus.com`. |
+
+### Examples
+
+#### CEX Candle
+
+```rust
+let api_key = "my_api_key".to_string();
+let candle: datamaxi::cex::Candle = datamaxi::api::Datamaxi::new(api_key);
+
+// Fetch supported exchanges for CEX candle data
+candle.exchanges("spot");
+
+// Fetch supported symbols for CEX candle data
+let symbols_options = datamaxi::cex::SymbolsOptions::new();
+candle.symbols("binance", symbols_options);
+
+// Fetch supported intervals for CEX candle data
+candle.intervals();
+
+// Fetch CEX candle data
+let candle_options = datamaxi::cex::CandleOptions::new();
+candle.get("binance", "ETH-USDT", candle_options);
+```
+
+#### DEX Candle
+
+```rust
+let api_key = "my_api_key".to_string();
+let candle: datamaxi::dex::Candle = datamaxi::api::Datamaxi::new(api_key);
+
+// Fetch supported intervals for DEX candle data
+candle.intervals();
+
+// Fetch supported exchange for DEX candle data
+candle.exchanges();
+
+// Fetch supported chains for DEX candle data
+candle.chains();
+
+// Fetch supported pools for DEX candle data
+let pools_options = datamaxi::dex::PoolsOptions::new();
+candle.pools(pools_options);
+
+// Fetch DEX candle data
+let params = datamaxi::dex::CandleOptions::new();
+candle.get(
+ "bsc_mainnet",
+ "pancakeswap",
+ "0xb24cd29e32FaCDDf9e73831d5cD1FFcd1e535423",
+ params,
+);
+```
+
+#### DEX Trade
+
+```rust
+let api_key = "my_api_key".to_string();
+let trade: datamaxi::dex::Trade = datamaxi::api::Datamaxi::new(api_key);
+
+// Fetch supported exchange for DEX trade data
+trade.exchanges();
+
+// Fetch supported chains for DEX trade data
+trade.chains();
+
+// Fetch supported pools for DEX trade data
+let pools_options = datamaxi::dex::PoolsOptions::new();
+trade.pools(pools_options);
+
+// Fetch DEX candle data
+let trade_options = datamaxi::dex::TradeOptions::new().limit(5);
+trade.get(
+ "bsc_mainnet",
+ "pancakeswap",
+ "0xb24cd29e32FaCDDf9e73831d5cD1FFcd1e535423",
+ trade_options
+);
+```
+
+### Links
+
+- [Official Website](https://datamaxiplus.com/)
+- [Documentation](https://docs.datamaxiplus.com/)
+
+### Contributing
+
+We welcome contributions!
+If you discover a bug in this project, please feel free to open an issue to discuss the changes you would like to propose.
+
+### License
+
+[MIT License](./LICENSE)
diff --git a/README.tpl b/README.tpl
new file mode 100644
index 0000000..274bb44
--- /dev/null
+++ b/README.tpl
@@ -0,0 +1 @@
+{{readme}}
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..fee0038
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,22 @@
+# DataMaxi+ Examples
+
+All examples load `DATAMAXI_API_KEY` environment variable to authenticate with the DataMaxi+ API.
+Setup your environment variable with your API key in `.env` file before running the examples.
+
+## CEX Candle
+
+```bash
+cargo run --release -q --example "cex-candle"
+```
+
+## DEX Trade
+
+```bash
+cargo run --release -q --example "dex-trade"
+```
+
+## DEX Candle
+
+```bash
+cargo run --release -q --example "dex-candle"
+```
diff --git a/examples/cex-candle.rs b/examples/cex-candle.rs
new file mode 100644
index 0000000..02a1d8d
--- /dev/null
+++ b/examples/cex-candle.rs
@@ -0,0 +1,41 @@
+use std::env;
+
+fn main() {
+ dotenv::dotenv().ok();
+ let api_key = env::var("DATAMAXI_API_KEY").expect("DATAMAXI_API_KEY not found");
+ let candle: datamaxi::cex::Candle = datamaxi::api::Datamaxi::new(api_key);
+
+ // CEX Candle Exchanges
+ match candle.exchanges("futures") {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // CEX Candle Symbols
+ let symbols_options = datamaxi::cex::SymbolsOptions::new();
+ let symbols_response = candle.symbols("binance", symbols_options);
+ match symbols_response {
+ Ok(answer) => match serde_json::to_string(&answer) {
+ Ok(json) => println!("{}", json),
+ Err(e) => println!("Error: {}", e),
+ },
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // CEX Candle Intervals
+ match candle.intervals() {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // CEX Candle Data
+ let candle_options = datamaxi::cex::CandleOptions::new();
+ let candle_response = candle.get("binance", "ETH-USDT", candle_options);
+ match candle_response {
+ Ok(answer) => match serde_json::to_string(&answer) {
+ Ok(json) => println!("{}", json),
+ Err(e) => println!("Error: {}", e),
+ },
+ Err(e) => println!("Error: {}", e),
+ }
+}
diff --git a/examples/dex-candle.rs b/examples/dex-candle.rs
new file mode 100644
index 0000000..718d7b0
--- /dev/null
+++ b/examples/dex-candle.rs
@@ -0,0 +1,52 @@
+use std::env;
+
+fn main() {
+ dotenv::dotenv().ok();
+ let api_key = env::var("DATAMAXI_API_KEY").expect("DATAMAXI_API_KEY not found");
+ let candle: datamaxi::dex::Candle = datamaxi::api::Datamaxi::new(api_key);
+
+ // DEX Candle Intervals
+ match candle.intervals() {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Candle Exchanges
+ match candle.exchanges() {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Candle Chains
+ match candle.chains() {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Candle Pools
+ let pools_options = datamaxi::dex::PoolsOptions::new();
+ let pools_response = candle.pools(pools_options);
+ match pools_response {
+ Ok(answer) => match serde_json::to_string(&answer) {
+ Ok(json) => println!("{}", json),
+ Err(e) => println!("Error: {}", e),
+ },
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Candle Data
+ let params = datamaxi::dex::CandleOptions::new();
+ let candle_response = candle.get(
+ "bsc_mainnet",
+ "pancakeswap",
+ "0xb24cd29e32FaCDDf9e73831d5cD1FFcd1e535423",
+ params,
+ );
+ match candle_response {
+ Ok(answer) => match serde_json::to_string(&answer) {
+ Ok(json) => println!("{}", json),
+ Err(e) => println!("Error: {}", e),
+ },
+ Err(e) => println!("Error: {}", e),
+ }
+}
diff --git a/examples/dex-trade.rs b/examples/dex-trade.rs
new file mode 100644
index 0000000..fa0a58c
--- /dev/null
+++ b/examples/dex-trade.rs
@@ -0,0 +1,46 @@
+use std::env;
+
+fn main() {
+ dotenv::dotenv().ok();
+ let api_key = env::var("DATAMAXI_API_KEY").expect("DATAMAXI_API_KEY not found");
+ let trade: datamaxi::dex::Trade = datamaxi::api::Datamaxi::new(api_key);
+
+ // DEX Trade Exchanges
+ match trade.exchanges() {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Trade Chains
+ match trade.chains() {
+ Ok(answer) => println!("{:?}", answer),
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Trade Pools
+ let pools_options = datamaxi::dex::PoolsOptions::new();
+ let pools_response = trade.pools(pools_options);
+ match pools_response {
+ Ok(answer) => match serde_json::to_string(&answer) {
+ Ok(json) => println!("{}", json),
+ Err(e) => println!("Error: {}", e),
+ },
+ Err(e) => println!("Error: {}", e),
+ }
+
+ // DEX Trade Data
+ let trade_options = datamaxi::dex::TradeOptions::new().limit(5);
+ let trade_response = trade.get(
+ "bsc_mainnet",
+ "pancakeswap",
+ "0xb24cd29e32FaCDDf9e73831d5cD1FFcd1e535423",
+ trade_options,
+ );
+ match trade_response {
+ Ok(answer) => match serde_json::to_string(&answer) {
+ Ok(json) => println!("{}", json),
+ Err(e) => println!("Error: {}", e),
+ },
+ Err(e) => println!("Error: {}", e),
+ }
+}
diff --git a/src/api.rs b/src/api.rs
new file mode 100644
index 0000000..4d203c3
--- /dev/null
+++ b/src/api.rs
@@ -0,0 +1,140 @@
+use error_chain::error_chain;
+use reqwest::blocking::Response;
+use reqwest::StatusCode;
+use serde::de::DeserializeOwned;
+use std::collections::HashMap;
+use std::io::Read;
+
+const BASE_URL: &str = "https://api.datamaxiplus.com/api/v1";
+
+/// A trait that defines the required methods for interacting with the Datamaxi+ API.
+pub trait Datamaxi {
+ /// Creates a new instance of the implementing type using the provided API key.
+ fn new(api_key: String) -> Self;
+
+ /// Creates a new instance of the implementing type using the provided API key and base URL.
+ fn new_with_base_url(api_key: String, base_url: String) -> Self;
+}
+
+/// The configuration for the Datamaxi+ API client.
+pub struct Config {
+ /// The base URL for the API.
+ pub base_url: Option,
+
+ /// The API key used for authentication.
+ pub api_key: String,
+}
+
+/// The client for interacting with the Datamaxi+ API.
+#[derive(Clone)]
+pub struct Client {
+ base_url: String,
+ api_key: String,
+ inner_client: reqwest::blocking::Client,
+}
+
+impl Client {
+ /// Creates a new instance of the `Client` struct with the provided configuration.
+ pub fn new(config: Config) -> Self {
+ Client {
+ base_url: config.base_url.unwrap_or(BASE_URL.to_string()),
+ api_key: config.api_key,
+ inner_client: reqwest::blocking::Client::builder()
+ .pool_idle_timeout(None)
+ .build()
+ .unwrap(),
+ }
+ }
+
+ /// Builds a request string from a set of parameters.
+ fn build_request(parameters: HashMap) -> String {
+ parameters
+ .iter()
+ .map(|(key, value)| format!("{}={}", key, value))
+ .collect::>()
+ .join("&")
+ }
+
+ /// Sends a GET request to the specified endpoint with optional parameters.
+ pub fn get(
+ &self,
+ endpoint: &'static str,
+ parameters: Option>,
+ ) -> Result {
+ let mut url: String = format!("{}{}", self.base_url, endpoint);
+
+ if let Some(p) = parameters {
+ let request = Self::build_request(p);
+
+ if !request.is_empty() {
+ url.push_str(format!("?{}", request).as_str());
+ }
+ }
+
+ let client = &self.inner_client;
+ let response = client
+ .get(url.as_str())
+ .header("X-DTMX-APIKEY", &self.api_key)
+ .send()?;
+
+ self.handle_response(response)
+ }
+
+ /// Processes the response from the API and returns the result.
+ fn handle_response(&self, response: Response) -> Result {
+ match response.status() {
+ StatusCode::OK => Ok(response.json::()?),
+ StatusCode::INTERNAL_SERVER_ERROR => {
+ let mut response_text = String::new();
+ response.take(1000).read_to_string(&mut response_text)?;
+ Err(ErrorKind::InternalServerError(response_text).into())
+ }
+ StatusCode::UNAUTHORIZED => Err(ErrorKind::Unauthorized.into()),
+ StatusCode::BAD_REQUEST => {
+ let mut response_text = String::new();
+ response.take(1000).read_to_string(&mut response_text)?;
+ Err(ErrorKind::BadRequest(response_text).into())
+ }
+ status => Err(ErrorKind::UnexpectedStatusCode(status.as_u16()).into()),
+ }
+ }
+}
+
+error_chain! {
+ errors {
+ /// Represents an error that occurs when a request to the API returns a bad request status.
+ BadRequest(msg: String) {
+ description("Bad request")
+ display("Bad request: {}", msg)
+ }
+
+ /// Represents an error that occurs when a request to the API returns an unauthorized status.
+ Unauthorized {
+ description("Unauthorized")
+ display("Unauthorized")
+ }
+
+ /// Represents an error that occurs when a request to the API returns an internal server error status.
+ InternalServerError(msg: String) {
+ description("Internal server error")
+ display("Internal server error: {}", msg)
+ }
+
+ /// Represents an error that occurs when a request to the API returns an unexpected status code.
+ UnexpectedStatusCode(status: u16) {
+ description("Unexpected status code")
+ display("Received unexpected status code: {}", status)
+ }
+ }
+
+ foreign_links {
+ ReqError(reqwest::Error);
+ InvalidHeaderError(reqwest::header::InvalidHeaderValue);
+ IoError(std::io::Error);
+ ParseFloatError(std::num::ParseFloatError);
+ UrlParserError(url::ParseError);
+ Json(serde_json::Error);
+ Tungstenite(tungstenite::Error);
+ TimestampError(std::time::SystemTimeError);
+ }
+}
diff --git a/src/cex.rs b/src/cex.rs
new file mode 100644
index 0000000..81d1254
--- /dev/null
+++ b/src/cex.rs
@@ -0,0 +1,150 @@
+use crate::api::{Client, Config, Datamaxi, Result};
+pub use crate::models::{CandleOptions, SymbolsOptions};
+use crate::models::{CandleResponse, SymbolsResponse};
+use std::collections::HashMap;
+
+/// Provides methods for retrieving CEX candle data and related information.
+#[derive(Clone)]
+pub struct Candle {
+ pub client: Client,
+}
+
+impl Candle {
+ /// Retrieves candle data for a specified exchange and symbol. Additional parameters can be
+ /// provided to filter and sort the results. The response will contain an array of candle data
+ /// objects, each representing a single candle with open, high, low, close, and volume values.
+ pub fn get(
+ &self,
+ exchange: E,
+ symbol: S,
+ options: CandleOptions,
+ ) -> Result
+ where
+ E: Into,
+ S: Into,
+ {
+ let mut parameters = HashMap::new();
+
+ // required
+ parameters.insert("exchange".to_string(), exchange.into());
+ parameters.insert("symbol".to_string(), symbol.into());
+
+ // optional
+ parameters.extend(
+ [
+ options
+ .market
+ .map(|market| ("market".to_string(), market.to_string())),
+ options
+ .interval
+ .map(|interval| ("interval".to_string(), interval.to_string())),
+ options
+ .page
+ .map(|page| ("page".to_string(), page.to_string())),
+ options
+ .limit
+ .map(|limit| ("limit".to_string(), limit.to_string())),
+ options
+ .from
+ .map(|from| ("from".to_string(), from.to_string())),
+ options.to.map(|to| ("to".to_string(), to.to_string())),
+ options
+ .sort
+ .map(|sort| ("sort".to_string(), sort.to_string())),
+ ]
+ .into_iter()
+ .flatten(),
+ );
+
+ self.client.get("/cex/candle", Some(parameters))
+ }
+
+ /// Retrieves a list of supported exchanges for candle data. The market parameter can be used
+ /// to filter the results by market.
+ pub fn exchanges(&self, market: M) -> Result>
+ where
+ M: Into,
+ {
+ let mut parameters = HashMap::new();
+
+ // required
+ parameters.insert("market".to_string(), market.into());
+
+ self.client.get("/cex/candle/exchanges", Some(parameters))
+ }
+
+ /// Retrieves a list of supported symbols for candle data. The exchange parameter is required,
+ /// and the market parameter can be used to filter the results by market.
+ pub fn symbols(&self, exchange: E, options: SymbolsOptions) -> Result>
+ where
+ E: Into,
+ {
+ let mut parameters = HashMap::new();
+
+ // required
+ parameters.insert("exchange".to_string(), exchange.into());
+
+ // optional
+ if let Some(market) = options.market {
+ parameters.insert("market".to_string(), market);
+ }
+
+ self.client.get("/cex/candle/symbols", Some(parameters))
+ }
+
+ /// Retrieves a list of supported candle intervals.
+ pub fn intervals(&self) -> Result> {
+ self.client.get("/cex/candle/intervals", None)
+ }
+}
+
+/// Implements the `Datamaxi` trait for `Candle`, providing methods
+/// to create new instances of `Candle` with or without a custom base URL.
+impl Datamaxi for Candle {
+ /// Creates a new `Candle` instance with the default base URL.
+ ///
+ /// # Parameters
+ /// - `api_key`: A `String` representing the API key used for authentication in API requests.
+ ///
+ /// # Returns
+ /// A new `Candle` instance configured with the default base URL and the provided `api_key`.
+ ///
+ /// # Example
+ /// ```rust
+ /// use crate::datamaxi::api::Datamaxi;
+ /// let candle = datamaxi::dex::Candle::new("my_api_key".to_string());
+ /// ```
+ fn new(api_key: String) -> Candle {
+ let config = Config {
+ base_url: None, // Default base URL will be used
+ api_key, // Provided API key
+ };
+ Candle {
+ client: Client::new(config), // Create a new client with the given config
+ }
+ }
+
+ /// Creates a new `Candle` instance with a custom base URL.
+ ///
+ /// # Parameters
+ /// - `api_key`: A `String` representing the API key used for authentication in API requests.
+ /// - `base_url`: A `String` representing the custom base URL for API requests.
+ ///
+ /// # Returns
+ /// A new `Candle` instance configured with the specified `base_url` and `api_key`.
+ ///
+ /// # Example
+ /// ```rust
+ /// use crate::datamaxi::api::Datamaxi;
+ /// let candle = datamaxi::dex::Candle::new_with_base_url("my_api_key".to_string(), "https://custom-api.example.com".to_string());
+ /// ```
+ fn new_with_base_url(api_key: String, base_url: String) -> Candle {
+ let config = Config {
+ base_url: Some(base_url), // Use the provided custom base URL
+ api_key, // Provided API key
+ };
+ Candle {
+ client: Client::new(config), // Create a new client with the given config
+ }
+ }
+}
diff --git a/src/dex.rs b/src/dex.rs
new file mode 100644
index 0000000..240c1cc
--- /dev/null
+++ b/src/dex.rs
@@ -0,0 +1,291 @@
+use crate::api::{Client, Config, Datamaxi, Result};
+pub use crate::models::{CandleOptions, PoolsOptions, TradeOptions};
+use crate::models::{CandleResponse, PoolsResponse, TradeResponse};
+use std::collections::HashMap;
+
+/// Provides methods for retrieving DEX candle data and related information.
+#[derive(Clone)]
+pub struct Candle {
+ pub client: Client,
+}
+
+impl Candle {
+ /// Retrieves candle data for a specified chain, exchange, and pool. Additional parameters can be
+ /// provided to filter and sort the results. The response will contain an array of candle data
+ /// objects, each representing a single candle with open, high, low, close, and volume values.
+ pub fn get(
+ &self,
+ chain: C,
+ exchange: E,
+ pool: P,
+ options: CandleOptions,
+ ) -> Result
+ where
+ C: Into,
+ E: Into,
+ P: Into,
+ {
+ let mut parameters = HashMap::new();
+
+ // required
+ parameters.insert("chain".to_string(), chain.into());
+ parameters.insert("exchange".to_string(), exchange.into());
+ parameters.insert("pool".to_string(), pool.into());
+
+ // optional
+ parameters.extend(
+ [
+ options
+ .market
+ .map(|market| ("market".to_string(), market.to_string())),
+ options
+ .interval
+ .map(|interval| ("interval".to_string(), interval.to_string())),
+ options
+ .page
+ .map(|page| ("page".to_string(), page.to_string())),
+ options
+ .limit
+ .map(|limit| ("limit".to_string(), limit.to_string())),
+ options
+ .from
+ .map(|from| ("from".to_string(), from.to_string())),
+ options.to.map(|to| ("to".to_string(), to.to_string())),
+ options
+ .sort
+ .map(|sort| ("sort".to_string(), sort.to_string())),
+ ]
+ .into_iter()
+ .flatten(),
+ );
+
+ self.client.get("/dex/candle", Some(parameters))
+ }
+
+ /// Retrieves information about available pools, including details about the chain, exchange,
+ /// base and quote symbols, and pool address. Optional parameters can be provided to filter the
+ /// results by chain and exchange.
+ pub fn pools(&self, options: PoolsOptions) -> Result> {
+ let mut parameters = HashMap::new();
+
+ // optional
+ parameters.extend(
+ [
+ options
+ .exchange
+ .map(|exchange| ("exchange".to_string(), exchange.to_string())),
+ options
+ .chain
+ .map(|chain| ("chain".to_string(), chain.to_string())),
+ ]
+ .into_iter()
+ .flatten(),
+ );
+
+ self.client.get("/dex/candle/pools", Some(parameters))
+ }
+
+ /// Retrieves a list of available chains for candle data.
+ pub fn chains(&self) -> Result> {
+ self.client.get("/dex/candle/chains", None)
+ }
+
+ /// Retrieves a list of available exchanges for candle data.
+ pub fn exchanges(&self) -> Result> {
+ self.client.get("/dex/candle/exchanges", None)
+ }
+
+ /// Retrieves a list of available intervals for candle data.
+ pub fn intervals(&self) -> Result> {
+ self.client.get("/dex/candle/intervals", None)
+ }
+}
+
+/// Implements the `Datamaxi` trait for `Candle`, providing methods
+/// to create new instances of `Candle` with or without a custom base URL.
+impl Datamaxi for Candle {
+ /// Creates a new `Candle` instance with the default base URL.
+ ///
+ /// # Parameters
+ /// - `api_key`: A `String` representing the API key used to authenticate requests.
+ ///
+ /// # Returns
+ /// A new `Candle` instance configured with the default base URL and the provided `api_key`.
+ ///
+ /// # Example
+ /// ```rust
+ /// use crate::datamaxi::api::Datamaxi;
+ /// let candle = datamaxi::dex::Candle::new("my_api_key".to_string());
+ /// ```
+ fn new(api_key: String) -> Candle {
+ let config = Config {
+ base_url: None, // Default base URL will be used
+ api_key, // Provided API key
+ };
+ Candle {
+ client: Client::new(config), // Create a new client with the provided config
+ }
+ }
+
+ /// Creates a new `Candle` instance with a custom base URL.
+ ///
+ /// # Parameters
+ /// - `api_key`: A `String` representing the API key used to authenticate requests.
+ /// - `base_url`: A `String` representing the custom base URL for API requests.
+ ///
+ /// # Returns
+ /// A new `Candle` instance configured with the provided `base_url` and `api_key`.
+ ///
+ /// # Example
+ /// ```rust
+ /// use crate::datamaxi::api::Datamaxi;
+ /// let candle = datamaxi::dex::Candle::new_with_base_url("my_api_key".to_string(), "https://custom-api.example.com".to_string());
+ /// ```
+ fn new_with_base_url(api_key: String, base_url: String) -> Candle {
+ let config = Config {
+ base_url: Some(base_url), // Use the provided custom base URL
+ api_key, // Provided API key
+ };
+ Candle {
+ client: Client::new(config), // Create a new client with the provided config
+ }
+ }
+}
+
+/// Provides methods for retrieving DEX trade data and related information.
+#[derive(Clone)]
+pub struct Trade {
+ pub client: Client,
+}
+
+impl Trade {
+ /// Retrieves trade data for a specified chain, exchange, and pool. Additional parameters can be
+ /// provided to filter and sort the results. The response will contain an array of trade data
+ /// objects, each representing a single trade with price, amount, and timestamp values.
+ pub fn get(
+ &self,
+ chain: C,
+ exchange: E,
+ pool: P,
+ options: TradeOptions,
+ ) -> Result
+ where
+ C: Into,
+ E: Into,
+ P: Into,
+ {
+ let mut parameters = HashMap::new();
+
+ // required
+ parameters.insert("chain".to_string(), chain.into());
+ parameters.insert("exchange".to_string(), exchange.into());
+ parameters.insert("pool".to_string(), pool.into());
+
+ // optional
+ parameters.extend(
+ [
+ options
+ .page
+ .map(|page| ("page".to_string(), page.to_string())),
+ options
+ .limit
+ .map(|limit| ("limit".to_string(), limit.to_string())),
+ options
+ .from
+ .map(|from| ("from".to_string(), from.to_string())),
+ options.to.map(|to| ("to".to_string(), to.to_string())),
+ options
+ .sort
+ .map(|sort| ("sort".to_string(), sort.to_string())),
+ ]
+ .into_iter()
+ .flatten(),
+ );
+
+ self.client.get("/dex/trade", Some(parameters))
+ }
+
+ /// Retrieves information about available pools, including details about the chain, exchange,
+ /// base and quote symbols, and pool address. Optional parameters can be provided to filter the
+ /// results by chain and exchange.
+ pub fn pools(&self, options: PoolsOptions) -> Result> {
+ let mut parameters = HashMap::new();
+
+ // optional
+ parameters.extend(
+ [
+ options
+ .chain
+ .map(|chain| ("chain".to_string(), chain.to_string())),
+ options
+ .exchange
+ .map(|exchange| ("exchange".to_string(), exchange.to_string())),
+ ]
+ .into_iter()
+ .flatten(),
+ );
+
+ self.client.get("/dex/trade/pools", Some(parameters))
+ }
+
+ /// Retrieves a list of available intervals for trade data.
+ pub fn chains(&self) -> Result> {
+ self.client.get("/dex/trade/chains", None)
+ }
+
+ /// Retrieves a list of available exchanges for trade data.
+ pub fn exchanges(&self) -> Result> {
+ self.client.get("/dex/trade/exchanges", None)
+ }
+}
+
+/// Implements the `Datamaxi` trait for `Trade`, providing methods
+/// to create new instances of `Trade` with or without a custom base URL.
+impl Datamaxi for Trade {
+ /// Creates a new `Trade` instance with the default base URL.
+ ///
+ /// # Parameters
+ /// - `api_key`: A `String` containing the API key to authenticate requests.
+ ///
+ /// # Returns
+ /// A new `Trade` instance configured with the default base URL and the provided `api_key`.
+ ///
+ /// # Example
+ /// ```rust
+ /// use crate::datamaxi::api::Datamaxi;
+ /// let trade = datamaxi::dex::Trade::new("my_api_key".to_string());
+ /// ```
+ fn new(api_key: String) -> Trade {
+ let config = Config {
+ base_url: None, // Use the default base URL
+ api_key, // Provided API key
+ };
+ Trade {
+ client: Client::new(config), // Create a new client with the given config
+ }
+ }
+
+ /// Creates a new `Trade` instance with a custom base URL.
+ ///
+ /// # Parameters
+ /// - `api_key`: A `String` containing the API key to authenticate requests.
+ /// - `base_url`: A `String` specifying the custom base URL for API requests.
+ ///
+ /// # Returns
+ /// A new `Trade` instance configured with the provided `base_url` and `api_key`.
+ ///
+ /// # Example
+ /// ```rust
+ /// use crate::datamaxi::api::Datamaxi;
+ /// let trade = datamaxi::dex::Trade::new_with_base_url("my_api_key".to_string(), "https://custom-api.example.com".to_string());
+ /// ```
+ fn new_with_base_url(api_key: String, base_url: String) -> Trade {
+ let config = Config {
+ base_url: Some(base_url), // Use the provided custom base URL
+ api_key, // Provided API key
+ };
+ Trade {
+ client: Client::new(config), // Create a new client with the given config
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..e5ae484
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,205 @@
+//! # DataMaxi+ Rust SDK
+//!
+//! This is the official implementation of Rust SDK for [DataMaxi+](https://datamaxiplus.com/).
+//! The package can be used to fetch both historical and latest data using [DataMaxi+ API](https://docs.datamaxiplus.com/).
+//!
+//! - [Installation](#installation)
+//! - [Configuration](#configuration)
+//! - [Links](#links)
+//! - [Contributing](#contributing)
+//! - [License](#license)
+//!
+//! ## Installation
+//!
+//! ```shell
+//! [dependencies]
+//! datamaxi = { git = "https://github.com/bisonai/datamaxi-rust.git" }
+//! ```
+//!
+//! ## Configuration
+//!
+//! Private API endpoints are protected by an API key.
+//! You can get the API key upon registering at .
+//!
+//!
+//!| Option | Explanation |
+//!|------------|-------------------------------------------------------------------------------|
+//!| `api_key` | Your API key |
+//!| `base_url` | If `base_url` is not provided, it defaults to `https://api.datamaxiplus.com`. |
+//!
+//! ## Examples
+//!
+//! ### CEX Candle
+//!
+//! ```rust
+//! let api_key = "my_api_key".to_string();
+//! let candle: datamaxi::cex::Candle = datamaxi::api::Datamaxi::new(api_key);
+//!
+//! // Fetch supported exchanges for CEX candle data
+//! candle.exchanges("spot");
+//!
+//! // Fetch supported symbols for CEX candle data
+//! let symbols_options = datamaxi::cex::SymbolsOptions::new();
+//! candle.symbols("binance", symbols_options);
+//!
+//! // Fetch supported intervals for CEX candle data
+//! candle.intervals();
+//!
+//! // Fetch CEX candle data
+//! let candle_options = datamaxi::cex::CandleOptions::new();
+//! candle.get("binance", "ETH-USDT", candle_options);
+//! ```
+//!
+//! ### DEX Candle
+//!
+//! ```rust
+//! let api_key = "my_api_key".to_string();
+//! let candle: datamaxi::dex::Candle = datamaxi::api::Datamaxi::new(api_key);
+//!
+//! // Fetch supported intervals for DEX candle data
+//! candle.intervals();
+//!
+//! // Fetch supported exchange for DEX candle data
+//! candle.exchanges();
+//!
+//! // Fetch supported chains for DEX candle data
+//! candle.chains();
+//!
+//! // Fetch supported pools for DEX candle data
+//! let pools_options = datamaxi::dex::PoolsOptions::new();
+//! candle.pools(pools_options);
+//!
+//! // Fetch DEX candle data
+//! let params = datamaxi::dex::CandleOptions::new();
+//! candle.get(
+//! "bsc_mainnet",
+//! "pancakeswap",
+//! "0xb24cd29e32FaCDDf9e73831d5cD1FFcd1e535423",
+//! params,
+//! );
+//! ```
+//!
+//! ### DEX Trade
+//!
+//! ```rust
+//! let api_key = "my_api_key".to_string();
+//! let trade: datamaxi::dex::Trade = datamaxi::api::Datamaxi::new(api_key);
+//!
+//! // Fetch supported exchange for DEX trade data
+//! trade.exchanges();
+//!
+//! // Fetch supported chains for DEX trade data
+//! trade.chains();
+//!
+//! // Fetch supported pools for DEX trade data
+//! let pools_options = datamaxi::dex::PoolsOptions::new();
+//! trade.pools(pools_options);
+//!
+//! // Fetch DEX candle data
+//! let trade_options = datamaxi::dex::TradeOptions::new().limit(5);
+//! trade.get(
+//! "bsc_mainnet",
+//! "pancakeswap",
+//! "0xb24cd29e32FaCDDf9e73831d5cD1FFcd1e535423",
+//! trade_options
+//! );
+//! ```
+//!
+//! ## Links
+//!
+//! - [Official Website](https://datamaxiplus.com/)
+//! - [Documentation](https://docs.datamaxiplus.com/)
+//!
+//! ## Contributing
+//!
+//! We welcome contributions!
+//! If you discover a bug in this project, please feel free to open an issue to discuss the changes you would like to propose.
+//!
+//! ## License
+//!
+//![MIT License](./LICENSE)
+
+/// API definitions and related utilities.
+pub mod api;
+
+/// CEX-related data fetcher and data structures.
+///
+/// This module provides functionality related to centralized exchange (CEX) data.
+/// It includes data structures and methods for retrieving candle data, as well as information about supported exchanges, symbols and intervals.
+///
+/// # Usage
+///
+/// The `Candle` struct is the primary interface for interacting with the CEX data.
+/// It provides methods for retrieving data with optional parameters to filter and sort the results.
+///
+/// ## Example
+///
+/// ```rust
+/// let config = datamaxi::api::Config {
+/// base_url: None,
+/// api_key: "my_api_key".to_string(),
+/// };
+/// let client = datamaxi::api::Client::new(config);
+/// let candle = datamaxi::cex::Candle { client: client.clone() };
+///
+/// // Retrieve supported exchanges
+/// let exchanges = candle.exchanges("spot");
+///
+/// // Retrieve supported intervals
+/// let intervals = candle.intervals();
+///
+/// // Retrieve supported Binance symbols
+/// let symbols_options = datamaxi::cex::SymbolsOptions::new();
+/// let symbols = candle.symbols("binance", symbols_options);
+///
+/// // Retrieve candle data
+/// let candle_options = datamaxi::cex::CandleOptions::new().interval("1h").market("spot");
+/// let candle_data = candle.get("binance", "BTC-USDT", candle_options);
+/// ```
+///
+/// # Error Handling
+///
+/// All methods return a `Result` type, which should be handled appropriately to manage potential errors.
+pub mod cex;
+
+/// DEX-related data fetcher and data structures.
+///
+/// This module provides functionality related to decentralized exchange (DEX) data,
+/// It includes data structures and methods for retrieving candle and trade data, as well as information supported chains, exchanges, pools and intervals.
+///
+/// # Usage
+///
+/// The `Candle` and `Trade` structs are the primary interfaces for interacting with the DEX data.
+/// They provide methods for retrieving data with optional parameters to filter and sort the results.
+///
+/// ## Example
+///
+/// ```rust
+/// let config = datamaxi::api::Config {
+/// base_url: None,
+/// api_key: "my_api_key".to_string(),
+/// };
+/// let client = datamaxi::api::Client::new(config);
+/// let candle = datamaxi::dex::Candle { client: client.clone() };
+/// let trade = datamaxi::dex::Trade { client };
+///
+/// // Retrieve candle data
+/// let candle_options = datamaxi::dex::CandleOptions::new().interval("1h").limit(100);
+/// let candle_data = candle.get("kaia_mainnet", "dragonswap", "0x...", candle_options);
+///
+/// // Retrieve trade data
+/// let trade_options = datamaxi::dex::TradeOptions::new().limit(50);
+/// let trade_data = trade.get("kaia_mainnet", "dragonswap", "0x...", trade_options);
+///
+/// // Retrieve available pools
+/// let pools_options = datamaxi::dex::PoolsOptions::new().chain("kaia_mainnet");
+/// let pools = candle.pools(pools_options);
+/// ```
+///
+/// # Error Handling
+///
+/// All methods return a `Result` type, which should be handled appropriately to manage potential errors.
+pub mod dex;
+
+/// Data models representing API responses and optional parameters.
+pub mod models;
diff --git a/src/models.rs b/src/models.rs
new file mode 100644
index 0000000..a23193a
--- /dev/null
+++ b/src/models.rs
@@ -0,0 +1,401 @@
+use serde::Deserialize;
+use serde::Serialize;
+
+/// Detailed information about a candle.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct CandleDetail {
+ /// The timestamp of the candle's open time.
+ #[serde(rename = "d")]
+ pub timestamp: String,
+
+ /// The opening price of the asset at the beginning of the time frame.
+ #[serde(rename = "o")]
+ pub open: String,
+
+ /// The highest price of the asset during the time frame.
+ #[serde(rename = "h")]
+ pub high: String,
+
+ /// The lowest price of the asset during the time frame.
+ #[serde(rename = "l")]
+ pub low: String,
+
+ /// The closing price of the asset at the end of the time frame.
+ #[serde(rename = "c")]
+ pub close: String,
+
+ /// The total volume of trades (in the base currency) that occurred during the time frame.
+ #[serde(rename = "v")]
+ pub volume: String,
+}
+
+/// Response containing candle data.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct CandleResponse {
+ /// A vector containing detailed information about each candle.
+ pub data: Vec,
+
+ /// The current page number in the paginated response.
+ pub page: i32,
+
+ /// The maximum number of items per page in the response.
+ pub limit: i32,
+
+ /// The starting point of the time frame for the candle data.
+ pub from: String,
+
+ /// The ending point of the time frame for the candle data.
+ pub to: String,
+
+ /// The sorting order for the candle data (e.g., "asc" or "desc").
+ pub sort: String,
+}
+
+/// Detailed information about a trade.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct TradeDetail {
+ /// The timestamp of the trade.
+ #[serde(rename = "d")]
+ pub timestamp: String,
+
+ /// The block number in which the trade was recorded.
+ #[serde(rename = "b")]
+ pub block_number: i64,
+
+ /// The trading pool where the trade occurred.
+ #[serde(rename = "pool")]
+ pub pool: String,
+
+ /// The trading symbol associated with the trade (e.g., BTC-USDT).
+ #[serde(rename = "s")]
+ pub symbol: String,
+
+ /// The hash of the transaction related to the trade.
+ #[serde(rename = "tx")]
+ pub transaction_hash: String,
+
+ /// The maker of the trade (the party who placed the order).
+ #[serde(rename = "m")]
+ pub maker: String,
+
+ /// The type of trade (e.g., buy or sell).
+ #[serde(rename = "t")]
+ pub trade_type: String,
+
+ /// The quantity of the base asset traded, in base unit.
+ #[serde(rename = "bq")]
+ pub base_quantity: String,
+
+ /// The quantity of the quote asset traded, in base unit.
+ #[serde(rename = "qq")]
+ pub quote_quantity: String,
+
+ /// The price of the trade in the quote asset's unit.
+ #[serde(rename = "p")]
+ pub price: String,
+}
+
+/// Response containing trade data.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct TradeResponse {
+ /// A vector containing detailed information about each trade.
+ pub data: Vec,
+
+ /// The current page number in the paginated response.
+ pub page: i32,
+
+ /// The maximum number of items per page in the response.
+ pub limit: i32,
+
+ /// The starting point of the time frame for the trade data.
+ pub from: String,
+
+ /// The ending point of the time frame for the trade data.
+ pub to: String,
+
+ /// The sorting order for the trade data (e.g., "asc" or "desc").
+ pub sort: String,
+}
+
+/// Optional parameters for a candle request.
+pub struct CandleOptions {
+ /// The market type (e.g., spot, futures).
+ pub market: Option,
+
+ /// The interval for the candle data (e.g., 1m, 1h, 1d).
+ pub interval: Option,
+
+ /// The page number for the candle data.
+ pub page: Option,
+
+ /// The maximum number of items per page in the response.
+ pub limit: Option,
+
+ /// The starting date & time for the candle data.
+ pub from: Option,
+
+ /// The ending date & time for the candle data.
+ pub to: Option,
+
+ /// The sorting order for the candle data (e.g., "asc" or "desc").
+ pub sort: Option,
+}
+
+impl Default for CandleOptions {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Provides a builder pattern for setting optional parameters for a candle request.
+impl CandleOptions {
+ /// Creates a new instance of `CandleOptions` with default values.
+ pub fn new() -> Self {
+ CandleOptions {
+ market: None,
+ interval: None,
+ page: 1.into(),
+ limit: 1000.into(),
+ from: None,
+ to: None,
+ sort: Some("desc".into()),
+ }
+ }
+
+ /// Sets the market for the candle query.
+ pub fn market(mut self, market: &str) -> Self {
+ self.market = Some(market.into());
+ self
+ }
+
+ /// Sets the interval for the candle query.
+ pub fn interval(mut self, interval: &str) -> Self {
+ self.interval = Some(interval.into());
+ self
+ }
+
+ /// Sets the page number for the candle query.
+ pub fn page(mut self, page: i32) -> Self {
+ self.page = Some(page);
+ self
+ }
+
+ /// Sets the limit for the number of results returned.
+ pub fn limit(mut self, limit: i32) -> Self {
+ self.limit = Some(limit);
+ self
+ }
+
+ /// Sets the starting date & time for the candle query.
+ pub fn from(mut self, from: &str) -> Self {
+ self.from = Some(from.into());
+ self
+ }
+
+ /// Sets the ending date & time for the candle query.
+ pub fn to(mut self, to: &str) -> Self {
+ self.to = Some(to.into());
+ self
+ }
+
+ /// Sets the sort order for the candle query (e.g., "asc" or "desc").
+ pub fn sort(mut self, sort: &str) -> Self {
+ self.sort = Some(sort.into());
+ self
+ }
+}
+
+/// Response containing details about symbols.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct SymbolsResponse {
+ /// The name of the exchange.
+ #[serde(rename = "e")]
+ pub exchange: String,
+
+ /// The market type (e.g., spot, futures).
+ #[serde(rename = "m")]
+ pub market: String,
+
+ /// The base asset of the trading pair.
+ #[serde(rename = "b")]
+ pub base: String,
+
+ /// The quote asset of the trading pair.
+ #[serde(rename = "q")]
+ pub quote: String,
+
+ /// The trading symbol (e.g., BTC-USDT).
+ #[serde(rename = "s")]
+ pub symbol: String,
+
+ /// An optional unique identifier for the symbol.
+ #[serde(rename = "id")]
+ pub id: Option,
+}
+
+/// Optional parameters for a symbols request.
+pub struct SymbolsOptions {
+ /// The market type (e.g., spot, futures).
+ pub market: Option,
+}
+
+impl Default for SymbolsOptions {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl SymbolsOptions {
+ /// Creates a new instance of `SymbolsOptions` with default values.
+ pub fn new() -> Self {
+ SymbolsOptions { market: None }
+ }
+
+ /// Sets the market for the symbols query.
+ pub fn market(mut self, market: &str) -> Self {
+ self.market = Some(market.into());
+ self
+ }
+}
+
+/// Response containing details about pools.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct PoolsResponse {
+ /// The blockchain where the pool is located.
+ #[serde(rename = "c")]
+ pub chain: String,
+
+ /// The name of the exchange where the pool is available.
+ #[serde(rename = "e")]
+ pub exchange: String,
+
+ /// The base asset used in the pool.
+ #[serde(rename = "b")]
+ pub base: String,
+
+ /// The quote asset used in the pool.
+ #[serde(rename = "q")]
+ pub quote: String,
+
+ /// The address of the base token in the pool.
+ #[serde(rename = "ba")]
+ pub baset_address: String,
+
+ /// The address of the quote token in the pool.
+ #[serde(rename = "qa")]
+ pub quote_address: String,
+
+ /// The unique address of the pool.
+ #[serde(rename = "pa")]
+ pub pool_address: String,
+
+ /// An optional unique identifier for the pool.
+ #[serde(rename = "id")]
+ pub id: Option,
+}
+
+/// Optional parameters for a trade request.
+pub struct TradeOptions {
+ /// The page number for the trade query.
+ pub page: Option,
+
+ /// The maximum number of items per page in the response.
+ pub limit: Option,
+
+ /// The starting date for the trade query.
+ pub from: Option,
+
+ /// The ending date for the trade query.
+ pub to: Option,
+
+ /// The sorting order for the trade query (e.g., "asc" or "desc").
+ pub sort: Option,
+}
+
+impl Default for TradeOptions {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Provides a builder pattern for setting optional parameters for a trade.
+impl TradeOptions {
+ /// Creates a new instance of `TradeOptions` with default values.
+ pub fn new() -> Self {
+ TradeOptions {
+ page: 1.into(),
+ limit: 1000.into(),
+ from: None,
+ to: None,
+ sort: Some("desc".into()),
+ }
+ }
+
+ /// Sets the page number for the trade query.
+ pub fn page(mut self, page: i32) -> Self {
+ self.page = Some(page);
+ self
+ }
+
+ /// Sets the limit for the number of results returned.
+ pub fn limit(mut self, limit: i32) -> Self {
+ self.limit = Some(limit);
+ self
+ }
+
+ /// Sets the starting date for the trade query.
+ pub fn from(mut self, from: &str) -> Self {
+ self.from = Some(from.into());
+ self
+ }
+
+ /// Sets the ending date for the trade query.
+ pub fn to(mut self, to: &str) -> Self {
+ self.to = Some(to.into());
+ self
+ }
+
+ /// Sets the sort order for the trade query (e.g., "asc" or "desc").
+ pub fn sort(mut self, sort: &str) -> Self {
+ self.sort = Some(sort.into());
+ self
+ }
+}
+
+/// Optional parameters for a pools request.
+pub struct PoolsOptions {
+ /// The chain for the pools query.
+ pub chain: Option,
+
+ /// The exchange for the pools query.
+ pub exchange: Option,
+}
+
+impl Default for PoolsOptions {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Provides a builder pattern for setting optional parameters for a pools request.
+impl PoolsOptions {
+ /// Creates a new instance of `PoolsOptions` with default values.
+ pub fn new() -> Self {
+ PoolsOptions {
+ chain: None,
+ exchange: None,
+ }
+ }
+
+ /// Sets the chain for the pools query.
+ pub fn chain(mut self, chain: &str) -> Self {
+ self.chain = Some(chain.into());
+ self
+ }
+
+ /// Sets the exchange for the pools query.
+ pub fn exchange(mut self, exchange: &str) -> Self {
+ self.exchange = Some(exchange.into());
+ self
+ }
+}