Expand description
§rithmic-rs
rithmic-rs is a Rust client library for the Rithmic R | Protocol API.
§Features
- Stream real-time market data (trades, quotes, order book depth)
- Submit and manage orders (bracket orders, modifications, cancellations)
- Access historical market data (ticks and time bars)
- Manage risk and track positions and P&L
- Connection health monitoring with heartbeat and forced logout handling
§Quick Start
use rithmic_rs::{
RithmicConfig, RithmicEnv, ConnectStrategy, RithmicTickerPlant,
rti::messages::RithmicMessage,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load configuration from environment variables
let config = RithmicConfig::from_env(RithmicEnv::Demo)?;
// Connect with Retry strategy (recommended default)
let ticker_plant = RithmicTickerPlant::connect(&config, ConnectStrategy::Retry).await?;
let mut handle = ticker_plant.get_handle();
// Login and subscribe to market data
handle.login().await?;
handle.subscribe("ESM6", "CME").await?;
// Process real-time updates
loop {
match handle.subscription_receiver.recv().await {
Ok(update) => {
// Check for connection health issues
if let Some(err) = &update.error {
eprintln!("Error: {}", err);
if err.is_connection_issue() { break; }
continue;
}
// Process market data
match update.message {
RithmicMessage::LastTrade(trade) => {
println!("Trade: {:?}", trade);
}
RithmicMessage::BestBidOffer(bbo) => {
println!("BBO: {:?}", bbo);
}
_ => {}
}
}
Err(e) => {
eprintln!("Channel error: {}", e);
break;
}
}
}
Ok(())
}§Connection Strategies
The library provides three connection strategies:
ConnectStrategy::Simple: Single connection attempt, fast-failConnectStrategy::Retry: Indefinite retries with linear backoff — 500 ms more per attempt, capped at 60s, jittered ±50% (recommended default)ConnectStrategy::AlternateWithRetry: Alternates between primary and beta URLs
A graceful disconnect().await logs out first and then closes the WebSocket.
See Error Handling for how that differs from an
unexpected drop.
§Configuration
Use RithmicConfig for modern, ergonomic configuration:
use rithmic_rs::{RithmicAccount, RithmicConfig, RithmicEnv};
fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// From environment variables
let config = RithmicConfig::from_env(RithmicEnv::Demo)?;
let account = RithmicAccount::from_env(RithmicEnv::Demo)?;
// Or using builder pattern
let config = RithmicConfig::builder(RithmicEnv::Demo)
.user("your_user".to_string())
.password("your_password".to_string())
.system_name("Rithmic Paper Trading".to_string())
.app_name("your_app_name".to_string())
.app_version("1".to_string())
.build()?;
let account = RithmicAccount::new("your_fcm", "your_ib", "your_account");
let _ = (config, account);
Ok(())
}§Error Handling
An error reaches you in one of two places: the call you made, or the subscription channel. Which one it is tells you what to do about it.
examples/error_handling.rs in the repository is this section as one
runnable file, if you would rather read code.
§From a call
Handle methods return Result<_, RithmicError>, but Ok does not mean
success. A request the server turned down still comes back as Ok, with the
reason in resp.error. Code that checks only for Err will read it as
having worked. login is the exception — a rejected login is an Err.
use rithmic_rs::RithmicError;
match handle.subscribe("ESM6", "CME").await {
Ok(resp) => match &resp.error {
Some(err) => eprintln!("Server rejected: {err}"),
None => { /* success */ }
},
Err(RithmicError::ConnectionClosed | RithmicError::SendFailed) => {
handle.abort();
// reconnect — see examples/reconnect.rs
}
Err(e) => eprintln!("{e}"),
}
if let Err(RithmicError::RequestRejected(err)) = handle.login().await {
eprintln!(
"Login rejected: code={} msg={}",
err.code.as_deref().unwrap_or("?"),
err.message.as_deref().unwrap_or(""),
);
}Two errors turn up in resp.error.
RequestRejected is the server saying no,
with its code and message split out so you can branch on the code.
ProtocolError means the response arrived but
would not decode — usually Rithmic’s schema has moved ahead of this crate, so
retrying will not help and it is worth filing.
An Err means you never got an answer at all:
InvalidArgument— your arguments. Nothing was sent. Fix them and call again.NoTradeRoute— no route for the order’s exchange. Nothing was sent. Set the order’strade_route, or check the exchange withtrade_route_forbefore you trade.SendFailed— the send failed. Only this request fails and the plant is still up, but the connection is usually on its way out; expect aConnectionErrorto follow. Treat it as a connection problem rather than retrying in a loop.ConnectionClosed— the plant is gone. Reconnect; calling again will not work.
When a connection drops, everything in flight fails with ConnectionClosed
whatever the real cause was. The cause goes out on the subscription channel,
so look there if you need to tell a heartbeat timeout from a dead socket.
The crate does not time out requests. A request finishes when Rithmic
answers it or the connection drops. If you need timeout handling, see
examples/request_timeout.rs. Timing out on your side does not cancel
anything on Rithmic’s, so reconcile an order rather than re-sending it.
(ConnectionFailed comes from connect()
rather than a handle method, and only under ConnectStrategy::Simple —
the retrying strategies keep trying instead of handing you an error.
EmptyResponse is a defensive case you should
not see.)
§From the subscription channel
Updates normally arrive with error: None. Five messages want a decision
from you:
| Message | What to do |
|---|---|
ConnectionError | Reconnect. The plant is stopping or already stopped. |
HeartbeatTimeout | Reconnect — unless error holds a RequestRejected, which means the server rejected a heartbeat and the connection is fine. |
ForcedLogout | The server ended your session. A ConnectionError follows, so expect two events. |
UnknownTemplate | Nothing, unless you want to. A template this crate has no mapping for, raw payload attached. Not an error. |
Unknown | A frame that would not decode. Log it and carry on. |
RithmicError::is_connection_issue is the shortcut: true means reconnect,
false means the connection is fine and something about the data or the
request was not. Do not reconnect on ProtocolError or RequestRejected —
neither says anything about connection health, and you will only churn.
This is a broadcast channel, so anything sent while you hold no receiver is gone. Keep it for as long as the plant lives.
§When a plant stops
Only transport failure takes one down: a broken socket, a keep-alive
timeout, a forced logout, or your own abort(). You get the matching
connection-health event and every pending call fails with ConnectionClosed.
Bad data never does. An undecodable frame, an unmapped template, a rejected
request — the plant keeps running and your other in-flight requests are
untouched. A decode failure usually comes back from the call it belongs to,
and arrives as Unknown when the frame names no request. A frame too
damaged to carry a template id at all is logged and dropped.
disconnect().await is the clean shutdown and emits none of those events.
Pending calls still fail with ConnectionClosed.
RithmicError implements std::error::Error, so ? works in functions
returning Box<dyn Error>.
§Feature Flags
| Flag | Default | Description |
|---|---|---|
serde | off | Adds Serialize/Deserialize derives on the config types (RithmicEnv, RithmicAccount), the trading enums (OrderSide, OrderType, TimeInForce, ManualOrAutoEntry, OrderCondition, OrderPriceField, BracketType, BracketOperationType, FillHistoryRange, EasyToBorrowRequest, RmsUpdateBits, OrderStatus), every order command type (RithmicOrder, RithmicBracketOrder, RithmicOcoOrder and its legs, RithmicModifyOrder, the cancel/exit/link/retag/adjustment commands), the triggers (TrailingStop, RithmicIfTouchedTrigger) and the history request types (VolumeProfileMinuteBarsRequest, TickBarReplayRequest) |
TLS backend: The crate uses native-tls (via tokio-tungstenite) for all
WebSocket connections. There is currently no rustls option.
§Module Organization
plants: Specialized clients for different data types (ticker, order, P&L, history)config: Configuration API for connecting to Rithmicerror: Typed error enum for plant handle methodsapi: Low-level API interfaces for sending and receiving messagestypes: High-level trading enums (order side, type, time-in-force, …)rti: Protocol message definitionsutil: Utility types and helpers (timestamps, order status, instrument info)
Re-exports§
pub use plants::history_plant::RithmicHistoryPlant;pub use plants::history_plant::RithmicHistoryPlantHandle;pub use plants::order_plant::RithmicOrderPlant;pub use plants::order_plant::RithmicOrderPlantHandle;pub use plants::pnl_plant::RithmicPnlPlant;pub use plants::pnl_plant::RithmicPnlPlantHandle;pub use plants::subscription::SubscriptionFilter;pub use plants::ticker_plant::RithmicTickerPlant;pub use plants::ticker_plant::RithmicTickerPlantHandle;pub use config::ConfigError;pub use config::RithmicAccount;pub use config::RithmicConfig;pub use config::RithmicConfigBuilder;pub use config::RithmicEnv;pub use error::RithmicError;pub use error::RithmicRequestError;pub use api::LoginConfig;pub use api::RithmicBracketLevelAdjustment;pub use api::RithmicBracketOrder;pub use api::RithmicCancelAllOrders;pub use api::RithmicCancelOrder;pub use api::RithmicExitPosition;pub use api::RithmicIfTouchedTrigger;pub use api::RithmicLinkOrders;pub use api::RithmicModifyOrder;pub use api::RithmicModifyOrderReferenceData;pub use api::RithmicOcoOrder;pub use api::RithmicOcoOrderLeg;pub use api::RithmicOrder;pub use api::RithmicResponse;pub use api::TrailingStop;pub use util::InstrumentInfo;pub use util::InstrumentInfoError;pub use util::OrderStatus;pub use util::UnknownTemplateMessage;pub use util::rithmic_to_unix_nanos;pub use util::rithmic_to_unix_nanos_precise;pub use types::BracketOperationType;pub use types::BracketType;pub use types::EasyToBorrowRequest;pub use types::FillHistoryRange;pub use types::ManualOrAutoEntry;pub use types::OrderCondition;pub use types::OrderPriceField;pub use types::OrderSide;pub use types::OrderType;pub use types::ParseOrderSideError;pub use types::ParseOrderTypeError;pub use types::ParseTimeInForceError;pub use types::RmsUpdateBits;pub use types::TickBarReplayRequest;pub use types::TimeBarReplayRequest;pub use types::TimeBarType;pub use types::TimeInForce;pub use types::VolumeProfileMinuteBarsRequest;pub use prost;
Modules§
- api
- Low-level API types for Rithmic communication.
- config
- Configuration API for connecting to Rithmic Configuration for Rithmic connections.
- error
- Error types for plant handle methods.
- plants
- Specialized clients (“plants”) for different Rithmic services.
- rti
- Rithmic protocol message definitions (protobuf-generated).
- types
- High-level trading types with optional serde support. Order enums with serde support and protobuf conversions.
- util
- Utility types for working with Rithmic data. Utility types for working with Rithmic data.
Enums§
- Connect
Strategy - Connection strategy for connecting to Rithmic servers.
Constants§
- DEFAULT_
REQUEST_ TIMEOUT Deprecated - No longer used. The library does not time out requests; wrap the call in
tokio::time::timeoutto set a deadline of your own. Removed in 4.0.0.