| Crates.io | ethereal_rust_sdk |
| lib.rs | ethereal_rust_sdk |
| version | 0.1.4 |
| created_at | 2026-01-02 12:54:07.206996+00 |
| updated_at | 2026-01-25 14:55:31.852508+00 |
| description | Trading client for Ethereal exchange |
| homepage | |
| repository | https://github.com/8ball030/ethereal_rust_sdk |
| max_upload_size | |
| id | 2018493 |
| size | 931,237 |
This is the Ethereal Rust SDK, which provides tools and libraries for interacting with the Ethereal platform using the Rust programming language.
At present, the Ethereal Rust SDK is under active development. To get started with the SDK, clone the repository and run the example code;`
We have a number of examples included in the examples directory. Here is how to run the market_data example:
git clone https://github.com/8ball030/ethereal_rust_sdk.git
cd ethereal_rust_sdk
cargo run --example market_data
There are two main clients provided by the SDK: an asynchronous HTTP client for interacting with the Ethereal REST API, and a WebSocket client for real-time data via the Ethereal WebSocket API.
A convenient utility function is provided to create both clients. Here is an example of how to use it:
let env = Environment::Testnet;
let private_key = "your_private_key_here";
let (http_client, ws_client) = create_client(env, private_key).await?;
All of the HTTP client functionality is encapsulated in the HttpClient struct. This client can be used to make requests to various endpoints of the Ethereal REST API.
The client has been generated using the OpenAPI specification provided by Ethereal, ensuring that all endpoints and data models are up-to-date with the latest API version.
// examples/simple_order_submission.rs
od common;
use ethereal_rust_sdk::models::{submit_order_limit_dto_data, OrderSide, OrderType};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (client, _) = common::create_test_clients().await?;
println!("Creating order...");
let ticker = "BTC-USD";
let quantity = 0.001;
let price = 80000.0;
let side = OrderSide::BUY;
let r#type = OrderType::Limit;
let expires_at = None;
let time_in_force = submit_order_limit_dto_data::TimeInForce::Gtd;
// We have a few more options when creating an order now.
let mut post_only = false;
let mut reduce_only = false;
let order = client
.submit_order(
ticker,
quantity,
Some(price),
side,
r#type,
time_in_force,
post_only,
reduce_only,
expires_at,
)
.await
.unwrap();
println!("Order submitted: {order:?}");
// We can also create orders with post only flag
println!("Creating post only reduce only order...");
post_only = true;
reduce_only = false;
let order = client
.submit_order(
ticker,
quantity,
Some(price),
side,
r#type,
time_in_force,
post_only,
reduce_only,
expires_at,
)
.await
.unwrap();
println!("Post and reduce only order submitted: {order:?}");
println!("Creating order with expires_at...");
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs() as i64;
let expires_at = Some(now + 60); // Expires in 60 seconds
let order = client
.submit_order(
ticker,
quantity,
Some(price),
side,
r#type,
time_in_force,
post_only,
reduce_only,
expires_at,
)
.await
.unwrap();
println!("Order with expires_at submitted: {order:?}");
println!("Fetching all current orders to cancel...");
let orders = client.get_open_orders().await?;
let cancel_result = client
.cancel_orders(orders.iter().map(|order| order.id.to_string()).collect())
.await?;
println!("Cancel result: {cancel_result:?}");
Ok(())
}
Positions can be fetched similarly:
// examples/fetch_positions.rs
use ethereal_rust_sdk::apis::{
position_api::PositionControllerListBySubaccountIdParams,
subaccount_api::SubaccountControllerListByAccountParams,
};
mod common;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
simple_logger::init_with_level(log::Level::Info).unwrap();
let (http_client, _) = common::create_test_clients().await?;
let params = SubaccountControllerListByAccountParams {
sender: http_client.address.clone(),
..Default::default()
};
let subaccounts = http_client.subaccount().list_by_account(params).await?;
let positions = http_client
.position()
.list_by_subaccount_id(PositionControllerListBySubaccountIdParams {
subaccount_id: subaccounts.data.first().unwrap().id.to_string(),
..Default::default()
})
.await?;
println!("Positions: {positions:#?}");
Ok(())
}
The Websocket client can be used as somewhat illustrated in the example below:
In order to proces messages from the websocket client, the user must first register a callback, then subscribe to the desired channel.
// examples/market_data.rs
use ethereal_rust_sdk::ws_client::run_forever;
use log::info;
mod common;
use ethereal_rust_sdk::apis::product_api::ProductControllerListParams;
use ethereal_rust_sdk::models::MarketPriceDto;
async fn market_data_callback(market_price: MarketPriceDto) {
info!(
"Market Price Update - Product ID: {:?}, Best Bid: {:?}, Best Ask: {:?}",
market_price.product_id, market_price.best_bid_price, market_price.best_ask_price
);
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
simple_logger::init_with_level(log::Level::Info).unwrap();
let (http_client, mut ws_client) = common::create_test_clients().await?;
let params = ProductControllerListParams::default();
let products = http_client.product().list(params).await.unwrap().data;
ws_client.register_market_data_callback(market_data_callback);
for product in products.iter() {
ws_client.subscribe_market_data(&product.id.to_string());
}
ws_client.connect().await?;
run_forever().await;
Ok(())
}
As can be seen, the SDK provides both asynchronous HTTP clients and WebSocket clients to interact with the Ethereal platform.
The following example demonstrates how to register for order updates.
// examples/order_updates.rs
mod common;
use ethereal_rust_sdk::apis::position_api::PositionControllerGetActiveParams;
use ethereal_rust_sdk::apis::product_api::ProductControllerListParams;
use ethereal_rust_sdk::apis::subaccount_api::SubaccountControllerListByAccountParams;
use ethereal_rust_sdk::models::PageOfOrderDtos;
use ethereal_rust_sdk::ws_client::run_forever;
use log::info;
async fn order_update_callback(raw_data: PageOfOrderDtos) {
for fill in raw_data.data {
info!(
"Order update - ID: {}, Product ID: {}, Price: {}, Side: {:?} Quantity: {:?}",
fill.id, fill.product_id, fill.price, fill.side, fill.filled
);
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
simple_logger::init_with_level(log::Level::Info).unwrap();
let (http_client, mut ws_client) = common::create_test_clients().await?;
let params = SubaccountControllerListByAccountParams {
sender: http_client.address.clone(),
..Default::default()
};
let subaccounts = http_client.subaccount().list_by_account(params).await?;
let params = ProductControllerListParams::default();
let products = http_client.product().list(params).await?;
products
.data
.first()
.expect("No products found in test account");
let product_id = &products.data.first().unwrap().id;
let params = PositionControllerGetActiveParams {
subaccount_id: subaccounts.data.first().unwrap().id.to_string(),
product_id: product_id.to_string(),
};
println!("Params: {params:?}");
ws_client.register_order_update_callback(order_update_callback);
subaccounts.data.iter().for_each(|subaccount| {
ws_client.subscribe_order_update(&subaccount.id.to_string());
});
ws_client.connect().await?;
run_forever().await;
Ok(())
}
The example can be run with the following command:
╰─>$ cargo run --example order_updates
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.41s
Running `target/debug/examples/order_updates`
2025-12-04T15:19:24.659Z INFO [ethereal_rust_sdk::ws_client] Callback registered channel=OrderUpdate
2025-12-04T15:19:24.659Z INFO [ethereal_rust_sdk::ws_client] Connecting websocket...
2025-12-04T15:19:26.294Z INFO [ethereal_rust_sdk::ws_client] Websocket connected
2025-12-04T15:19:26.295Z INFO [ethereal_rust_sdk::ws_client] Subscribed to channel=OrderUpdate subaccount_id=11111111-2222-3333-4444-444444444444
2025-12-04T15:19:41.089Z INFO [order_updates] Order update - ID: 11111111-2222-3333-4444-555555555555, Product ID: dce327cc-4fbb-4d5d-9ede-1c1fca7ef4ba, Price: 92324, Side: SELL Quantity: "0.001"
An order fill callback can be registered and subscribed to in a similar manner, this time using the register_order_fill_callback and subscribe_order_fill methods.
Additionally, it should be pointed out that a different data model is used for order fills, namely PageOfOrderFillDtos.
// examples/order_fills.rs
mod common;
use ethereal_rust_sdk::apis::subaccount_api::SubaccountControllerListByAccountParams;
use ethereal_rust_sdk::models::PageOfOrderFillDtos;
use ethereal_rust_sdk::ws_client::run_forever;
use log::info;
async fn order_fill_callback(raw_data: PageOfOrderFillDtos) {
for fill in raw_data.data {
info!(
"Order fill - ID: {}, Product ID: {}, Price: {}, Side: {:?} Quantity: {:?}",
fill.id, fill.product_id, fill.price, fill.side, fill.filled
);
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
simple_logger::init_with_level(log::Level::Info).unwrap();
let (http_client, mut ws_client) = common::create_test_clients().await?;
let params = SubaccountControllerListByAccountParams {
sender: http_client.address.clone(),
..Default::default()
};
let subaccounts = http_client.subaccount().list_by_account(params).await?;
ws_client.register_order_fill_callback(order_fill_callback);
subaccounts.data.iter().for_each(|subaccount| {
ws_client.subscribe_order_fill(&subaccount.id.to_string());
});
ws_client.connect().await?;
run_forever().await;
Ok(())
}
╰─>$ cargo run --example order_fills
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s
Running `target/debug/examples/order_fills`
2025-12-04T15:22:11.425Z INFO [ethereal_rust_sdk::ws_client] Callback registered channel=OrderFill
2025-12-04T15:22:11.425Z INFO [ethereal_rust_sdk::ws_client] Connecting websocket...
2025-12-04T15:22:13.104Z INFO [ethereal_rust_sdk::ws_client] Websocket connected
2025-12-04T15:22:13.142Z INFO [ethereal_rust_sdk::ws_client] Subscribed to channel=OrderFill subaccount_id=11111111-2222-3333-4444-444444444444
2025-12-04T15:22:26.745Z INFO [order_fills] Order fill - ID: 11111111-2222-3333-4444-555555555555, Product ID: dce327cc-4fbb-4d5d-9ede-1c1fca7ef4ba, Price: 92724, Side: SELL Quantity: "0.001"
:NOTE: Instructions for getting started with the Ethereal Rust SDK will be provided here soon.
Contributions are welcome! Please fork the repository and submit a pull request with your changes. Before submitting a pull request, please ensure that your code adheres to the project's coding standards and passes all tests. Please run the following commands to lint, format, build, and test the project before submitting your changes:
make fmt
make lint
make build
make test
# Or simpler
make all
This project is licensed under the MIT License. See the LICENSE file for details.